/[svn]/linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3581 - (show annotations) (download)
Fri Aug 30 11:40:25 2019 UTC (4 years, 7 months ago) by schoenebeck
File size: 48651 byte(s)
NKSP: Allow more wider support of standard measuring units & 'final'ness.

* Raised compiler requirement to be C++14 compliant (due to severe
  restrictions regarding C-style aggregate initializer lists in C++11
  which are now massively used throughout the code base).

* NKSP VM API: Allow units and 'final'ness to be returned as result from
  built-in functions (added methods VMFunction::returnUnitType() and
  VMFunction::returnsFinal() for that purpose which must be implemented by
  built-in function implementations).

* NKSP language: Allow metric unit prefixes of numeric scalar and array
  variables to be changed freely at runtime (unlike unit types like Hz etc.
  which are still sticky parse-time features of variables which cannot be
  changed at runtime for the intentional sake of determinism).

* NKSP language: 'final' values are prohibited for array variables for now
  (attempt causes a parsers error).

* NKSP language: expressions with unit types (e.g. Hz) are prohibited for
  conditions of runtime control structures like if(), while(), select()
  (attempt causes a parser error).

* NKSP VM API: Allow built-in functions to perform their own, individual
  parse time checks of arguments going to be passed to the function at
  runtime (added method VMFunction::checkArgs() for that purpose).

* NKSP language: raise parser warning if only one operand of binary
  operators (like logical 'or' comparison) contain a 'final' value (because
  it would always yield in a 'final' result in such cases).

