--- linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp 2017/05/26 18:30:42 3221 +++ linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp 2019/08/30 12:23:40 3582 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017 Christian Schoenebeck + * Copyright (c) 2014-2019 Christian Schoenebeck * * http://www.linuxsampler.org * @@ -15,9 +15,17 @@ #include #include "tree.h" #include "ScriptVM.h" +#include "../common/RTMath.h" namespace LinuxSampler { +inline bool _fEqualX(vmfloat a, vmfloat b) { + if (sizeof(vmfloat) == sizeof(float)) + return RTMath::fEqual32(a, b); + else + return RTMath::fEqual64(a, b); +} + /////////////////////////////////////////////////////////////////////////// // class VMEmptyResultFunction @@ -34,15 +42,62 @@ /////////////////////////////////////////////////////////////////////////// // class VMIntResultFunction -VMFnResult* VMIntResultFunction::errorResult(int i) { +VMFnResult* VMIntResultFunction::errorResult(vmint i) { result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); result.value = i; + result.unitPrefixFactor = VM_NO_FACTOR; return &result; } -VMFnResult* VMIntResultFunction::successResult(int i) { +VMFnResult* VMIntResultFunction::successResult(vmint i) { result.flags = STMT_SUCCESS; result.value = i; + result.unitPrefixFactor = VM_NO_FACTOR; + return &result; +} + +VMFnResult* VMIntResultFunction::errorResult(VMIntFnResDef res) { + result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + result.value = res.value; + result.unitPrefixFactor = res.unitFactor; + return &result; +} + +VMFnResult* VMIntResultFunction::successResult(VMIntFnResDef res) { + result.flags = STMT_SUCCESS; + result.value = res.value; + result.unitPrefixFactor = res.unitFactor; + return &result; +} + +/////////////////////////////////////////////////////////////////////////// +// class VMRealResultFunction + +VMFnResult* VMRealResultFunction::errorResult(vmfloat f) { + result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + result.value = f; + result.unitPrefixFactor = VM_NO_FACTOR; + return &result; +} + +VMFnResult* VMRealResultFunction::errorResult(VMRealFnResDef res) { + result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + result.value = res.value; + result.unitPrefixFactor = res.unitFactor; + return &result; +} + +VMFnResult* VMRealResultFunction::successResult(vmfloat f) { + result.flags = STMT_SUCCESS; + result.value = f; + result.unitPrefixFactor = VM_NO_FACTOR; + return &result; +} + +VMFnResult* VMRealResultFunction::successResult(VMRealFnResDef res) { + result.flags = STMT_SUCCESS; + result.value = res.value; + result.unitPrefixFactor = res.unitFactor; return &result; } @@ -62,24 +117,91 @@ } /////////////////////////////////////////////////////////////////////////// +// class VMNumberResultFunction + +VMFnResult* VMNumberResultFunction::errorResult(vmint i) { + intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + intResult.value = i; + intResult.unitPrefixFactor = VM_NO_FACTOR; + return &intResult; +} + +VMFnResult* VMNumberResultFunction::errorResult(vmfloat f) { + realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + realResult.value = f; + realResult.unitPrefixFactor = VM_NO_FACTOR; + return &realResult; +} + +VMFnResult* VMNumberResultFunction::successResult(vmint i) { + intResult.flags = STMT_SUCCESS; + intResult.value = i; + intResult.unitPrefixFactor = VM_NO_FACTOR; + return &intResult; +} + +VMFnResult* VMNumberResultFunction::successResult(vmfloat f) { + realResult.flags = STMT_SUCCESS; + realResult.value = f; + realResult.unitPrefixFactor = VM_NO_FACTOR; + return &realResult; +} + +VMFnResult* VMNumberResultFunction::errorIntResult(VMIntFnResDef res) { + intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + intResult.value = res.value; + intResult.unitPrefixFactor = res.unitFactor; + return &intResult; +} + +VMFnResult* VMNumberResultFunction::errorRealResult(VMRealFnResDef res) { + realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); + realResult.value = res.value; + realResult.unitPrefixFactor = res.unitFactor; + return &realResult; +} + +VMFnResult* VMNumberResultFunction::successIntResult(VMIntFnResDef res) { + intResult.flags = STMT_SUCCESS; + intResult.value = res.value; + intResult.unitPrefixFactor = res.unitFactor; + return &intResult; +} + +VMFnResult* VMNumberResultFunction::successRealResult(VMRealFnResDef res) { + realResult.flags = STMT_SUCCESS; + realResult.value = res.value; + realResult.unitPrefixFactor = res.unitFactor; + return &realResult; +} + +/////////////////////////////////////////////////////////////////////////// // built-in script function: message() -bool CoreVMFunction_message::acceptsArgType(int iArg, ExprType_t type) const { - return type == INT_EXPR || type == STRING_EXPR; +bool CoreVMFunction_message::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR; } VMFnResult* CoreVMFunction_message::exec(VMFnArgs* args) { if (!args->argsCount()) return errorResult(); + uint64_t usecs = RTMath::unsafeMicroSeconds(RTMath::real_clock); + VMStringExpr* strExpr = dynamic_cast(args->arg(0)); if (strExpr) { - std::cout << "[ScriptVM] " << strExpr->evalStr() << "\n"; + printf("[ScriptVM %.3f] %s\n", usecs/1000000.f, strExpr->evalStr().c_str()); + return successResult(); + } + + VMRealExpr* realExpr = dynamic_cast(args->arg(0)); + if (realExpr) { + printf("[ScriptVM %.3f] %f\n", usecs/1000000.f, realExpr->evalReal()); return successResult(); } VMIntExpr* intExpr = dynamic_cast(args->arg(0)); if (intExpr) { - std::cout << "[ScriptVM] " << intExpr->evalInt() << "\n"; + printf("[ScriptVM %.3f] %lld\n", usecs/1000000.f, (int64_t)intExpr->evalInt()); return successResult(); } @@ -89,18 +211,88 @@ /////////////////////////////////////////////////////////////////////////// // built-in script function: exit() +vmint CoreVMFunction_exit::maxAllowedArgs() const { + return (vm->isExitResultEnabled()) ? 1 : 0; +} + +bool CoreVMFunction_exit::acceptsArgType(vmint iArg, ExprType_t type) const { + if (!vm->isExitResultEnabled()) return false; + return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR; +} + +bool CoreVMFunction_exit::acceptsArgUnitType(vmint iArg, StdUnit_t type) const { + if (!vm->isExitResultEnabled()) return false; + return true; +} + +bool CoreVMFunction_exit::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const { + if (!vm->isExitResultEnabled()) return false; + return true; +} +bool CoreVMFunction_exit::acceptsArgFinal(vmint iArg) const { + if (!vm->isExitResultEnabled()) return false; + return true; +} + VMFnResult* CoreVMFunction_exit::exec(VMFnArgs* args) { this->result.flags = STMT_ABORT_SIGNALLED; + if (vm->isExitResultEnabled() && args->argsCount()) { + ExecContext* ctx = dynamic_cast(vm->currentVMExecContext()); + switch (args->arg(0)->exprType()) { + case INT_EXPR: { + VMIntExpr* expr = args->arg(0)->asInt(); + ctx->exitRes.intLiteral = IntLiteral({ + .value = expr->evalInt(), + .unitFactor = expr->unitFactor(), + .unitType = expr->unitType(), + .isFinal = expr->isFinal() + }); + ctx->exitRes.value = &ctx->exitRes.intLiteral; + break; + } + case REAL_EXPR: { + VMRealExpr* expr = args->arg(0)->asReal(); + ctx->exitRes.realLiteral = RealLiteral({ + .value = expr->evalReal(), + .unitFactor = expr->unitFactor(), + .unitType = expr->unitType(), + .isFinal = expr->isFinal() + }); + ctx->exitRes.value = &ctx->exitRes.realLiteral; + break; + } + case STRING_EXPR: + ctx->exitRes.stringLiteral = StringLiteral( + args->arg(0)->asString()->evalStr() + ); + ctx->exitRes.value = &ctx->exitRes.stringLiteral; + break; + default: + ; // noop - just to shut up the compiler + } + } return &result; } /////////////////////////////////////////////////////////////////////////// // built-in script function: wait() +bool CoreVMFunction_wait::acceptsArgUnitType(vmint iArg, StdUnit_t type) const { + if (iArg == 0) + return type == VM_NO_UNIT || type == VM_SECOND; + else + return type == VM_NO_UNIT; +} + +bool CoreVMFunction_wait::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const { + return iArg == 0 && type == VM_SECOND; +} + VMFnResult* CoreVMFunction_wait::exec(VMFnArgs* args) { ExecContext* ctx = dynamic_cast(vm->currentVMExecContext()); VMIntExpr* expr = dynamic_cast(args->arg(0)); - int us = expr->evalInt(); + StdUnit_t unit = expr->unitType(); + vmint us = (unit) ? expr->evalInt(VM_MICRO) : expr->evalInt(); if (us < 0) { wrnMsg("wait(): argument may not be negative! Aborting script!"); this->result.flags = STMT_ABORT_SIGNALLED; @@ -117,370 +309,1020 @@ /////////////////////////////////////////////////////////////////////////// // built-in script function: abs() -bool CoreVMFunction_abs::acceptsArgType(int iArg, ExprType_t type) const { - return type == INT_EXPR; +ExprType_t CoreVMFunction_abs::returnType(VMFnArgs* args) { + return args->arg(0)->exprType(); +} + +StdUnit_t CoreVMFunction_abs::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_abs::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + +bool CoreVMFunction_abs::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR; } VMFnResult* CoreVMFunction_abs::exec(VMFnArgs* args) { - return successResult( ::abs(args->arg(0)->asInt()->evalInt()) ); + VMExpr* arg = args->arg(0); + if (arg->exprType() == REAL_EXPR) { + VMRealExpr* expr = arg->asReal(); + return successRealResult({ + .value = ::fabs(expr->evalReal()), + .unitFactor = expr->unitFactor() + }); + } else { + VMIntExpr* expr = arg->asInt(); + return successIntResult({ + .value = ::abs(expr->evalInt()), + .unitFactor = expr->unitFactor() + }); + } } /////////////////////////////////////////////////////////////////////////// // built-in script function: random() -bool CoreVMFunction_random::acceptsArgType(int iArg, ExprType_t type) const { - return type == INT_EXPR; +ExprType_t CoreVMFunction_random::returnType(VMFnArgs* args) { + return (args->arg(0)->exprType() == INT_EXPR && + args->arg(1)->exprType() == INT_EXPR) ? INT_EXPR : REAL_EXPR; +} + +StdUnit_t CoreVMFunction_random::returnUnitType(VMFnArgs* args) { + // we ensure in checkArgs() below (which is called before this method here) + // that both arguments must be of same unit type, so either one is fine here + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_random::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal() || + args->arg(1)->asNumber()->isFinal(); +} + +bool CoreVMFunction_random::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR; +} + +void CoreVMFunction_random::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType() != + args->arg(1)->asNumber()->unitType()) + { + String a = unitTypeStr(args->arg(0)->asNumber()->unitType()); + String b = unitTypeStr(args->arg(1)->asNumber()->unitType()); + err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + "."); + return; + } + if (args->arg(0)->asNumber()->isFinal() != + args->arg(1)->asNumber()->isFinal()) + { + String a = args->arg(0)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + String b = args->arg(1)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final."); + } } VMFnResult* CoreVMFunction_random::exec(VMFnArgs* args) { - int iMin = args->arg(0)->asInt()->evalInt(); - int iMax = args->arg(1)->asInt()->evalInt(); float f = float(::rand()) / float(RAND_MAX); - return successResult( - iMin + roundf( f * float(iMax - iMin) ) - ); + + VMNumberExpr* arg0 = args->arg(0)->asNumber(); + VMNumberExpr* arg1 = args->arg(1)->asNumber(); + + if (arg0->exprType() == INT_EXPR && arg1->exprType() == INT_EXPR) { + vmint iMin = args->arg(0)->asInt()->evalInt(); + vmint iMax = args->arg(1)->asInt()->evalInt(); + if (arg0->unitFactor() == arg1->unitFactor()) { + return successIntResult({ + .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ), + .unitFactor = arg0->unitFactor() + }); + } else if (arg0->unitFactor() < arg1->unitFactor()) { + iMax = Unit::convIntToUnitFactor(iMax, arg1, arg0); + return successIntResult({ + .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ), + .unitFactor = arg0->unitFactor() + }); + } else { // arg0->unitFactor() > arg1->unitFactor() ... + iMin = Unit::convIntToUnitFactor(iMin, arg0, arg1); + return successIntResult({ + .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ), + .unitFactor = arg1->unitFactor() + }); + } + } else { + vmfloat fMin = arg0->evalCastReal(); + vmfloat fMax = arg1->evalCastReal(); + if (arg0->unitFactor() == arg1->unitFactor()) { + return successRealResult({ + .value = fMin + f * (fMax - fMin), + .unitFactor = arg0->unitFactor() + }); + } else if (arg0->unitFactor() < arg1->unitFactor()) { + fMax = Unit::convRealToUnitFactor(fMax, arg1, arg0); + return successRealResult({ + .value = fMin + f * (fMax - fMin), + .unitFactor = arg0->unitFactor() + }); + } else { // arg0->unitFactor() > arg1->unitFactor() ... + fMin = Unit::convRealToUnitFactor(fMin, arg0, arg1); + return successRealResult({ + .value = fMin + f * (fMax - fMin), + .unitFactor = arg1->unitFactor() + }); + } + } } /////////////////////////////////////////////////////////////////////////// // built-in script function: num_elements() -bool CoreVMFunction_num_elements::acceptsArgType(int iArg, ExprType_t type) const { - return type == INT_ARR_EXPR; +bool CoreVMFunction_num_elements::acceptsArgType(vmint iArg, ExprType_t type) const { + return isArray(type); } VMFnResult* CoreVMFunction_num_elements::exec(VMFnArgs* args) { - return successResult( args->arg(0)->asIntArray()->arraySize() ); + return successResult( args->arg(0)->asArray()->arraySize() ); } /////////////////////////////////////////////////////////////////////////// // built-in script function: inc() +StdUnit_t CoreVMFunction_inc::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_inc::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + +void CoreVMFunction_inc::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType()) { + String unitType = unitTypeStr(args->arg(0)->asNumber()->unitType()); + wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be incremented by one."); + } +} + VMFnResult* CoreVMFunction_inc::exec(VMFnArgs* args) { VMExpr* arg = args->arg(0); VMIntExpr* in = dynamic_cast(arg); VMVariable* out = dynamic_cast(arg); - if (!in || !out) successResult(0); - int i = in->evalInt() + 1; - IntLiteral tmp(i); + vmint i = in->evalInt() + 1; + IntLiteral tmp({ + .value = i, + .unitFactor = in->unitFactor() + }); out->assignExpr(&tmp); - return successResult(i); + return successResult({ + .value = i, + .unitFactor = in->unitFactor() + }); } /////////////////////////////////////////////////////////////////////////// // built-in script function: dec() +StdUnit_t CoreVMFunction_dec::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_dec::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + +void CoreVMFunction_dec::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType()) { + String unitType = unitTypeStr(args->arg(0)->asNumber()->unitType()); + wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be decremented by one."); + } +} + VMFnResult* CoreVMFunction_dec::exec(VMFnArgs* args) { VMExpr* arg = args->arg(0); VMIntExpr* in = dynamic_cast(arg); VMVariable* out = dynamic_cast(arg); - if (!in || !out) successResult(0); - int i = in->evalInt() - 1; - IntLiteral tmp(i); + vmint i = in->evalInt() - 1; + IntLiteral tmp({ + .value = i, + .unitFactor = in->unitFactor() + }); out->assignExpr(&tmp); - return successResult(i); + return successResult({ + .value = i, + .unitFactor = in->unitFactor() + }); } /////////////////////////////////////////////////////////////////////////// // built-in script function: in_range() -VMFnResult* CoreVMFunction_in_range::exec(VMFnArgs* args) { - int i = args->arg(0)->asInt()->evalInt(); - int lo = args->arg(1)->asInt()->evalInt(); - int hi = args->arg(2)->asInt()->evalInt(); - if (lo > hi) { // swap lo and hi - int tmp = lo; - lo = hi; - hi = tmp; +bool CoreVMFunction_in_range::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR; +} + +void CoreVMFunction_in_range::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType() != + args->arg(1)->asNumber()->unitType() || + args->arg(1)->asNumber()->unitType() != + args->arg(2)->asNumber()->unitType()) + { + String a = unitTypeStr(args->arg(0)->asNumber()->unitType()); + String b = unitTypeStr(args->arg(1)->asNumber()->unitType()); + String c = unitTypeStr(args->arg(2)->asNumber()->unitType()); + err("Arguments must all have same unit, however argument 1 is " + a + + ", argument 2 is " + b + ", argument 3 is " + c + "."); + return; + } + if (args->arg(0)->exprType() != args->arg(1)->exprType() || + args->arg(1)->exprType() != args->arg(2)->exprType()) + { + String a = typeStr(args->arg(0)->exprType()); + String b = typeStr(args->arg(1)->exprType()); + String c = typeStr(args->arg(2)->exprType()); + String r = typeStr(REAL_EXPR); + wrn("Argument 1 is " + a + ", argument 2 is " + b + + ", argument 3 is " + c + ", function result will be " + r + "."); } - return successResult(i >= lo && i <= hi); +} + +template +inline void _swapByValue(T& a, T& b) { + T tmp = a; + a = b; + b = tmp; +} + +VMFnResult* CoreVMFunction_in_range::exec(VMFnArgs* args) { + VMNumberExpr* argNeedle = args->arg(0)->asNumber(); + VMNumberExpr* argLo = args->arg(1)->asNumber(); + VMNumberExpr* argHi = args->arg(2)->asNumber(); + + vmfloat needle = argNeedle->evalCastReal(); + vmfloat lo = argLo->evalCastReal(); + vmfloat hi = argHi->evalCastReal(); + + needle *= argNeedle->unitFactor(); + lo *= argLo->unitFactor(); + hi *= argHi->unitFactor(); + + if (lo > hi) _swapByValue(lo, hi); + + return successResult(needle >= lo && needle <= hi); } /////////////////////////////////////////////////////////////////////////// // built-in script function: sh_left() +bool CoreVMFunction_sh_left::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + VMFnResult* CoreVMFunction_sh_left::exec(VMFnArgs* args) { - int i = args->arg(0)->asInt()->evalInt(); - int n = args->arg(1)->asInt()->evalInt(); + vmint i = args->arg(0)->asInt()->evalInt(); + vmint n = args->arg(1)->asInt()->evalInt(); return successResult(i << n); } /////////////////////////////////////////////////////////////////////////// // built-in script function: sh_right() +bool CoreVMFunction_sh_right::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + VMFnResult* CoreVMFunction_sh_right::exec(VMFnArgs* args) { - int i = args->arg(0)->asInt()->evalInt(); - int n = args->arg(1)->asInt()->evalInt(); + vmint i = args->arg(0)->asInt()->evalInt(); + vmint n = args->arg(1)->asInt()->evalInt(); return successResult(i >> n); } /////////////////////////////////////////////////////////////////////////// // built-in script function: min() +ExprType_t CoreVMFunction_min::returnType(VMFnArgs* args) { + return (args->arg(0)->exprType() == REAL_EXPR || + args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR; +} + +StdUnit_t CoreVMFunction_min::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_min::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal() || + args->arg(1)->asNumber()->isFinal(); +} + +bool CoreVMFunction_min::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR; +} + +void CoreVMFunction_min::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType() != + args->arg(1)->asNumber()->unitType()) + { + String a = unitTypeStr(args->arg(0)->asNumber()->unitType()); + String b = unitTypeStr(args->arg(1)->asNumber()->unitType()); + err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + "."); + return; + } + if (args->arg(0)->exprType() != args->arg(1)->exprType()) { + String a = typeStr(args->arg(0)->exprType()); + String b = typeStr(args->arg(1)->exprType()); + String c = typeStr(REAL_EXPR); + wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + "."); + return; + } + if (args->arg(0)->asNumber()->isFinal() != + args->arg(1)->asNumber()->isFinal()) + { + String a = args->arg(0)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + String b = args->arg(1)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final."); + } +} + VMFnResult* CoreVMFunction_min::exec(VMFnArgs* args) { - int l = args->arg(0)->asInt()->evalInt(); - int r = args->arg(1)->asInt()->evalInt(); - return successResult(l < r ? l : r); + VMNumberExpr* lhs = args->arg(0)->asNumber(); + VMNumberExpr* rhs = args->arg(1)->asNumber(); + if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) { + vmfloat lm = lhs->asReal()->evalReal(); + vmfloat rm = rhs->asReal()->evalReal(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod < rprod) ? lm : rm, + .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) { + vmfloat lm = lhs->asReal()->evalReal(); + vmint rm = rhs->asInt()->evalInt(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod < rprod) ? lm : rm, + .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) { + vmint lm = lhs->asInt()->evalInt(); + vmfloat rm = rhs->asReal()->evalReal(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod < rprod) ? lm : rm, + .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else { + vmint lm = lhs->asInt()->evalInt(); + vmint rm = rhs->asInt()->evalInt(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successIntResult({ + .value = (lprod < rprod) ? lm : rm, + .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } } /////////////////////////////////////////////////////////////////////////// // built-in script function: max() +ExprType_t CoreVMFunction_max::returnType(VMFnArgs* args) { + return (args->arg(0)->exprType() == REAL_EXPR || + args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR; +} + +StdUnit_t CoreVMFunction_max::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_max::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal() || + args->arg(1)->asNumber()->isFinal(); +} + +bool CoreVMFunction_max::acceptsArgType(vmint iArg, ExprType_t type) const { + return type == INT_EXPR || type == REAL_EXPR; +} + +void CoreVMFunction_max::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->asNumber()->unitType() != + args->arg(1)->asNumber()->unitType()) + { + String a = unitTypeStr(args->arg(0)->asNumber()->unitType()); + String b = unitTypeStr(args->arg(1)->asNumber()->unitType()); + err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + "."); + return; + } + if (args->arg(0)->exprType() != args->arg(1)->exprType()) { + String a = typeStr(args->arg(0)->exprType()); + String b = typeStr(args->arg(1)->exprType()); + String c = typeStr(REAL_EXPR); + wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + "."); + return; + } + if (args->arg(0)->asNumber()->isFinal() != + args->arg(1)->asNumber()->isFinal()) + { + String a = args->arg(0)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + String b = args->arg(1)->asNumber()->isFinal() ? "'final'" : "not 'final'"; + wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final."); + } +} + VMFnResult* CoreVMFunction_max::exec(VMFnArgs* args) { - int l = args->arg(0)->asInt()->evalInt(); - int r = args->arg(1)->asInt()->evalInt(); - return successResult(l > r ? l : r); + VMNumberExpr* lhs = args->arg(0)->asNumber(); + VMNumberExpr* rhs = args->arg(1)->asNumber(); + if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) { + vmfloat lm = lhs->asReal()->evalReal(); + vmfloat rm = rhs->asReal()->evalReal(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod > rprod) ? lm : rm, + .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) { + vmfloat lm = lhs->asReal()->evalReal(); + vmint rm = rhs->asInt()->evalInt(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod > rprod) ? lm : rm, + .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) { + vmint lm = lhs->asInt()->evalInt(); + vmfloat rm = rhs->asReal()->evalReal(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successRealResult({ + .value = (lprod > rprod) ? lm : rm, + .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } else { + vmint lm = lhs->asInt()->evalInt(); + vmint rm = rhs->asInt()->evalInt(); + vmfloat lprod = lm * lhs->unitFactor(); + vmfloat rprod = rm * rhs->unitFactor(); + return successIntResult({ + .value = (lprod > rprod) ? lm : rm, + .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor() + }); + } } /////////////////////////////////////////////////////////////////////////// // built-in script function: array_equal() +bool CoreVMFunction_array_equal::acceptsArgType(vmint iArg, ExprType_t type) const { + return isArray(type); +} + +void CoreVMFunction_array_equal::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->exprType() != args->arg(1)->exprType()) { + String a = typeStr(args->arg(0)->exprType()); + String b = typeStr(args->arg(1)->exprType()); + err("Argument 1 is " + a + ", whereas argument 2 is " + b + "."); + return; + } + if (args->arg(0)->asArray()->arraySize() != + args->arg(1)->asArray()->arraySize()) + { + wrn("Result of function call is always false, since the passed two arrays were declared with different array sizes."); + } +} + VMFnResult* CoreVMFunction_array_equal::exec(VMFnArgs* args) { - VMIntArrayExpr* l = args->arg(0)->asIntArray(); - VMIntArrayExpr* r = args->arg(1)->asIntArray(); + VMArrayExpr* l = args->arg(0)->asArray(); + VMArrayExpr* r = args->arg(1)->asArray(); if (l->arraySize() != r->arraySize()) { - wrnMsg("array_equal(): the two arrays differ in size"); + //wrnMsg("array_equal(): the two arrays differ in size"); return successResult(0); // false } - const int n = l->arraySize(); - for (int i = 0; i < n; ++i) - if (l->evalIntElement(i) != r->evalIntElement(i)) - return successResult(0); // false + const vmint n = l->arraySize(); + // checkArgs() above ensured that we either have INT_ARR_EXPR on both sides + // or REAL_ARR_EXPR on both sides, so we can simplify here (a bit) + if (l->exprType() == INT_ARR_EXPR) { + VMIntArrayExpr* lia = l->asIntArray(); + VMIntArrayExpr* ria = r->asIntArray(); + for (vmint i = 0; i < n; ++i) { + vmint lvalue = lia->evalIntElement(i); + vmint rvalue = ria->evalIntElement(i); + vmfloat lfactor = lia->unitFactorOfElement(i); + vmfloat rfactor = ria->unitFactorOfElement(i); + if (lfactor == rfactor) { + if (lvalue != rvalue) + return successResult(0); // false + else + continue; + } + if (lfactor < rfactor) { + if (lvalue != Unit::convIntToUnitFactor(rvalue, rfactor, lfactor)) + return successResult(0); // false + else + continue; + } else { + if (rvalue != Unit::convIntToUnitFactor(lvalue, lfactor, rfactor)) + return successResult(0); // false + else + continue; + } + } + } else { + VMRealArrayExpr* lra = l->asRealArray(); + VMRealArrayExpr* rra = r->asRealArray(); + for (vmint i = 0; i < n; ++i) { + vmfloat lvalue = lra->evalRealElement(i); + vmfloat rvalue = rra->evalRealElement(i); + vmfloat lfactor = lra->unitFactorOfElement(i); + vmfloat rfactor = rra->unitFactorOfElement(i); + if (lfactor == rfactor) { + if (!_fEqualX(lvalue, rvalue)) + return successResult(0); // false + else + continue; + } + if (lfactor < rfactor) { + if (!_fEqualX(lvalue, Unit::convRealToUnitFactor(rvalue, rfactor, lfactor))) + return successResult(0); // false + else + continue; + } else { + if (!_fEqualX(rvalue, Unit::convRealToUnitFactor(lvalue, lfactor, rfactor))) + return successResult(0); // false + else + continue; + } + } + } return successResult(1); // true } /////////////////////////////////////////////////////////////////////////// // built-in script function: search() -ExprType_t CoreVMFunction_search::argType(int iArg) const { +ExprType_t CoreVMFunction_search::argType(vmint iArg) const { return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR; } -bool CoreVMFunction_search::acceptsArgType(int iArg, ExprType_t type) const { +bool CoreVMFunction_search::acceptsArgType(vmint iArg, ExprType_t type) const { if (iArg == 0) - return type == INT_ARR_EXPR; + return isArray(type); else - return type == INT_EXPR; + return type == INT_EXPR || type == REAL_EXPR; +} + +void CoreVMFunction_search::checkArgs(VMFnArgs* args, + std::function err, + std::function wrn) +{ + // super class checks + Super::checkArgs(args, err, wrn); + + // own checks ... + if (args->arg(0)->exprType() == INT_ARR_EXPR && + args->arg(1)->exprType() != INT_EXPR) + { + String a = typeStr(INT_ARR_EXPR); + String bIs = typeStr(args->arg(1)->exprType()); + String bShould = typeStr(INT_EXPR); + err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though."); + return; + } + if (args->arg(0)->exprType() == REAL_ARR_EXPR && + args->arg(1)->exprType() != REAL_EXPR) + { + String a = typeStr(REAL_ARR_EXPR); + String bIs = typeStr(args->arg(1)->exprType()); + String bShould = typeStr(REAL_EXPR); + err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though."); + return; + } } VMFnResult* CoreVMFunction_search::exec(VMFnArgs* args) { - VMIntArrayExpr* a = args->arg(0)->asIntArray(); - const int needle = args->arg(1)->asInt()->evalInt(); - const int n = a->arraySize(); - for (int i = 0; i < n; ++i) - if (a->evalIntElement(i) == needle) - return successResult(i); + VMArrayExpr* a = args->arg(0)->asArray(); + const vmint n = a->arraySize(); + if (a->exprType() == INT_ARR_EXPR) { + const vmint needle = args->arg(1)->asInt()->evalInt(); + VMIntArrayExpr* intArray = a->asIntArray(); + for (vmint i = 0; i < n; ++i) + if (intArray->evalIntElement(i) == needle) + return successResult(i); + } else { // real array ... + const vmfloat needle = args->arg(1)->asReal()->evalReal(); + VMRealArrayExpr* realArray = a->asRealArray(); + for (vmint i = 0; i < n; ++i) { + const vmfloat value = realArray->evalRealElement(i); + if (_fEqualX(value, needle)) + return successResult(i); + } + } return successResult(-1); // not found } /////////////////////////////////////////////////////////////////////////// // built-in script function: sort() -ExprType_t CoreVMFunction_sort::argType(int iArg) const { +ExprType_t CoreVMFunction_sort::argType(vmint iArg) const { return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR; } -bool CoreVMFunction_sort::acceptsArgType(int iArg, ExprType_t type) const { +bool CoreVMFunction_sort::acceptsArgType(vmint iArg, ExprType_t type) const { if (iArg == 0) - return type == INT_ARR_EXPR; + return isArray(type); else return type == INT_EXPR; } +// The following structs and template classes act as adapters for allowing to +// use std sort algorithms on our arrays. It might look a bit more complicated +// than it ought to be, but there is one reason for the large amount of +// 'adapter' code below: the STL std algorithms rely on 'lvalues' to do their +// e.g. sorting) jobs, that is they expect containers to have 'localizeable' +// data which essentially means their data should reside somewhere in memory and +// directly be accessible (readable and writable) there, which is not the case +// with our VM interfaces which actually always require virtual getter and +// setter methods to be called instead. So we must emulate lvalues by custom +// classes/structs which forward between our getters/setters and the lvalue +// access operators used by the STL std algorithms. + +struct IntArrayAccessor { + static inline vmint getPrimaryValue(VMIntArrayExpr* arr, vmint index) { + return arr->evalIntElement(index); + } + static inline void setPrimaryValue(VMIntArrayExpr* arr, vmint index, vmint value) { + arr->assignIntElement(index, value); + } +}; + +struct RealArrayAccessor { + static inline vmfloat getPrimaryValue(VMRealArrayExpr* arr, vmint index) { + return arr->evalRealElement(index); + } + static inline void setPrimaryValue(VMRealArrayExpr* arr, vmint index, vmfloat value) { + arr->assignRealElement(index, value); + } +}; + +template // i.e. T_array is either VMIntArrayExpr or VMRealArrayExpr struct ArrElemPOD { - VMIntArrayExpr* m_array; - int m_index; + T_array* m_array; + vmint m_index; }; -static inline void swap(class ArrElemRef& a, class ArrElemRef& b); +// This class is used for temporary values by std::sort(). +template // i.e. T_value is either vmint or vmfloat +struct ScalarNmbrVal { + T_value primValue; + vmfloat unitFactor; + + inline bool operator<(const ScalarNmbrVal& other) const { + return getProdValue() < other.getProdValue(); + } + inline bool operator>(const ScalarNmbrVal& other) const { + return getProdValue() > other.getProdValue(); + } + inline vmfloat getProdValue() const { + // simple solution for both vmint and vmfloat, should be fine for just sorting + return primValue * unitFactor; + } +}; -class ArrElemRef : protected ArrElemPOD { +// This class emulates lvalue access (access by reference) which is used by ArrExprIter::operator*() below. +template // T_accessor is either IntArrayAccessor or RealArrayAccessor +class ArrElemRef : protected ArrElemPOD { public: - ArrElemRef() { - m_array = NULL; - m_index = 0; - } - ArrElemRef(VMIntArrayExpr* a, int index) { - m_array = a; - m_index = index; + typedef ScalarNmbrVal ScalarNmbrVal; + + inline ArrElemRef(T_array* a, vmint index) { + this->m_array = a; + this->m_index = index; + } + inline ArrElemRef(const ArrElemRef& ref) { + this->m_array = ref.m_array; + this->m_index = ref.m_index; } inline ArrElemRef& operator=(const ArrElemRef& e) { - setValue(e.getValue()); + setPrimValue(e.getPrimValue()); + setUnitFactor(e.getUnitFactor()); return *this; } - inline ArrElemRef& operator=(int val) { - setValue(val); + inline ArrElemRef& operator=(ScalarNmbrVal value) { + setPrimValue(value.primValue); + setUnitFactor(value.unitFactor); return *this; } inline bool operator==(const ArrElemRef& e) const { - if (m_index == e.m_index) - return true; - return getValue() == e.getValue(); - } - inline bool operator==(int val) const { - return getValue() == val; + return getProdValue() == e.getProdValue(); } inline bool operator!=(const ArrElemRef& e) const { return !(operator==(e)); } - inline bool operator!=(int val) const { - return !(operator==(val)); - } inline bool operator<(const ArrElemRef& e) const { - if (m_index == e.m_index) - return false; - return getValue() < e.getValue(); - } - inline bool operator<(int val) const { - return getValue() < val; + return getProdValue() < e.getProdValue(); } inline bool operator>(const ArrElemRef& e) const { - if (m_index == e.m_index) - return false; - return getValue() > e.getValue(); - } - inline bool operator>(int val) const { - return getValue() > val; + return getProdValue() > e.getProdValue(); } inline bool operator<=(const ArrElemRef& e) const { - if (m_index == e.m_index) - return true; - return getValue() <= e.getValue(); - } - inline bool operator<=(int val) const { - return getValue() <= val; + return getProdValue() <= e.getProdValue(); } inline bool operator>=(const ArrElemRef& e) const { - if (m_index == e.m_index) - return true; - return getValue() >= e.getValue(); + return getProdValue() >= e.getProdValue(); + } + inline bool operator==(const ScalarNmbrVal& s) const { + return getProdValue() == s.getProdValue(); + } + inline bool operator!=(const ScalarNmbrVal& s) const { + return !(operator==(s)); + } + inline bool operator<(const ScalarNmbrVal& s) const { + return getProdValue() < s.getProdValue(); + } + inline bool operator>(const ScalarNmbrVal& s) const { + return getProdValue() > s.getProdValue(); + } + inline bool operator<=(const ScalarNmbrVal& s) const { + return getProdValue() <= s.getProdValue(); } - inline bool operator>=(int val) const { - return getValue() >= val; + inline bool operator>=(const ScalarNmbrVal& s) const { + return getProdValue() >= s.getProdValue(); } - inline operator int() const { - return getValue(); + inline operator ScalarNmbrVal() { + return { + .primValue = getPrimValue() , + .unitFactor = getUnitFactor() + }; } protected: - inline int getValue() const { - return m_array->evalIntElement(m_index); + inline T_value getPrimValue() const { + return T_accessor::getPrimaryValue( this->m_array, this->m_index ); } - inline void setValue(int value) { - m_array->assignIntElement(m_index, value); + inline void setPrimValue(T_value value) { + T_accessor::setPrimaryValue( this->m_array, this->m_index, value ); } - - friend void swap(class ArrElemRef& a, class ArrElemRef& b); -}; - -class ArrElemPtr : protected ArrElemPOD { -public: - ArrElemPtr() { - m_array = NULL; - m_index = 0; - } - ArrElemPtr(VMIntArrayExpr* a, int index) { - m_array = a; - m_index = index; + inline vmfloat getUnitFactor() const { + return this->m_array->unitFactorOfElement(this->m_index); } - inline ArrElemRef operator*() { - return *(ArrElemRef*)this; + inline void setUnitFactor(vmfloat factor) { + this->m_array->assignElementUnitFactor(this->m_index, factor); + } + inline vmfloat getProdValue() const { + // simple solution for both vmint and vmfloat, should be fine for just sorting + vmfloat primary = (vmfloat) getPrimValue(); + vmfloat factor = getUnitFactor(); + return primary * factor; } -}; -static inline void swap(ArrElemRef& a, ArrElemRef& b) { - int valueA = a.getValue(); - int valueB = b.getValue(); - a.setValue(valueB); - b.setValue(valueA); -} + // allow swap() functions below to access protected methods here + friend void swap(class ArrElemRef a, + class ArrElemRef b); +}; -class ArrExprIter : public ArrElemPOD { +// custom iterator class to be used by std:sort() on our VM arrays +template +class ArrExprIter : public ArrElemPOD { public: typedef std::random_access_iterator_tag iterator_category; - typedef int value_type; typedef ssize_t difference_type; - typedef ArrElemPtr pointer; - typedef ArrElemRef reference; - - ArrExprIter(VMIntArrayExpr* a, int index) { - m_array = a; - m_index = index; + typedef ArrElemRef ArrElemRef; + typedef ArrElemRef reference; // type used by STL for access by reference + typedef void pointer; // type used by STL for -> operator result, we don't use that operator at all so just void it + typedef ScalarNmbrVal value_type; // type used by STL for temporary values + + ArrExprIter(T_array* a, vmint index) { + this->m_array = a; + this->m_index = index; + } + ArrExprIter(const ArrElemRef& ref) { + this->m_array = ref.m_array; + this->m_index = ref.m_index; } inline ArrElemRef operator*() { - return *(ArrElemRef*)this; + return ArrElemRef(this->m_array, this->m_index); } inline ArrExprIter& operator++() { // prefix increment - ++m_index; + ++(this->m_index); return *this; } inline ArrExprIter& operator--() { // prefix decrement - --m_index; + --(this->m_index); return *this; } inline ArrExprIter operator++(int) { // postfix increment ArrExprIter it = *this; - ++m_index; + ++(this->m_index); return it; } inline ArrExprIter operator--(int) { // postfix decrement ArrExprIter it = *this; - --m_index; + --(this->m_index); return it; } + inline ArrExprIter& operator+=(difference_type d) { + this->m_index += d; + return *this; + } + inline ArrExprIter& operator-=(difference_type d) { + this->m_index -= d; + return *this; + } inline bool operator==(const ArrExprIter& other) const { - return m_index == other.m_index; + return this->m_index == other.m_index; } inline bool operator!=(const ArrExprIter& other) const { - return m_index != other.m_index; + return this->m_index != other.m_index; } inline bool operator<(const ArrExprIter& other) const { - return m_index < other.m_index; + return this->m_index < other.m_index; } inline bool operator>(const ArrExprIter& other) const { - return m_index > other.m_index; + return this->m_index > other.m_index; } inline bool operator<=(const ArrExprIter& other) const { - return m_index <= other.m_index; + return this->m_index <= other.m_index; } inline bool operator>=(const ArrExprIter& other) const { - return m_index >= other.m_index; + return this->m_index >= other.m_index; } inline difference_type operator+(const ArrExprIter& other) const { - return m_index + other.m_index; + return this->m_index + other.m_index; } inline difference_type operator-(const ArrExprIter& other) const { - return m_index - other.m_index; + return this->m_index - other.m_index; } inline ArrExprIter operator-(difference_type d) const { - return ArrExprIter(m_array, m_index - d); + return ArrExprIter(this->m_array, this->m_index - d); } inline ArrExprIter operator+(difference_type d) const { - return ArrExprIter(m_array, m_index + d); + return ArrExprIter(this->m_array, this->m_index + d); } inline ArrExprIter operator*(difference_type factor) const { - return ArrExprIter(m_array, m_index * factor); + return ArrExprIter(this->m_array, this->m_index * factor); } }; +typedef ArrExprIter IntArrExprIter; +typedef ArrExprIter RealArrExprIter; + +// intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions +static inline void swap(IntArrExprIter::ArrElemRef a, + IntArrExprIter::ArrElemRef b) +{ + vmint valueA = a.getPrimValue(); + vmint valueB = b.getPrimValue(); + vmfloat factorA = a.getUnitFactor(); + vmfloat factorB = b.getUnitFactor(); + a.setPrimValue(valueB); + a.setUnitFactor(factorB); + b.setPrimValue(valueA); + b.setUnitFactor(factorA); +} + +// intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions +static inline void swap(RealArrExprIter::ArrElemRef a, + RealArrExprIter::ArrElemRef b) +{ + vmfloat valueA = a.getPrimValue(); + vmfloat valueB = b.getPrimValue(); + vmfloat factorA = a.getUnitFactor(); + vmfloat factorB = b.getUnitFactor(); + a.setPrimValue(valueB); + a.setUnitFactor(factorB); + b.setPrimValue(valueA); + b.setUnitFactor(factorA); +} + +// used to sort in descending order (unlike the default behaviour of std::sort() which is ascending order) +template // T is either IntArrExprIter or RealArrExprIter struct DescArrExprSorter { - inline bool operator()(const int& a, const int& b) const { + inline bool operator()(const typename T::value_type a, const typename T::value_type b) const { return a > b; } }; VMFnResult* CoreVMFunction_sort::exec(VMFnArgs* args) { - VMIntArrayExpr* a = args->arg(0)->asIntArray(); - bool bAscending = + const bool bAscending = (args->argsCount() < 2) ? true : !args->arg(1)->asInt()->evalInt(); - int n = a->arraySize(); - ArrExprIter itBegin(a, 0); - ArrExprIter itEnd(a, n); - if (bAscending) { - std::sort(itBegin, itEnd); + + if (args->arg(0)->exprType() == INT_ARR_EXPR) { + VMIntArrayExpr* a = args->arg(0)->asIntArray(); + vmint n = a->arraySize(); + IntArrExprIter itBegin(a, 0); + IntArrExprIter itEnd(a, n); + if (bAscending) { + std::sort(itBegin, itEnd); + } else { + DescArrExprSorter sorter; + std::sort(itBegin, itEnd, sorter); + } } else { - DescArrExprSorter sorter; - std::sort(itBegin, itEnd, sorter); + VMRealArrayExpr* a = args->arg(0)->asRealArray(); + vmint n = a->arraySize(); + RealArrExprIter itBegin(a, 0); + RealArrExprIter itEnd(a, n); + if (bAscending) { + std::sort(itBegin, itEnd); + } else { + DescArrExprSorter sorter; + std::sort(itBegin, itEnd, sorter); + } } + return successResult(); } +/////////////////////////////////////////////////////////////////////////// +// built-in script function: real_to_int() and int() + +StdUnit_t CoreVMFunction_real_to_int::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_real_to_int::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + +VMFnResult* CoreVMFunction_real_to_int::exec(VMFnArgs* args) { + VMRealExpr* realExpr = args->arg(0)->asReal(); + vmfloat f = realExpr->evalReal(); + return successResult({ + .value = vmint(f), + .unitFactor = realExpr->unitFactor() + }); +} + +/////////////////////////////////////////////////////////////////////////// +// built-in script function: int_to_real() and real() + +StdUnit_t CoreVMFunction_int_to_real::returnUnitType(VMFnArgs* args) { + return args->arg(0)->asNumber()->unitType(); +} + +bool CoreVMFunction_int_to_real::returnsFinal(VMFnArgs* args) { + return args->arg(0)->asNumber()->isFinal(); +} + +VMFnResult* CoreVMFunction_int_to_real::exec(VMFnArgs* args) { + VMIntExpr* intExpr = args->arg(0)->asInt(); + vmint i = intExpr->evalInt(); + return successResult({ + .value = vmfloat(i), + .unitFactor = intExpr->unitFactor() + }); +} + } // namespace LinuxSampler