Add floating point support to C4Value/C4Aul

floating-point
Nicolas Hake 2010-07-08 03:15:03 +02:00
parent ff2e4e05b0
commit 6938e64cba
9 changed files with 226 additions and 41 deletions

View File

@ -1535,7 +1535,7 @@ bool C4Command::InitEvaluation()
case C4CMD_MoveTo:
{
// Target coordinates by Target
if (Target) { Tx+=Target->GetX(); Ty+=Target->GetY(); Target=NULL; }
if (Target) { Tx+=C4VInt(Target->GetX()); Ty+=Target->GetY(); Target=NULL; }
// Adjust coordinates
int32_t iTx = Tx._getInt();
if (~Data.getInt() & C4CMD_MoveTo_NoPosAdjust) AdjustMoveToTarget(iTx,Ty,FreeMoveTo(cObj),cObj->Shape.Hgt);

View File

@ -55,6 +55,9 @@
#define C4REAL_MODE C4REAL_MODE_SSE_FLOAT
#endif
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/is_pod.hpp>
template<class C4RealImpl>
class C4RealBase
{
@ -62,6 +65,7 @@ class C4RealBase
friend C4RealBase Sin(const C4RealBase &);
friend C4RealBase Cos(const C4RealBase &);
public:
inline C4RealBase(int32_t val = 0) : value(val) { }
inline C4RealBase(float val) : value(val) {}
@ -127,6 +131,23 @@ public:
// versions via operator bool
inline operator bool() const { return static_cast<bool>(value); }
inline bool operator !() const { return !operator bool(); }
// C++03 doesn't support explicitly defaulted ctors, so C4RealBase can't
// be a POD, so we can't directly store it into unions. Find a type that
// allows this.
template<class T, class IsPOD> struct StorageTypeSelector;
template<class T>
struct StorageTypeSelector<T, boost::false_type> { T v; };
template<class T>
struct StorageTypeSelector<T, boost::true_type> { typename T::StorageType v; };
typedef StorageTypeSelector<C4RealImpl, typename boost::is_class<C4RealImpl>::type> StorageType;
static_assert(boost::is_pod<StorageType>::value, "C4RealBase: StorageType is not a POD type");
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
C4RealBase(StorageType rhs) : value(rhs.v) {}
operator StorageType() const { StorageType nrv = {value}; return nrv; }
};
typedef C4RealBase<class C4RealImpl_Fixed> C4Real_Fixed;

View File

@ -45,6 +45,9 @@ class C4RealImpl_Fixed
static long SineTable[9001]; // external table of sine values
public:
struct StorageType { int32_t v; };
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
inline C4RealImpl_Fixed() : val(0) {}
inline C4RealImpl_Fixed(const C4RealImpl_Fixed &rhs) : val(rhs.val) {}
explicit inline C4RealImpl_Fixed(int32_t iVal) : val (iVal * FIXED_FPF) { }
@ -57,6 +60,8 @@ public:
explicit inline C4RealImpl_Fixed(float fVal)
: val(static_cast<int32_t>(fVal * float(FIXED_FPF)))
{ }
inline C4RealImpl_Fixed(StorageType rhs) : val(rhs.v) {}
operator StorageType() const { StorageType nrv = {val}; return nrv; }
int32_t to_int() const
{

View File

@ -63,6 +63,21 @@ public:
return f;
}
// To store C4RealImpl_SSE into unions, we're using an anonymous struct
// to distinguish types, and an int32_t inside that struct to avoid passing
// parameters via the x87 stack.
struct StorageType { int32_t v; };
friend bool operator==(StorageType lhs, StorageType rhs) { return lhs.v == rhs.v; }
inline C4RealImpl_SSE(StorageType rhs)
: value(_mm_load_ss(reinterpret_cast<float*>(&rhs.v)))
{}
operator StorageType() const
{
StorageType nrv;
_mm_store_ss(reinterpret_cast<float*>(&nrv.v), value);
return nrv;
}
// Arithmetics
// We're using _ps intrinsics for everything except division because they
// have the same latency as their _ss counterparts, but their representa-

View File

@ -192,6 +192,7 @@ enum C4AulBCCType
AB_CALLFS, // failsafe direct call
AB_STACK, // push nulls / pop
AB_INT, // constant: int
AB_FLOAT, // constant: float
AB_BOOL, // constant: bool
AB_STRING, // constant: string
AB_C4ID, // constant: C4ID
@ -238,6 +239,7 @@ struct C4AulBCC
union
{
int32_t i;
C4Real::StorageType fl;
C4String * s;
C4AulFunc * f;
intptr_t X;

View File

@ -173,6 +173,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PushValue(C4VInt(pCPos->Par.i));
break;
case AB_FLOAT:
PushValue(C4VFloat(pCPos->Par.fl));
break;
case AB_BOOL:
PushValue(C4VBool(!! pCPos->Par.i));
break;
@ -274,7 +278,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
if (!pPar2->_getInt())
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
pPar1->SetInt(pPar1->_getInt() / pPar2->_getInt());
pPar1->Deref();
*pPar1 /= *pPar2;
PopValue();
break;
}
@ -282,7 +287,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() * pPar2->_getInt());
pPar1->Deref();
*pPar1 *= *pPar2;
PopValue();
break;
}
@ -301,7 +307,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() - pPar2->_getInt());
pPar1->Deref();
*pPar1 -= *pPar2;
PopValue();
break;
}
@ -309,7 +316,8 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetInt(pPar1->_getInt() + pPar2->_getInt());
pPar1->Deref();
*pPar1 += *pPar2;
PopValue();
break;
}
@ -405,7 +413,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 *= pPar2 ->_getInt();
*pPar1 *= *pPar2;
PopValue();
break;
}
@ -415,7 +423,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
if (!pPar2->_getInt())
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
*pPar1 /= pPar2->_getInt();
*pPar1 /= *pPar2;
PopValue();
break;
}
@ -433,7 +441,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 += pPar2 ->_getInt();
*pPar1 += *pPar2;
PopValue();
break;
}
@ -441,7 +449,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
{
CheckOpPars3(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
*pPar1 -= pPar2 ->_getInt();
*pPar1 -= *pPar2;
PopValue();
break;
}

View File

@ -96,6 +96,7 @@ enum C4AulTokenType
ATT_DIR, // directive
ATT_IDTF, // identifier
ATT_INT, // integer constant
ATT_FLOAT, // floating point constant
ATT_BOOL, // boolean constant
ATT_STRING, // string constant
ATT_NIL, // "nil"
@ -436,11 +437,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
// postfix
{ 14, "**", AB_Pow, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "/", AB_Div, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 13, "/", AB_Div, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 13, "%", AB_Mod, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 12, "-", AB_Sub, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 12, "+", AB_Sum, 1, 0, 0, C4V_Any, C4V_Any, C4V_Any},
{ 11, "<<", AB_LeftShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 11, ">>", AB_RightShift, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 10, "<", AB_LessThan, 1, 0, 0, C4V_Bool, C4V_Int, C4V_Int},
@ -454,11 +455,11 @@ C4ScriptOpDef C4ScriptOpMap[] =
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
{ 4, "||", AB_JUMPOR, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
{ 2, "&=", AB_AndIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "|=", AB_OrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
{ 2, "^=", AB_XOrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
@ -545,6 +546,11 @@ static int32_t StrToI32(char *s, int base, char **scan_end)
return result;
}
static float StrToF32(const char *s, char **scan_end)
{
return strtod(s, scan_end);
}
void C4AulParseState::ClearToken()
{
// if last token was a string, make sure its ref is deleted
@ -571,6 +577,7 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
TGS_Ident, // getting identifier
TGS_Int, // getting integer
TGS_IntHex, // getting hexadecimal integer
TGS_Float, // getting floating point value
TGS_String, // getting string
TGS_Dir // getting directive
};
@ -709,6 +716,13 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
break;
case TGS_Int: // integer: parse until non-number is found
if (C == '.')
{
State = TGS_Float;
break;
}
else
// Fall through
case TGS_IntHex:
if ((C < '0') || (C > '9'))
{
@ -741,6 +755,17 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
}
break;
case TGS_Float: // float (after decimal point): parse until non-numeric
if ((C < '0') || (C > '9'))
{
Len = Min(Len, C4AUL_MAX_Identifier);
SCopy(SPos0, pToken, Len);
float value = StrToF32(pToken, 0);
*pInt = *reinterpret_cast<int*>(&value);
return ATT_FLOAT;
}
break;
case TGS_String: // string: parse until '"'; check for eof!
// string end
@ -1020,6 +1045,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
switch (eType)
{
case AB_INT:
case AB_FLOAT:
case AB_BOOL:
case AB_STRING:
case AB_C4ID:
@ -2439,6 +2465,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
switch (val.GetType())
{
case C4V_Int: AddBCC(AB_INT, val.GetData().Int); break;
case C4V_Float:
{
C4Real::StorageType f = val.getFloat();
AddBCC(AB_FLOAT, *reinterpret_cast<intptr_t*>(&f));
break;
}
case C4V_Bool: AddBCC(AB_BOOL, val.GetData().Int); break;
case C4V_String:
AddBCC(AB_STRING, reinterpret_cast<intptr_t>(val._getStr()));
@ -2474,6 +2506,12 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
Shift();
break;
}
case ATT_FLOAT: // constant in cInt
{
AddBCC(AB_FLOAT, cInt);
Shift();
break;
}
case ATT_BOOL: // constant in cInt
{
AddBCC(AB_BOOL, cInt);

View File

@ -284,6 +284,8 @@ const char* GetC4VName(const C4V_Type Type)
return "nil";
case C4V_Int:
return "int";
case C4V_Float:
return "float";
case C4V_Bool:
return "bool";
case C4V_C4Object:
@ -309,6 +311,8 @@ char GetC4VID(const C4V_Type Type)
return 'A';
case C4V_Int:
return 'i';
case C4V_Float:
return 'f';
case C4V_Bool:
return 'b';
case C4V_C4Object:
@ -338,6 +342,8 @@ C4V_Type GetC4VFromID(const char C4VID)
return C4V_Any;
case 'i':
return C4V_Int;
case 'f':
return C4V_Float;
case 'b':
return C4V_Bool;
case 'o':
@ -400,9 +406,27 @@ bool C4Value::FnCnvObject(C4Value *Val, C4V_Type toType)
return false;
}
static bool FnI2F(C4Value *val, C4V_Type toType)
{
assert(val->GetType() == C4V_Int || val->GetType() == C4V_Bool);
assert(toType == C4V_Float);
val->SetFloat(val->_getInt());
return true;
}
static bool FnF2I(C4Value *val, C4V_Type toType)
{
assert(toType == C4V_Int || toType == C4V_Bool);
assert(val->GetType() == C4V_Float);
val->SetInt(val->_getFloat());
return val->ConvertTo(toType);
}
// Type conversion table
#define CnvOK 0, false // allow conversion by same value
#define CnvOK0 FnOk0, true
#define CnvI2F FnI2F, false // convert int->C4Real
#define CnvF2I FnF2I, false // convert C4Real->int
#define CnvError FnCnvError, true
#define CnvDeref FnCnvDeref, false
#define CnvPLR FnCnvPLR, false
@ -413,6 +437,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Any - is always 0, convertible to everything
{ CnvOK }, // any same
{ CnvOK }, // int
{ CnvOK }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object
@ -424,6 +449,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Int
{ CnvOK }, // any
{ CnvOK }, // int same
{ CnvI2F }, // float
{ CnvOK }, // Bool
{ CnvOK0 }, // PropList only if 0
{ CnvOK0 }, // C4Object only if 0
@ -432,9 +458,22 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ CnvError }, // Ref
{ CnvError }, // PropListRef
},
{ // C4V_Float
{ CnvOK }, // any
{ CnvF2I }, // int
{ CnvOK }, // float same
{ CnvF2I }, // Bool
{ CnvOK0 }, // PropList only if 0
{ CnvOK0 }, // C4Object only if 0
{ CnvOK0 }, // String only if 0
{ CnvOK0 }, // Array only if 0
{ CnvError }, // Ref
{ CnvError }, // PropListRef
},
{ // C4V_Bool
{ CnvOK }, // any
{ CnvOK }, // int might be used
{ CnvI2F }, // float
{ CnvOK }, // Bool same
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -446,6 +485,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_PropList
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList same
{ CnvObject }, // C4Object
@ -457,6 +497,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Object
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvOK }, // PropList
{ CnvOK }, // C4Object same
@ -468,6 +509,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_String
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -479,6 +521,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Array
{ CnvOK }, // any
{ CnvError }, // int NEVER!
{ CnvError }, // float
{ CnvOK }, // Bool
{ CnvError }, // PropList NEVER!
{ CnvError }, // C4Object NEVER!
@ -490,6 +533,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Ref - resolve reference and retry type check
{ CnvDeref }, // any
{ CnvDeref }, // int
{ CnvDeref }, // float
{ CnvDeref }, // Bool
{ CnvDeref }, // PropList
{ CnvDeref }, // C4Object
@ -501,6 +545,7 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
{ // C4V_Ref - resolve reference and retry type check
{ CnvPLR }, // any
{ CnvPLR }, // int
{ CnvPLR }, // float
{ CnvPLR }, // Bool
{ CnvPLR }, // PropList
{ CnvPLR }, // C4Object
@ -513,6 +558,8 @@ C4VCnvFn C4Value::C4ScriptCnvMap[C4V_Last+1][C4V_Last+1] =
#undef CnvOK
#undef CnvOK0
#undef CnvI2F
#undef CnvF2I
#undef CnvError
#undef CnvDeref
#undef CnvPLR
@ -529,6 +576,8 @@ StdStrBuf C4Value::GetDataString()
{
case C4V_Int:
return FormatString("%ld", static_cast<long>(Data.Int));
case C4V_Float:
return FormatString("%f", static_cast<float>(C4Real(Data.Float)));
case C4V_Bool:
return StdStrBuf(Data ? "true" : "false");
case C4V_C4Object:
@ -671,6 +720,12 @@ void C4Value::CompileFunc(StdCompiler *pComp)
Data.Int = iTmp;
break;
case C4V_Float:
{
C4Real val = Data.Float;
pComp->Value(val);
Data.Float = val;
}
// object: save object number instead
case C4V_C4Object: case C4V_PropList:
@ -761,20 +816,25 @@ bool C4Value::operator == (const C4Value& Value2) const
assert(!Data);
return Value2.Type == Type;
case C4V_Int:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return Data == Value2.Data;
default:
return false;
}
case C4V_Bool:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return Data == Value2.Data;
case C4V_Float:
return C4Real(Value2.Data.Float) == static_cast<int>(Data.Int);
default:
return false;
}
case C4V_Float:
switch (Value2.Type)
{
case C4V_Int:
case C4V_Bool:
return C4Real(Data.Float) == static_cast<int>(Data.Int);
case C4V_Float:
return Data.Float == Value2.Data.Float;
default:
return false;
}

View File

@ -21,6 +21,7 @@
#define INC_C4Value
#include "C4Id.h"
#include "C4Real.h"
// class declarations
class C4Value;
@ -32,18 +33,19 @@ class C4ValueArray;
// C4Value type
enum C4V_Type
{
C4V_Any=0, // nil
C4V_Int=1,
C4V_Bool=2,
C4V_PropList=3,
C4V_C4Object=4,
C4V_String=5,
C4V_Array=6,
C4V_Ref=7, // reference to a value (variable)
C4V_PropListRef=8, // reference to an entry in a proplist
C4V_Any, // nil
C4V_Int,
C4V_Float,
C4V_Bool,
C4V_PropList,
C4V_C4Object,
C4V_String,
C4V_Array,
C4V_Ref, // reference to a value (variable)
C4V_PropListRef, // reference to an entry in a proplist
C4V_C4ObjectEnum=9, // enumerated object
C4V_C4DefEnum=10 // enumerated object
C4V_C4ObjectEnum, // enumerated object
C4V_C4DefEnum // enumerated object
};
#define C4V_Last (int) C4V_PropListRef
@ -54,6 +56,7 @@ C4V_Type GetC4VFromID(char C4VID);
union C4V_Data
{
C4Real::StorageType Float;
intptr_t Int;
C4Object * Obj;
C4PropList * PropList;
@ -88,6 +91,8 @@ public:
{ Data.Int = data; AddDataRef(); }
explicit C4Value(int32_t data): NextRef(NULL), FirstRef(NULL), Type(C4V_Int), HasBaseArray(false)
{ Data.Int = data; AddDataRef(); }
explicit C4Value(C4Real data): NextRef(NULL), FirstRef(NULL), Type(C4V_Float), HasBaseArray(false)
{ Data.Float = data; AddDataRef(); }
explicit C4Value(C4Object *pObj): NextRef(NULL), FirstRef(NULL), Type(pObj ? C4V_C4Object : C4V_Any), HasBaseArray(false)
{ Data.Obj = pObj; AddDataRef(); }
explicit C4Value(C4String *pStr): NextRef(NULL), FirstRef(NULL), Type(pStr ? C4V_String : C4V_Any), HasBaseArray(false)
@ -105,6 +110,7 @@ public:
// Checked getters
int32_t getInt() { return ConvertTo(C4V_Int) ? Data.Int : 0; }
C4Real getFloat() { return ConvertTo(C4V_Float) ? Data.Float : C4Real(0); }
bool getBool() { return ConvertTo(C4V_Bool) ? !! Data : 0; }
C4ID getC4ID();
C4Object * getObj() { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
@ -115,6 +121,7 @@ public:
// Unchecked getters
int32_t _getInt() const { return Data.Int; }
C4Real _getFloat() const { return Data.Float; }
bool _getBool() const { return !! Data.Int; }
C4Object *_getObj() const { return Data.Obj; }
C4String *_getStr() const { return Data.Str; }
@ -133,6 +140,8 @@ public:
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
void SetFloat(C4Real f) { C4V_Data d; d.Float = f; Set(d, C4V_Float); }
void SetBool(bool b) { C4V_Data d; d.Int = b; Set(d, C4V_Bool); }
void SetObject(C4Object * Obj) { C4V_Data d; d.Obj = Obj; Set(d, C4V_C4Object); }
@ -153,10 +162,29 @@ public:
bool operator != (const C4Value& Value2) const;
// Change and set Type to int in case it was any before (avoids GuessType())
C4Value & operator += (int32_t by) { GetData().Int += by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator -= (int32_t by) { GetData().Int -= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator *= (int32_t by) { GetData().Int *= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator /= (int32_t by) { GetData().Int /= by; GetRefVal().Type=C4V_Int; return *this; }
#define C4VALUE_ARITHMETIC_OPERATOR(op) \
/* combined arithmetic and assignment op */ \
C4Value &operator op##= (const C4Value &rhs) \
{ \
/* Promote numeric values to float if any operand is float */ \
if (rhs.GetType() == C4V_Float || GetType() == C4V_Float) \
{ \
C4Real lhsf = getFloat(); \
C4Real rhsf = C4Value(rhs).getFloat(); \
SetFloat(lhsf op##= rhsf); \
} \
else \
{ \
GetData().Int op##= rhs.GetData().Int; \
GetRefVal().Type=C4V_Int; \
} \
return *this; \
}
C4VALUE_ARITHMETIC_OPERATOR(+)
C4VALUE_ARITHMETIC_OPERATOR(-)
C4VALUE_ARITHMETIC_OPERATOR(*)
C4VALUE_ARITHMETIC_OPERATOR(/)
#undef C4VALUE_ARITHMETIC_OPERATOR
C4Value & operator %= (int32_t by) { GetData().Int %= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator &= (int32_t by) { GetData().Int &= by; GetRefVal().Type=C4V_Int; return *this; }
C4Value & operator ^= (int32_t by) { GetData().Int ^= by; GetRefVal().Type=C4V_Int; return *this; }
@ -215,7 +243,7 @@ public:
void CompileFunc(StdCompiler *pComp);
static inline bool IsNullableType(C4V_Type Type)
{ return Type == C4V_Int || Type == C4V_Bool; }
{ return Type == C4V_Int || Type == C4V_Float || Type == C4V_Bool; }
protected:
// data
@ -269,6 +297,7 @@ protected:
// converter
inline C4Value C4VInt(int32_t iVal) { C4V_Data d; d.Int = iVal; return C4Value(d, C4V_Int); }
inline C4Value C4VFloat(C4Real f) { return C4Value(f); }
inline C4Value C4VBool(bool fVal) { C4V_Data d; d.Int = fVal; return C4Value(d, C4V_Bool); }
C4Value C4VID(C4ID iVal);
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
@ -288,6 +317,13 @@ template <> struct C4ValueConv<int32_t>
inline static int32_t _FromC4V(C4Value &v) { return v._getInt(); }
inline static C4Value ToC4V(int32_t v) { return C4VInt(v); }
};
template <> struct C4ValueConv<C4Real>
{
inline static C4V_Type Type() { return C4V_Float; }
inline static C4Real FromC4V(C4Value &v) { return v.getFloat(); }
inline static C4Real _FromC4V(C4Value &v) { return v._getFloat(); }
inline static C4Value ToC4V(C4Real v) { return C4VFloat(v); }
};
template <> struct C4ValueConv<bool>
{
inline static C4V_Type Type() { return C4V_Bool; }