* NKSP language: Allow comparison (=, #, <, >, <=, >=) of values with
  different metric unit prefixes, which will behave as expected (e.g.
  result of expression '1000us < 2ms' is true).

* NKSP language: Allow adding values with different metric unit prefixes
  (e.g. result of expression '100Hz + 5kHz' is '5100Hz').

* NKSP language: Allow subtracting values with different metric unit
  prefixes (e.g. result of expression '1ms - 20us' is '980us').

* NKSP language: Allow multiplying with any metric unit prefixes
  (e.g. result of expression '2k * 3ms' is '6s'), however multiplications
  with unit types on both sides (e.g. '2s * 2s') is still prohibited since
  we don't have any considerable practical use for a term like '4s^2'
  (hence any attempt multiplying two unit types still causes parser error).

* NKSP language: Allow dividing by any metric unit prefixes and allow
  division of same unit type on both sides (e.g. expression '8kHz / 1000Hz'
  yields in unit free result '8'). So this is now a way to cast units away
  e.g. for passing the result to other expressions, certain function calls
  or variables which are not accepting any units (or that specific unit).

* NKSP language: integer arrays and real number arrays can now be converted
  to strings (e.g. for dumping their content with message() calls for
  script debugging purposes).

* NKSP language: expressions and variables with units are now correctly
  casted to strings (e.g. with message() calls).

* NKSP language: comparing real numbers for equalness (e.g. '~foo = 3.1') or
  unequalness (e.g. '~foo # 3.1') is now less strict and takes the expected
  floating point tolerances into account.

* NKSP VM API: Added methods VMScalarNumberExpr::evalCastInt() and
  VMScalarNumberExpr::evalCastReal().

* NKSP VM API: Added base class 'VMNumberArrayExpr' for classes
  'VMIntArrayExpr' and 'VMRealArrayExpr'.

* NKSP VM API: replaced all unitPrefix() (parse time) methods by
  unitFactor() (runtime) methods.

* Built-in function "exit()" supports now returning units and 'final'ness
  exclusively for test cases.

* The following built-in functions support now units as well: "abs()",
  "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "real_to_int()", "int()", "int_to_real()" and "real()".

* Built-in functions "array_equal()", "search()" and "sort()" support now
  real number arrays (correctly) as well.

* Added individual parse time checks of arguments to be passed to built-in
  functions "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "array_equal()" and "search()" specific for their individual purposes.

* Test cases: Added massive amount of NKSP test cases for standard
  measuring units and 'final' operator usage cases.

* Test cases: Added NKSP test cases for (floating point tolerance aware)
  real number equalness / unequalness comparison.

* Bumped version (2.1.1.svn8).

1 /*
2 * Copyright (c) 2014-2019 Christian Schoenebeck
3 *
4 * http://www.linuxsampler.org
5 *
6 * This file is part of LinuxSampler and released under the same terms.
7 * See README file for details.
8 */
9
10 #include "CoreVMFunctions.h"
11
12 #include <iostream>
13 #include <algorithm> // for std::sort()
14 #include <math.h>
15 #include <stdlib.h>
16 #include "tree.h"
17 #include "ScriptVM.h"
18 #include "../common/RTMath.h"
19
20 namespace LinuxSampler {
21
22 inline bool _fEqualX(vmfloat a, vmfloat b) {
23 if (sizeof(vmfloat) == sizeof(float))
24 return RTMath::fEqual32(a, b);
25 else
26 return RTMath::fEqual64(a, b);
27 }
28
29 ///////////////////////////////////////////////////////////////////////////
30 // class VMEmptyResultFunction
31
32 VMFnResult* VMEmptyResultFunction::errorResult() {
33 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
34 return &result;
35 }
36
37 VMFnResult* VMEmptyResultFunction::successResult() {
38 result.flags = STMT_SUCCESS;
39 return &result;
40 }
41
42 ///////////////////////////////////////////////////////////////////////////
43 // class VMIntResultFunction
44
45 VMFnResult* VMIntResultFunction::errorResult(vmint i) {
46 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
47 result.value = i;
48 result.unitPrefixFactor = VM_NO_FACTOR;
49 return &result;
50 }
51
52 VMFnResult* VMIntResultFunction::successResult(vmint i) {
53 result.flags = STMT_SUCCESS;
54 result.value = i;
55 result.unitPrefixFactor = VM_NO_FACTOR;
56 return &result;
57 }
58
59 VMFnResult* VMIntResultFunction::errorResult(VMIntFnResDef res) {
60 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
61 result.value = res.value;
62 result.unitPrefixFactor = res.unitFactor;
63 return &result;
64 }
65
66 VMFnResult* VMIntResultFunction::successResult(VMIntFnResDef res) {
67 result.flags = STMT_SUCCESS;
68 result.value = res.value;
69 result.unitPrefixFactor = res.unitFactor;
70 return &result;
71 }
72
73 ///////////////////////////////////////////////////////////////////////////
74 // class VMRealResultFunction
75
76 VMFnResult* VMRealResultFunction::errorResult(vmfloat f) {
77 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
78 result.value = f;
79 result.unitPrefixFactor = VM_NO_FACTOR;
80 return &result;
81 }
82
83 VMFnResult* VMRealResultFunction::errorResult(VMRealFnResDef res) {
84 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
85 result.value = res.value;
86 result.unitPrefixFactor = res.unitFactor;
87 return &result;
88 }
89
90 VMFnResult* VMRealResultFunction::successResult(vmfloat f) {
91 result.flags = STMT_SUCCESS;
92 result.value = f;
93 result.unitPrefixFactor = VM_NO_FACTOR;
94 return &result;
95 }
96
97 VMFnResult* VMRealResultFunction::successResult(VMRealFnResDef res) {
98 result.flags = STMT_SUCCESS;
99 result.value = res.value;
100 result.unitPrefixFactor = res.unitFactor;
101 return &result;
102 }
103
104 ///////////////////////////////////////////////////////////////////////////
105 // class VMStringResultFunction
106
107 VMFnResult* VMStringResultFunction::errorResult(const String& s) {
108 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
109 result.value = s;
110 return &result;
111 }
112
113 VMFnResult* VMStringResultFunction::successResult(const String& s) {
114 result.flags = STMT_SUCCESS;
115 result.value = s;
116 return &result;
117 }
118
119 ///////////////////////////////////////////////////////////////////////////
120 // class VMScalarNumberResultFunction
121
122 VMFnResult* VMScalarNumberResultFunction::errorResult(vmint i) {
123 intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
124 intResult.value = i;
125 intResult.unitPrefixFactor = VM_NO_FACTOR;
126 return &intResult;
127 }
128
129 VMFnResult* VMScalarNumberResultFunction::errorResult(vmfloat f) {
130 realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
131 realResult.value = f;
132 realResult.unitPrefixFactor = VM_NO_FACTOR;
133 return &realResult;
134 }
135
136 VMFnResult* VMScalarNumberResultFunction::successResult(vmint i) {
137 intResult.flags = STMT_SUCCESS;
138 intResult.value = i;
139 intResult.unitPrefixFactor = VM_NO_FACTOR;
140 return &intResult;
141 }
142
143 VMFnResult* VMScalarNumberResultFunction::successResult(vmfloat f) {
144 realResult.flags = STMT_SUCCESS;
145 realResult.value = f;
146 realResult.unitPrefixFactor = VM_NO_FACTOR;
147 return &realResult;
148 }
149
150 VMFnResult* VMScalarNumberResultFunction::errorIntResult(VMIntFnResDef res) {
151 intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
152 intResult.value = res.value;
153 intResult.unitPrefixFactor = res.unitFactor;
154 return &intResult;
155 }
156
157 VMFnResult* VMScalarNumberResultFunction::errorRealResult(VMRealFnResDef res) {
158 realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
159 realResult.value = res.value;
160 realResult.unitPrefixFactor = res.unitFactor;
161 return &realResult;
162 }
163
164 VMFnResult* VMScalarNumberResultFunction::successIntResult(VMIntFnResDef res) {
165 intResult.flags = STMT_SUCCESS;
166 intResult.value = res.value;
167 intResult.unitPrefixFactor = res.unitFactor;
168 return &intResult;
169 }
170
171 VMFnResult* VMScalarNumberResultFunction::successRealResult(VMRealFnResDef res) {
172 realResult.flags = STMT_SUCCESS;
173 realResult.value = res.value;
174 realResult.unitPrefixFactor = res.unitFactor;
175 return &realResult;
176 }
177
178 ///////////////////////////////////////////////////////////////////////////
179 // built-in script function: message()
180
181 bool CoreVMFunction_message::acceptsArgType(vmint iArg, ExprType_t type) const {
182 return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR;
183 }
184
185 VMFnResult* CoreVMFunction_message::exec(VMFnArgs* args) {
186 if (!args->argsCount()) return errorResult();
187
188 uint64_t usecs = RTMath::unsafeMicroSeconds(RTMath::real_clock);
189
190 VMStringExpr* strExpr = dynamic_cast<VMStringExpr*>(args->arg(0));
191 if (strExpr) {
192 printf("[ScriptVM %.3f] %s\n", usecs/1000000.f, strExpr->evalStr().c_str());
193 return successResult();
194 }
195
196 VMRealExpr* realExpr = dynamic_cast<VMRealExpr*>(args->arg(0));
197 if (realExpr) {
198 printf("[ScriptVM %.3f] %f\n", usecs/1000000.f, realExpr->evalReal());
199 return successResult();
200 }
201
202 VMIntExpr* intExpr = dynamic_cast<VMIntExpr*>(args->arg(0));
203 if (intExpr) {
204 printf("[ScriptVM %.3f] %lld\n", usecs/1000000.f, (int64_t)intExpr->evalInt());
205 return successResult();
206 }
207
208 return errorResult();
209 }
210
211 ///////////////////////////////////////////////////////////////////////////
212 // built-in script function: exit()
213
214 vmint CoreVMFunction_exit::maxAllowedArgs() const {
215 return (vm->isExitResultEnabled()) ? 1 : 0;
216 }
217
218 bool CoreVMFunction_exit::acceptsArgType(vmint iArg, ExprType_t type) const {
219 if (!vm->isExitResultEnabled()) return false;
220 return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR;
221 }
222
223 bool CoreVMFunction_exit::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
224 if (!vm->isExitResultEnabled()) return false;
225 return true;
226 }
227
228 bool CoreVMFunction_exit::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const {
229 if (!vm->isExitResultEnabled()) return false;
230 return true;
231 }
232 bool CoreVMFunction_exit::acceptsArgFinal(vmint iArg) const {
233 if (!vm->isExitResultEnabled()) return false;
234 return true;
235 }
236
237 VMFnResult* CoreVMFunction_exit::exec(VMFnArgs* args) {
238 this->result.flags = STMT_ABORT_SIGNALLED;
239 if (vm->isExitResultEnabled() && args->argsCount()) {
240 ExecContext* ctx = dynamic_cast<ExecContext*>(vm->currentVMExecContext());
241 switch (args->arg(0)->exprType()) {
242 case INT_EXPR: {
243 VMIntExpr* expr = args->arg(0)->asInt();
244 ctx->exitRes.intLiteral = IntLiteral({
245 .value = expr->evalInt(),
246 .unitFactor = expr->unitFactor(),
247 .unitType = expr->unitType(),
248 .isFinal = expr->isFinal()
249 });
250 ctx->exitRes.value = &ctx->exitRes.intLiteral;
251 break;
252 }
253 case REAL_EXPR: {
254 VMRealExpr* expr = args->arg(0)->asReal();
255 ctx->exitRes.realLiteral = RealLiteral({
256 .value = expr->evalReal(),
257 .unitFactor = expr->unitFactor(),
258 .unitType = expr->unitType(),
259 .isFinal = expr->isFinal()
260 });
261 ctx->exitRes.value = &ctx->exitRes.realLiteral;
262 break;
263 }
264 case STRING_EXPR:
265 ctx->exitRes.stringLiteral = StringLiteral(
266 args->arg(0)->asString()->evalStr()
267 );
268 ctx->exitRes.value = &ctx->exitRes.stringLiteral;
269 break;
270 default:
271 ; // noop - just to shut up the compiler
272 }
273 }
274 return &result;
275 }
276
277 ///////////////////////////////////////////////////////////////////////////
278 // built-in script function: wait()
279
280 bool CoreVMFunction_wait::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
281 if (iArg == 0)
282 return type == VM_NO_UNIT || type == VM_SECOND;
283 else
284 return type == VM_NO_UNIT;
285 }
286
287 bool CoreVMFunction_wait::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const {
288 return iArg == 0 && type == VM_SECOND;
289 }
290
291 VMFnResult* CoreVMFunction_wait::exec(VMFnArgs* args) {
292 ExecContext* ctx = dynamic_cast<ExecContext*>(vm->currentVMExecContext());
293 VMIntExpr* expr = dynamic_cast<VMIntExpr*>(args->arg(0));
294 StdUnit_t unit = expr->unitType();
295 vmint us = (unit) ? expr->evalInt(VM_MICRO) : expr->evalInt();
296 if (us < 0) {
297 wrnMsg("wait(): argument may not be negative! Aborting script!");
298 this->result.flags = STMT_ABORT_SIGNALLED;
299 } else if (us == 0) {
300 wrnMsg("wait(): argument may not be zero! Aborting script!");
301 this->result.flags = STMT_ABORT_SIGNALLED;
302 } else {
303 ctx->suspendMicroseconds = us;
304 this->result.flags = STMT_SUSPEND_SIGNALLED;
305 }
306 return &result;
307 }
308
309 ///////////////////////////////////////////////////////////////////////////
310 // built-in script function: abs()
311
312 ExprType_t CoreVMFunction_abs::returnType(VMFnArgs* args) {
313 return args->arg(0)->exprType();
314 }
315
316 StdUnit_t CoreVMFunction_abs::returnUnitType(VMFnArgs* args) {
317 return args->arg(0)->asScalarNumberExpr()->unitType();
318 }
319
320 bool CoreVMFunction_abs::returnsFinal(VMFnArgs* args) {
321 return args->arg(0)->asScalarNumberExpr()->isFinal();
322 }
323
324 bool CoreVMFunction_abs::acceptsArgType(vmint iArg, ExprType_t type) const {
325 return type == INT_EXPR || type == REAL_EXPR;
326 }
327
328 VMFnResult* CoreVMFunction_abs::exec(VMFnArgs* args) {
329 VMExpr* arg = args->arg(0);
330 if (arg->exprType() == REAL_EXPR) {
331 VMRealExpr* expr = arg->asReal();
332 return successRealResult({
333 .value = ::fabs(expr->evalReal()),
334 .unitFactor = expr->unitFactor()
335 });
336 } else {
337 VMIntExpr* expr = arg->asInt();
338 return successIntResult({
339 .value = ::abs(expr->evalInt()),
340 .unitFactor = expr->unitFactor()
341 });
342 }
343 }
344
345 ///////////////////////////////////////////////////////////////////////////
346 // built-in script function: random()
347
348 ExprType_t CoreVMFunction_random::returnType(VMFnArgs* args) {
349 return (args->arg(0)->exprType() == INT_EXPR &&
350 args->arg(1)->exprType() == INT_EXPR) ? INT_EXPR : REAL_EXPR;
351 }
352
353 StdUnit_t CoreVMFunction_random::returnUnitType(VMFnArgs* args) {
354 // we ensure in checkArgs() below (which is called before this method here)
355 // that both arguments must be of same unit type, so either one is fine here
356 return args->arg(0)->asScalarNumberExpr()->unitType();
357 }
358
359 bool CoreVMFunction_random::returnsFinal(VMFnArgs* args) {
360 return args->arg(0)->asScalarNumberExpr()->isFinal() ||
361 args->arg(1)->asScalarNumberExpr()->isFinal();
362 }
363
364 bool CoreVMFunction_random::acceptsArgType(vmint iArg, ExprType_t type) const {
365 return type == INT_EXPR || type == REAL_EXPR;
366 }
367
368 void CoreVMFunction_random::checkArgs(VMFnArgs* args,
369 std::function<void(String)> err,
370 std::function<void(String)> wrn)
371 {
372 // super class checks
373 Super::checkArgs(args, err, wrn);
374
375 // own checks ...
376 if (args->arg(0)->asScalarNumberExpr()->unitType() !=
377 args->arg(1)->asScalarNumberExpr()->unitType())
378 {
379 String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
380 String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
381 err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
382 return;
383 }
384 if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
385 args->arg(1)->asScalarNumberExpr()->isFinal())
386 {
387 String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
388 String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
389 wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
390 }
391 }
392
393 VMFnResult* CoreVMFunction_random::exec(VMFnArgs* args) {
394 float f = float(::rand()) / float(RAND_MAX);
395
396 VMScalarNumberExpr* arg0 = args->arg(0)->asScalarNumberExpr();
397 VMScalarNumberExpr* arg1 = args->arg(1)->asScalarNumberExpr();
398
399 if (arg0->exprType() == INT_EXPR && arg1->exprType() == INT_EXPR) {
400 vmint iMin = args->arg(0)->asInt()->evalInt();
401 vmint iMax = args->arg(1)->asInt()->evalInt();
402 if (arg0->unitFactor() == arg1->unitFactor()) {
403 return successIntResult({
404 .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
405 .unitFactor = arg0->unitFactor()
406 });
407 } else if (arg0->unitFactor() < arg1->unitFactor()) {
408 iMax = Unit::convIntToUnitFactor(iMax, arg1, arg0);
409 return successIntResult({
410 .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
411 .unitFactor = arg0->unitFactor()
412 });
413 } else { // arg0->unitFactor() > arg1->unitFactor() ...
414 iMin = Unit::convIntToUnitFactor(iMin, arg0, arg1);
415 return successIntResult({
416 .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
417 .unitFactor = arg1->unitFactor()
418 });
419 }
420 } else {
421 vmfloat fMin = arg0->evalCastReal();
422 vmfloat fMax = arg1->evalCastReal();
423 if (arg0->unitFactor() == arg1->unitFactor()) {
424 return successRealResult({
425 .value = fMin + f * (fMax - fMin),
426 .unitFactor = arg0->unitFactor()
427 });
428 } else if (arg0->unitFactor() < arg1->unitFactor()) {
429 fMax = Unit::convRealToUnitFactor(fMax, arg1, arg0);
430 return successRealResult({
431 .value = fMin + f * (fMax - fMin),
432 .unitFactor = arg0->unitFactor()
433 });
434 } else { // arg0->unitFactor() > arg1->unitFactor() ...
435 fMin = Unit::convRealToUnitFactor(fMin, arg0, arg1);
436 return successRealResult({
437 .value = fMin + f * (fMax - fMin),
438 .unitFactor = arg1->unitFactor()
439 });
440 }
441 }
442 }
443
444 ///////////////////////////////////////////////////////////////////////////
445 // built-in script function: num_elements()
446
447 bool CoreVMFunction_num_elements::acceptsArgType(vmint iArg, ExprType_t type) const {
448 return isArray(type);
449 }
450
451 VMFnResult* CoreVMFunction_num_elements::exec(VMFnArgs* args) {
452 return successResult( args->arg(0)->asArray()->arraySize() );
453 }
454
455 ///////////////////////////////////////////////////////////////////////////
456 // built-in script function: inc()
457
458 StdUnit_t CoreVMFunction_inc::returnUnitType(VMFnArgs* args) {
459 return args->arg(0)->asScalarNumberExpr()->unitType();
460 }
461
462 bool CoreVMFunction_inc::returnsFinal(VMFnArgs* args) {
463 return args->arg(0)->asScalarNumberExpr()->isFinal();
464 }
465
466 void CoreVMFunction_inc::checkArgs(VMFnArgs* args,
467 std::function<void(String)> err,
468 std::function<void(String)> wrn)
469 {
470 // super class checks
471 Super::checkArgs(args, err, wrn);
472
473 // own checks ...
474 if (args->arg(0)->asScalarNumberExpr()->unitType()) {
475 String unitType = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
476 wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be incremented by one.");
477 }
478 }
479
480 VMFnResult* CoreVMFunction_inc::exec(VMFnArgs* args) {
481 VMExpr* arg = args->arg(0);
482 VMIntExpr* in = dynamic_cast<VMIntExpr*>(arg);
483 VMVariable* out = dynamic_cast<VMVariable*>(arg);
484 vmint i = in->evalInt() + 1;
485 IntLiteral tmp({
486 .value = i,
487 .unitFactor = in->unitFactor()
488 });
489 out->assignExpr(&tmp);
490 return successResult({
491 .value = i,
492 .unitFactor = in->unitFactor()
493 });
494 }
495
496 ///////////////////////////////////////////////////////////////////////////
497 // built-in script function: dec()
498
499 StdUnit_t CoreVMFunction_dec::returnUnitType(VMFnArgs* args) {
500 return args->arg(0)->asScalarNumberExpr()->unitType();
501 }
502
503 bool CoreVMFunction_dec::returnsFinal(VMFnArgs* args) {
504 return args->arg(0)->asScalarNumberExpr()->isFinal();
505 }
506
507 void CoreVMFunction_dec::checkArgs(VMFnArgs* args,
508 std::function<void(String)> err,
509 std::function<void(String)> wrn)
510 {
511 // super class checks
512 Super::checkArgs(args, err, wrn);
513
514 // own checks ...
515 if (args->arg(0)->asScalarNumberExpr()->unitType()) {
516 String unitType = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
517 wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be decremented by one.");
518 }
519 }
520
521 VMFnResult* CoreVMFunction_dec::exec(VMFnArgs* args) {
522 VMExpr* arg = args->arg(0);
523 VMIntExpr* in = dynamic_cast<VMIntExpr*>(arg);
524 VMVariable* out = dynamic_cast<VMVariable*>(arg);
525 vmint i = in->evalInt() - 1;
526 IntLiteral tmp({
527 .value = i,
528 .unitFactor = in->unitFactor()
529 });
530 out->assignExpr(&tmp);
531 return successResult({
532 .value = i,
533 .unitFactor = in->unitFactor()
534 });
535 }
536
537 ///////////////////////////////////////////////////////////////////////////
538 // built-in script function: in_range()
539
540 bool CoreVMFunction_in_range::acceptsArgType(vmint iArg, ExprType_t type) const {
541 return type == INT_EXPR || type == REAL_EXPR;
542 }
543
544 void CoreVMFunction_in_range::checkArgs(VMFnArgs* args,
545 std::function<void(String)> err,
546 std::function<void(String)> wrn)
547 {
548 // super class checks
549 Super::checkArgs(args, err, wrn);
550
551 // own checks ...
552 if (args->arg(0)->asScalarNumberExpr()->unitType() !=
553 args->arg(1)->asScalarNumberExpr()->unitType() ||
554 args->arg(1)->asScalarNumberExpr()->unitType() !=
555 args->arg(2)->asScalarNumberExpr()->unitType())
556 {
557 String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
558 String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
559 String c = unitTypeStr(args->arg(2)->asScalarNumberExpr()->unitType());
560 err("Arguments must all have same unit, however argument 1 is " + a +
561 ", argument 2 is " + b + ", argument 3 is " + c + ".");
562 return;
563 }
564 if (args->arg(0)->exprType() != args->arg(1)->exprType() ||
565 args->arg(1)->exprType() != args->arg(2)->exprType())
566 {
567 String a = typeStr(args->arg(0)->exprType());
568 String b = typeStr(args->arg(1)->exprType());
569 String c = typeStr(args->arg(2)->exprType());
570 String r = typeStr(REAL_EXPR);
571 wrn("Argument 1 is " + a + ", argument 2 is " + b +
572 ", argument 3 is " + c + ", function result will be " + r + ".");
573 }
574 }
575
576 template<class T>
577 inline void _swapByValue(T& a, T& b) {
578 T tmp = a;
579 a = b;
580 b = tmp;
581 }
582
583 VMFnResult* CoreVMFunction_in_range::exec(VMFnArgs* args) {
584 VMScalarNumberExpr* argNeedle = args->arg(0)->asScalarNumberExpr();
585 VMScalarNumberExpr* argLo = args->arg(1)->asScalarNumberExpr();
586 VMScalarNumberExpr* argHi = args->arg(2)->asScalarNumberExpr();
587
588 vmfloat needle = argNeedle->evalCastReal();
589 vmfloat lo = argLo->evalCastReal();
590 vmfloat hi = argHi->evalCastReal();
591
592 needle *= argNeedle->unitFactor();
593 lo *= argLo->unitFactor();
594 hi *= argHi->unitFactor();
595
596 if (lo > hi) _swapByValue(lo, hi);
597
598 return successResult(needle >= lo && needle <= hi);
599 }
600
601 ///////////////////////////////////////////////////////////////////////////
602 // built-in script function: sh_left()
603
604 bool CoreVMFunction_sh_left::returnsFinal(VMFnArgs* args) {
605 return args->arg(0)->asScalarNumberExpr()->isFinal();
606 }
607
608 VMFnResult* CoreVMFunction_sh_left::exec(VMFnArgs* args) {
609 vmint i = args->arg(0)->asInt()->evalInt();
610 vmint n = args->arg(1)->asInt()->evalInt();
611 return successResult(i << n);
612 }
613
614 ///////////////////////////////////////////////////////////////////////////
615 // built-in script function: sh_right()
616
617 bool CoreVMFunction_sh_right::returnsFinal(VMFnArgs* args) {
618 return args->arg(0)->asScalarNumberExpr()->isFinal();
619 }
620
621 VMFnResult* CoreVMFunction_sh_right::exec(VMFnArgs* args) {
622 vmint i = args->arg(0)->asInt()->evalInt();
623 vmint n = args->arg(1)->asInt()->evalInt();
624 return successResult(i >> n);
625 }
626
627 ///////////////////////////////////////////////////////////////////////////
628 // built-in script function: min()
629
630 ExprType_t CoreVMFunction_min::returnType(VMFnArgs* args) {
631 return (args->arg(0)->exprType() == REAL_EXPR ||
632 args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR;
633 }
634
635 StdUnit_t CoreVMFunction_min::returnUnitType(VMFnArgs* args) {
636 return args->arg(0)->asScalarNumberExpr()->unitType();
637 }
638
639 bool CoreVMFunction_min::returnsFinal(VMFnArgs* args) {
640 return args->arg(0)->asScalarNumberExpr()->isFinal() ||
641 args->arg(1)->asScalarNumberExpr()->isFinal();
642 }
643
644 bool CoreVMFunction_min::acceptsArgType(vmint iArg, ExprType_t type) const {
645 return type == INT_EXPR || type == REAL_EXPR;
646 }
647
648 void CoreVMFunction_min::checkArgs(VMFnArgs* args,
649 std::function<void(String)> err,
650 std::function<void(String)> wrn)
651 {
652 // super class checks
653 Super::checkArgs(args, err, wrn);
654
655 // own checks ...
656 if (args->arg(0)->asScalarNumberExpr()->unitType() !=
657 args->arg(1)->asScalarNumberExpr()->unitType())
658 {
659 String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
660 String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
661 err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
662 return;
663 }
664 if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
665 String a = typeStr(args->arg(0)->exprType());
666 String b = typeStr(args->arg(1)->exprType());
667 String c = typeStr(REAL_EXPR);
668 wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + ".");
669 return;
670 }
671 if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
672 args->arg(1)->asScalarNumberExpr()->isFinal())
673 {
674 String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
675 String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
676 wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
677 }
678 }
679
680 VMFnResult* CoreVMFunction_min::exec(VMFnArgs* args) {
681 VMScalarNumberExpr* lhs = args->arg(0)->asScalarNumberExpr();
682 VMScalarNumberExpr* rhs = args->arg(1)->asScalarNumberExpr();
683 if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) {
684 vmfloat lm = lhs->asReal()->evalReal();
685 vmfloat rm = rhs->asReal()->evalReal();
686 vmfloat lprod = lm * lhs->unitFactor();
687 vmfloat rprod = rm * rhs->unitFactor();
688 return successRealResult({
689 .value = (lprod < rprod) ? lm : rm,
690 .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
691 });
692 } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) {
693 vmfloat lm = lhs->asReal()->evalReal();
694 vmint rm = rhs->asInt()->evalInt();
695 vmfloat lprod = lm * lhs->unitFactor();
696 vmfloat rprod = rm * rhs->unitFactor();
697 return successRealResult({
698 .value = (lprod < rprod) ? lm : rm,
699 .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
700 });
701 } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) {
702 vmint lm = lhs->asInt()->evalInt();
703 vmfloat rm = rhs->asReal()->evalReal();
704 vmfloat lprod = lm * lhs->unitFactor();
705 vmfloat rprod = rm * rhs->unitFactor();
706 return successRealResult({
707 .value = (lprod < rprod) ? lm : rm,
708 .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
709 });
710 } else {
711 vmint lm = lhs->asInt()->evalInt();
712 vmint rm = rhs->asInt()->evalInt();
713 vmfloat lprod = lm * lhs->unitFactor();
714 vmfloat rprod = rm * rhs->unitFactor();
715 return successIntResult({
716 .value = (lprod < rprod) ? lm : rm,
717 .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
718 });
719 }
720 }
721
722 ///////////////////////////////////////////////////////////////////////////
723 // built-in script function: max()
724
725 ExprType_t CoreVMFunction_max::returnType(VMFnArgs* args) {
726 return (args->arg(0)->exprType() == REAL_EXPR ||
727 args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR;
728 }
729
730 StdUnit_t CoreVMFunction_max::returnUnitType(VMFnArgs* args) {
731 return args->arg(0)->asScalarNumberExpr()->unitType();
732 }
733
734 bool CoreVMFunction_max::returnsFinal(VMFnArgs* args) {
735 return args->arg(0)->asScalarNumberExpr()->isFinal() ||
736 args->arg(1)->asScalarNumberExpr()->isFinal();
737 }
738
739 bool CoreVMFunction_max::acceptsArgType(vmint iArg, ExprType_t type) const {
740 return type == INT_EXPR || type == REAL_EXPR;
741 }
742
743 void CoreVMFunction_max::checkArgs(VMFnArgs* args,
744 std::function<void(String)> err,
745 std::function<void(String)> wrn)
746 {
747 // super class checks
748 Super::checkArgs(args, err, wrn);
749
750 // own checks ...
751 if (args->arg(0)->asScalarNumberExpr()->unitType() !=
752 args->arg(1)->asScalarNumberExpr()->unitType())
753 {
754 String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
755 String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
756 err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
757 return;
758 }
759 if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
760 String a = typeStr(args->arg(0)->exprType());
761 String b = typeStr(args->arg(1)->exprType());
762 String c = typeStr(REAL_EXPR);
763 wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + ".");
764 return;
765 }
766 if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
767 args->arg(1)->asScalarNumberExpr()->isFinal())
768 {
769 String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
770 String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
771 wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
772 }
773 }
774
775 VMFnResult* CoreVMFunction_max::exec(VMFnArgs* args) {
776 VMScalarNumberExpr* lhs = args->arg(0)->asScalarNumberExpr();
777 VMScalarNumberExpr* rhs = args->arg(1)->asScalarNumberExpr();
778 if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) {
779 vmfloat lm = lhs->asReal()->evalReal();
780 vmfloat rm = rhs->asReal()->evalReal();
781 vmfloat lprod = lm * lhs->unitFactor();
782 vmfloat rprod = rm * rhs->unitFactor();
783 return successRealResult({
784 .value = (lprod > rprod) ? lm : rm,
785 .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
786 });
787 } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) {
788 vmfloat lm = lhs->asReal()->evalReal();
789 vmint rm = rhs->asInt()->evalInt();
790 vmfloat lprod = lm * lhs->unitFactor();
791 vmfloat rprod = rm * rhs->unitFactor();
792 return successRealResult({
793 .value = (lprod > rprod) ? lm : rm,
794 .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
795 });
796 } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) {
797 vmint lm = lhs->asInt()->evalInt();
798 vmfloat rm = rhs->asReal()->evalReal();
799 vmfloat lprod = lm * lhs->unitFactor();
800 vmfloat rprod = rm * rhs->unitFactor();
801 return successRealResult({
802 .value = (lprod > rprod) ? lm : rm,
803 .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
804 });
805 } else {
806 vmint lm = lhs->asInt()->evalInt();
807 vmint rm = rhs->asInt()->evalInt();
808 vmfloat lprod = lm * lhs->unitFactor();
809 vmfloat rprod = rm * rhs->unitFactor();
810 return successIntResult({
811 .value = (lprod > rprod) ? lm : rm,
812 .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
813 });
814 }
815 }
816
817 ///////////////////////////////////////////////////////////////////////////
818 // built-in script function: array_equal()
819
820 bool CoreVMFunction_array_equal::acceptsArgType(vmint iArg, ExprType_t type) const {
821 return isArray(type);
822 }
823
824 void CoreVMFunction_array_equal::checkArgs(VMFnArgs* args,
825 std::function<void(String)> err,
826 std::function<void(String)> wrn)
827 {
828 // super class checks
829 Super::checkArgs(args, err, wrn);
830
831 // own checks ...
832 if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
833 String a = typeStr(args->arg(0)->exprType());
834 String b = typeStr(args->arg(1)->exprType());
835 err("Argument 1 is " + a + ", whereas argument 2 is " + b + ".");
836 return;
837 }
838 if (args->arg(0)->asArray()->arraySize() !=
839 args->arg(1)->asArray()->arraySize())
840 {
841 wrn("Result of function call is always false, since the passed two arrays were declared with different array sizes.");
842 }
843 }
844
845 VMFnResult* CoreVMFunction_array_equal::exec(VMFnArgs* args) {
846 VMArrayExpr* l = args->arg(0)->asArray();
847 VMArrayExpr* r = args->arg(1)->asArray();
848 if (l->arraySize() != r->arraySize()) {
849 //wrnMsg("array_equal(): the two arrays differ in size");
850 return successResult(0); // false
851 }
852 const vmint n = l->arraySize();
853 // checkArgs() above ensured that we either have INT_ARR_EXPR on both sides
854 // or REAL_ARR_EXPR on both sides, so we can simplify here (a bit)
855 if (l->exprType() == INT_ARR_EXPR) {
856 VMIntArrayExpr* lia = l->asIntArray();
857 VMIntArrayExpr* ria = r->asIntArray();
858 for (vmint i = 0; i < n; ++i) {
859 vmint lvalue = lia->evalIntElement(i);
860 vmint rvalue = ria->evalIntElement(i);
861 vmfloat lfactor = lia->unitFactorOfElement(i);
862 vmfloat rfactor = ria->unitFactorOfElement(i);
863 if (lfactor == rfactor) {
864 if (lvalue != rvalue)
865 return successResult(0); // false
866 else
867 continue;
868 }
869 if (lfactor < rfactor) {
870 if (lvalue != Unit::convIntToUnitFactor(rvalue, rfactor, lfactor))
871 return successResult(0); // false
872 else
873 continue;
874 } else {
875 if (rvalue != Unit::convIntToUnitFactor(lvalue, lfactor, rfactor))
876 return successResult(0); // false
877 else
878 continue;
879 }
880 }
881 } else {
882 VMRealArrayExpr* lra = l->asRealArray();
883 VMRealArrayExpr* rra = r->asRealArray();
884 for (vmint i = 0; i < n; ++i) {
885 vmfloat lvalue = lra->evalRealElement(i);
886 vmfloat rvalue = rra->evalRealElement(i);
887 vmfloat lfactor = lra->unitFactorOfElement(i);
888 vmfloat rfactor = rra->unitFactorOfElement(i);
889 if (lfactor == rfactor) {
890 if (!_fEqualX(lvalue, rvalue))
891 return successResult(0); // false
892 else
893 continue;
894 }
895 if (lfactor < rfactor) {
896 if (!_fEqualX(lvalue, Unit::convRealToUnitFactor(rvalue, rfactor, lfactor)))
897 return successResult(0); // false
898 else
899 continue;
900 } else {
901 if (!_fEqualX(rvalue, Unit::convRealToUnitFactor(lvalue, lfactor, rfactor)))
902 return successResult(0); // false
903 else
904 continue;
905 }
906 }
907 }
908 return successResult(1); // true
909 }
910
911 ///////////////////////////////////////////////////////////////////////////
912 // built-in script function: search()
913
914 ExprType_t CoreVMFunction_search::argType(vmint iArg) const {
915 return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR;
916 }
917
918 bool CoreVMFunction_search::acceptsArgType(vmint iArg, ExprType_t type) const {
919 if (iArg == 0)
920 return isArray(type);
921 else
922 return type == INT_EXPR || type == REAL_EXPR;
923 }
924
925 void CoreVMFunction_search::checkArgs(VMFnArgs* args,
926 std::function<void(String)> err,
927 std::function<void(String)> wrn)
928 {
929 // super class checks
930 Super::checkArgs(args, err, wrn);
931
932 // own checks ...
933 if (args->arg(0)->exprType() == INT_ARR_EXPR &&
934 args->arg(1)->exprType() != INT_EXPR)
935 {
936 String a = typeStr(INT_ARR_EXPR);
937 String bIs = typeStr(args->arg(1)->exprType());
938 String bShould = typeStr(INT_EXPR);
939 err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though.");
940 return;
941 }
942 if (args->arg(0)->exprType() == REAL_ARR_EXPR &&
943 args->arg(1)->exprType() != REAL_EXPR)
944 {
945 String a = typeStr(REAL_ARR_EXPR);
946 String bIs = typeStr(args->arg(1)->exprType());
947 String bShould = typeStr(REAL_EXPR);
948 err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though.");
949 return;
950 }
951 }
952
953 VMFnResult* CoreVMFunction_search::exec(VMFnArgs* args) {
954 VMArrayExpr* a = args->arg(0)->asArray();
955 const vmint n = a->arraySize();
956 if (a->exprType() == INT_ARR_EXPR) {
957 const vmint needle = args->arg(1)->asInt()->evalInt();
958 VMIntArrayExpr* intArray = a->asIntArray();
959 for (vmint i = 0; i < n; ++i)
960 if (intArray->evalIntElement(i) == needle)
961 return successResult(i);
962 } else { // real array ...
963 const vmfloat needle = args->arg(1)->asReal()->evalReal();
964 VMRealArrayExpr* realArray = a->asRealArray();
965 for (vmint i = 0; i < n; ++i) {
966 const vmfloat value = realArray->evalRealElement(i);
967 if (_fEqualX(value, needle))
968 return successResult(i);
969 }
970 }
971 return successResult(-1); // not found
972 }
973
974 ///////////////////////////////////////////////////////////////////////////
975 // built-in script function: sort()
976
977 ExprType_t CoreVMFunction_sort::argType(vmint iArg) const {
978 return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR;
979 }
980
981 bool CoreVMFunction_sort::acceptsArgType(vmint iArg, ExprType_t type) const {
982 if (iArg == 0)
983 return isArray(type);
984 else
985 return type == INT_EXPR;
986 }
987
988 // The following structs and template classes act as adapters for allowing to
989 // use std sort algorithms on our arrays. It might look a bit more complicated
990 // than it ought to be, but there is one reason for the large amount of
991 // 'adapter' code below: the STL std algorithms rely on 'lvalues' to do their
992 // e.g. sorting) jobs, that is they expect containers to have 'localizeable'
993 // data which essentially means their data should reside somewhere in memory and
994 // directly be accessible (readable and writable) there, which is not the case
995 // with our VM interfaces which actually always require virtual getter and
996 // setter methods to be called instead. So we must emulate lvalues by custom
997 // classes/structs which forward between our getters/setters and the lvalue
998 // access operators used by the STL std algorithms.
999
1000 struct IntArrayAccessor {
1001 static inline vmint getPrimaryValue(VMIntArrayExpr* arr, vmint index) {
1002 return arr->evalIntElement(index);
1003 }
1004 static inline void setPrimaryValue(VMIntArrayExpr* arr, vmint index, vmint value) {
1005 arr->assignIntElement(index, value);
1006 }
1007 };
1008
1009 struct RealArrayAccessor {
1010 static inline vmfloat getPrimaryValue(VMRealArrayExpr* arr, vmint index) {
1011 return arr->evalRealElement(index);
1012 }
1013 static inline void setPrimaryValue(VMRealArrayExpr* arr, vmint index, vmfloat value) {
1014 arr->assignRealElement(index, value);
1015 }
1016 };
1017
1018 template<class T_array> // i.e. T_array is either VMIntArrayExpr or VMRealArrayExpr
1019 struct ArrElemPOD {
1020 T_array* m_array;
1021 vmint m_index;
1022 };
1023
1024 // This class is used for temporary values by std::sort().
1025 template<class T_value> // i.e. T_value is either vmint or vmfloat
1026 struct ScalarNmbrVal {
1027 T_value primValue;
1028 vmfloat unitFactor;
1029
1030 inline bool operator<(const ScalarNmbrVal& other) const {
1031 return getProdValue() < other.getProdValue();
1032 }
1033 inline bool operator>(const ScalarNmbrVal& other) const {
1034 return getProdValue() > other.getProdValue();
1035 }
1036 inline vmfloat getProdValue() const {
1037 // simple solution for both vmint and vmfloat, should be fine for just sorting
1038 return primValue * unitFactor;
1039 }
1040 };
1041
1042 // This class emulates lvalue access (access by reference) which is used by ArrExprIter::operator*() below.
1043 template<class T_array, // T_array is either VMIntArrayExpr or VMRealArrayExpr
1044 class T_value, // T_value is either vmint or vmfloat
1045 class T_accessor> // T_accessor is either IntArrayAccessor or RealArrayAccessor
1046 class ArrElemRef : protected ArrElemPOD<T_array> {
1047 public:
1048 typedef ScalarNmbrVal<T_value> ScalarNmbrVal;
1049
1050 inline ArrElemRef(T_array* a, vmint index) {
1051 this->m_array = a;
1052 this->m_index = index;
1053 }
1054 inline ArrElemRef(const ArrElemRef& ref) {
1055 this->m_array = ref.m_array;
1056 this->m_index = ref.m_index;
1057 }
1058 inline ArrElemRef& operator=(const ArrElemRef& e) {
1059 setPrimValue(e.getPrimValue());
1060 setUnitFactor(e.getUnitFactor());
1061 return *this;
1062 }
1063 inline ArrElemRef& operator=(ScalarNmbrVal value) {
1064 setPrimValue(value.primValue);
1065 setUnitFactor(value.unitFactor);
1066 return *this;
1067 }
1068 inline bool operator==(const ArrElemRef& e) const {
1069 return getProdValue() == e.getProdValue();
1070 }
1071 inline bool operator!=(const ArrElemRef& e) const {
1072 return !(operator==(e));
1073 }
1074 inline bool operator<(const ArrElemRef& e) const {
1075 return getProdValue() < e.getProdValue();
1076 }
1077 inline bool operator>(const ArrElemRef& e) const {
1078 return getProdValue() > e.getProdValue();
1079 }
1080 inline bool operator<=(const ArrElemRef& e) const {
1081 return getProdValue() <= e.getProdValue();
1082 }
1083 inline bool operator>=(const ArrElemRef& e) const {
1084 return getProdValue() >= e.getProdValue();
1085 }
1086 inline bool operator==(const ScalarNmbrVal& s) const {
1087 return getProdValue() == s.getProdValue();
1088 }
1089 inline bool operator!=(const ScalarNmbrVal& s) const {
1090 return !(operator==(s));
1091 }
1092 inline bool operator<(const ScalarNmbrVal& s) const {
1093 return getProdValue() < s.getProdValue();
1094 }
1095 inline bool operator>(const ScalarNmbrVal& s) const {
1096 return getProdValue() > s.getProdValue();
1097 }
1098 inline bool operator<=(const ScalarNmbrVal& s) const {
1099 return getProdValue() <= s.getProdValue();
1100 }
1101 inline bool operator>=(const ScalarNmbrVal& s) const {
1102 return getProdValue() >= s.getProdValue();
1103 }
1104 inline operator ScalarNmbrVal() {
1105 return {
1106 .primValue = getPrimValue() ,
1107 .unitFactor = getUnitFactor()
1108 };
1109 }
1110 protected:
1111 inline T_value getPrimValue() const {
1112 return T_accessor::getPrimaryValue( this->m_array, this->m_index );
1113 }
1114 inline void setPrimValue(T_value value) {
1115 T_accessor::setPrimaryValue( this->m_array, this->m_index, value );
1116 }
1117 inline vmfloat getUnitFactor() const {
1118 return this->m_array->unitFactorOfElement(this->m_index);
1119 }
1120 inline void setUnitFactor(vmfloat factor) {
1121 this->m_array->assignElementUnitFactor(this->m_index, factor);
1122 }
1123 inline vmfloat getProdValue() const {
1124 // simple solution for both vmint and vmfloat, should be fine for just sorting
1125 vmfloat primary = (vmfloat) getPrimValue();
1126 vmfloat factor = getUnitFactor();
1127 return primary * factor;
1128 }
1129
1130 // allow swap() functions below to access protected methods here
1131 friend void swap(class ArrElemRef<T_array,T_value,T_accessor> a,
1132 class ArrElemRef<T_array,T_value,T_accessor> b);
1133 };
1134
1135 // custom iterator class to be used by std:sort() on our VM arrays
1136 template<class T_array, class T_value, class T_accessor>
1137 class ArrExprIter : public ArrElemPOD<T_array> {
1138 public:
1139 typedef std::random_access_iterator_tag iterator_category;
1140 typedef ssize_t difference_type;
1141 typedef ArrElemRef<T_array, T_value, T_accessor> ArrElemRef;
1142 typedef ArrElemRef reference; // type used by STL for access by reference
1143 typedef void pointer; // type used by STL for -> operator result, we don't use that operator at all so just void it
1144 typedef ScalarNmbrVal<T_value> value_type; // type used by STL for temporary values
1145
1146 ArrExprIter(T_array* a, vmint index) {
1147 this->m_array = a;
1148 this->m_index = index;
1149 }
1150 ArrExprIter(const ArrElemRef& ref) {
1151 this->m_array = ref.m_array;
1152 this->m_index = ref.m_index;
1153 }
1154 inline ArrElemRef operator*() {
1155 return ArrElemRef(this->m_array, this->m_index);
1156 }
1157 inline ArrExprIter& operator++() { // prefix increment
1158 ++(this->m_index);
1159 return *this;
1160 }
1161 inline ArrExprIter& operator--() { // prefix decrement
1162 --(this->m_index);
1163 return *this;
1164 }
1165 inline ArrExprIter operator++(int) { // postfix increment
1166 ArrExprIter it = *this;
1167 ++(this->m_index);
1168 return it;
1169 }
1170 inline ArrExprIter operator--(int) { // postfix decrement
1171 ArrExprIter it = *this;
1172 --(this->m_index);
1173 return it;
1174 }
1175 inline ArrExprIter& operator+=(difference_type d) {
1176 this->m_index += d;
1177 return *this;
1178 }
1179 inline ArrExprIter& operator-=(difference_type d) {
1180 this->m_index -= d;
1181 return *this;
1182 }
1183 inline bool operator==(const ArrExprIter& other) const {
1184 return this->m_index == other.m_index;
1185 }
1186 inline bool operator!=(const ArrExprIter& other) const {
1187 return this->m_index != other.m_index;
1188 }
1189 inline bool operator<(const ArrExprIter& other) const {
1190 return this->m_index < other.m_index;
1191 }
1192 inline bool operator>(const ArrExprIter& other) const {
1193 return this->m_index > other.m_index;
1194 }
1195 inline bool operator<=(const ArrExprIter& other) const {
1196 return this->m_index <= other.m_index;
1197 }
1198 inline bool operator>=(const ArrExprIter& other) const {
1199 return this->m_index >= other.m_index;
1200 }
1201 inline difference_type operator+(const ArrExprIter& other) const {
1202 return this->m_index + other.m_index;
1203 }
1204 inline difference_type operator-(const ArrExprIter& other) const {
1205 return this->m_index - other.m_index;
1206 }
1207 inline ArrExprIter operator-(difference_type d) const {
1208 return ArrExprIter(this->m_array, this->m_index - d);
1209 }
1210 inline ArrExprIter operator+(difference_type d) const {
1211 return ArrExprIter(this->m_array, this->m_index + d);
1212 }
1213 inline ArrExprIter operator*(difference_type factor) const {
1214 return ArrExprIter(this->m_array, this->m_index * factor);
1215 }
1216 };
1217
1218 typedef ArrExprIter<VMIntArrayExpr,vmint,IntArrayAccessor> IntArrExprIter;
1219 typedef ArrExprIter<VMRealArrayExpr,vmfloat,RealArrayAccessor> RealArrExprIter;
1220
1221 // intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions
1222 static inline void swap(IntArrExprIter::ArrElemRef a,
1223 IntArrExprIter::ArrElemRef b)
1224 {
1225 vmint valueA = a.getPrimValue();
1226 vmint valueB = b.getPrimValue();
1227 vmfloat factorA = a.getUnitFactor();
1228 vmfloat factorB = b.getUnitFactor();
1229 a.setPrimValue(valueB);
1230 a.setUnitFactor(factorB);
1231 b.setPrimValue(valueA);
1232 b.setUnitFactor(factorA);
1233 }
1234
1235 // intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions
1236 static inline void swap(RealArrExprIter::ArrElemRef a,
1237 RealArrExprIter::ArrElemRef b)
1238 {
1239 vmfloat valueA = a.getPrimValue();
1240 vmfloat valueB = b.getPrimValue();
1241 vmfloat factorA = a.getUnitFactor();
1242 vmfloat factorB = b.getUnitFactor();
1243 a.setPrimValue(valueB);
1244 a.setUnitFactor(factorB);
1245 b.setPrimValue(valueA);
1246 b.setUnitFactor(factorA);
1247 }
1248
1249 // used to sort in descending order (unlike the default behaviour of std::sort() which is ascending order)
1250 template<class T> // T is either IntArrExprIter or RealArrExprIter
1251 struct DescArrExprSorter {
1252 inline bool operator()(const typename T::value_type a, const typename T::value_type b) const {
1253 return a > b;
1254 }
1255 };
1256
1257 VMFnResult* CoreVMFunction_sort::exec(VMFnArgs* args) {
1258 const bool bAscending =
1259 (args->argsCount() < 2) ? true : !args->arg(1)->asInt()->evalInt();
1260
1261 if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1262 VMIntArrayExpr* a = args->arg(0)->asIntArray();
1263 vmint n = a->arraySize();
1264 IntArrExprIter itBegin(a, 0);
1265 IntArrExprIter itEnd(a, n);
1266 if (bAscending) {
1267 std::sort(itBegin, itEnd);
1268 } else {
1269 DescArrExprSorter<IntArrExprIter> sorter;
1270 std::sort(itBegin, itEnd, sorter);
1271 }
1272 } else {
1273 VMRealArrayExpr* a = args->arg(0)->asRealArray();
1274 vmint n = a->arraySize();
1275 RealArrExprIter itBegin(a, 0);
1276 RealArrExprIter itEnd(a, n);
1277 if (bAscending) {
1278 std::sort(itBegin, itEnd);
1279 } else {
1280 DescArrExprSorter<RealArrExprIter> sorter;
1281 std::sort(itBegin, itEnd, sorter);
1282 }
1283 }
1284
1285 return successResult();
1286 }
1287
1288 ///////////////////////////////////////////////////////////////////////////
1289 // built-in script function: real_to_int() and int()
1290
1291 StdUnit_t CoreVMFunction_real_to_int::returnUnitType(VMFnArgs* args) {
1292 return args->arg(0)->asScalarNumberExpr()->unitType();
1293 }
1294
1295 bool CoreVMFunction_real_to_int::returnsFinal(VMFnArgs* args) {
1296 return args->arg(0)->asScalarNumberExpr()->isFinal();
1297 }
1298
1299 VMFnResult* CoreVMFunction_real_to_int::exec(VMFnArgs* args) {
1300 VMRealExpr* realExpr = args->arg(0)->asReal();
1301 vmfloat f = realExpr->evalReal();
1302 return successResult({
1303 .value = vmint(f),
1304 .unitFactor = realExpr->unitFactor()
1305 });
1306 }
1307
1308 ///////////////////////////////////////////////////////////////////////////
1309 // built-in script function: int_to_real() and real()
1310
1311 StdUnit_t CoreVMFunction_int_to_real::returnUnitType(VMFnArgs* args) {
1312 return args->arg(0)->asScalarNumberExpr()->unitType();
1313 }
1314
1315 bool CoreVMFunction_int_to_real::returnsFinal(VMFnArgs* args) {
1316 return args->arg(0)->asScalarNumberExpr()->isFinal();
1317 }
1318
1319 VMFnResult* CoreVMFunction_int_to_real::exec(VMFnArgs* args) {
1320 VMIntExpr* intExpr = args->arg(0)->asInt();
1321 vmint i = intExpr->evalInt();
1322 return successResult({
1323 .value = vmfloat(i),
1324 .unitFactor = intExpr->unitFactor()
1325 });
1326 }
1327
1328 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC