2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2001, 2004 Sven Eberhardt
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2001-2002, 2006, 2010 Peter Wortmann
|
|
|
|
* Copyright (c) 2006-2010 Günther Brammer
|
|
|
|
* Copyright (c) 2009 Nicolas Hake
|
|
|
|
* Copyright (c) 2010 Armin Burgmeier
|
2009-05-08 13:28:41 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
#ifndef INC_C4Value
|
|
|
|
#define INC_C4Value
|
|
|
|
|
|
|
|
#include "C4Id.h"
|
2010-10-26 01:05:20 +00:00
|
|
|
#include "C4StringTable.h"
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// C4Value type
|
|
|
|
enum C4V_Type
|
|
|
|
{
|
2010-03-23 22:56:59 +00:00
|
|
|
C4V_Any=0, // nil
|
|
|
|
C4V_Int=1,
|
|
|
|
C4V_Bool=2,
|
2009-04-12 12:04:28 +00:00
|
|
|
C4V_PropList=3,
|
2010-03-23 22:56:59 +00:00
|
|
|
C4V_C4Object=4,
|
|
|
|
C4V_String=5,
|
|
|
|
C4V_Array=6,
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-03-21 23:40:03 +00:00
|
|
|
C4V_C4ObjectEnum=9, // enumerated object
|
2011-03-27 16:14:41 +00:00
|
|
|
C4V_C4DefEnum=10, // enumerated definition
|
|
|
|
C4V_Enum=11 // enumerated array or proplist
|
2009-05-08 13:28:41 +00:00
|
|
|
};
|
2011-03-31 20:26:07 +00:00
|
|
|
// last C4V_Type that doesn't vanish in Denumerate
|
|
|
|
#define C4V_Last ((int) C4V_Array)
|
|
|
|
// first C4V_Type that is a pointer
|
|
|
|
#define C4V_FirstPointer C4V_PropList
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
const char* GetC4VName(const C4V_Type Type);
|
|
|
|
|
2010-03-28 17:58:21 +00:00
|
|
|
union C4V_Data
|
|
|
|
{
|
2010-02-28 00:42:57 +00:00
|
|
|
intptr_t Int;
|
2009-05-08 13:28:41 +00:00
|
|
|
C4Object * Obj;
|
2009-05-19 22:12:11 +00:00
|
|
|
C4PropList * PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
C4String * Str;
|
|
|
|
C4ValueArray * Array;
|
|
|
|
// cheat a little - assume that all members have the same length
|
2010-04-08 00:47:45 +00:00
|
|
|
operator void * () { return Obj; }
|
|
|
|
operator const void * () const { return Obj; }
|
|
|
|
C4V_Data &operator = (void *p) { Obj = reinterpret_cast<C4Object *>(p); return *this; }
|
2009-05-08 13:28:41 +00:00
|
|
|
};
|
2010-03-23 22:56:59 +00:00
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
// converter function, used in converter table
|
|
|
|
struct C4VCnvFn
|
2010-03-28 17:58:21 +00:00
|
|
|
{
|
2010-09-20 17:49:00 +00:00
|
|
|
enum { CnvOK, CnvOK0, CnvError, CnvObject } Function;
|
2009-05-08 13:28:41 +00:00
|
|
|
bool Warn;
|
2010-03-28 17:58:21 +00:00
|
|
|
};
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
class C4Value
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2010-09-15 19:23:02 +00:00
|
|
|
C4Value() : Type(C4V_Any), NextRef(NULL) { Data.Obj = 0; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-09-15 19:23:02 +00:00
|
|
|
C4Value(const C4Value &nValue) : Data(nValue.Data), Type(nValue.Type), NextRef(NULL)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ AddDataRef(); }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(bool data): Type(C4V_Bool), NextRef(NULL)
|
2010-04-08 00:47:45 +00:00
|
|
|
{ Data.Int = data; }
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(int32_t data): Type(C4V_Int), NextRef(NULL)
|
2010-04-08 00:47:45 +00:00
|
|
|
{ Data.Int = data; }
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(C4Object *pObj): Type(pObj ? C4V_C4Object : C4V_Any), NextRef(NULL)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ Data.Obj = pObj; AddDataRef(); }
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(C4String *pStr): Type(pStr ? C4V_String : C4V_Any), NextRef(NULL)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ Data.Str = pStr; AddDataRef(); }
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(C4ValueArray *pArray): Type(pArray ? C4V_Array : C4V_Any), NextRef(NULL)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ Data.Array = pArray; AddDataRef(); }
|
2010-09-15 19:23:02 +00:00
|
|
|
explicit C4Value(C4PropList *p): Type(p ? C4V_PropList : C4V_Any), NextRef(NULL)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ Data.PropList = p; AddDataRef(); }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-04-08 00:47:45 +00:00
|
|
|
C4Value& operator = (const C4Value& nValue) { Set(nValue); return *this; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-04-08 00:47:45 +00:00
|
|
|
~C4Value() { DelDataRef(Data, Type, NextRef); }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Checked getters
|
2010-09-20 17:49:00 +00:00
|
|
|
int32_t getInt() const { return ConvertTo(C4V_Int) ? Data.Int : 0; }
|
|
|
|
bool getBool() const { return ConvertTo(C4V_Bool) ? !! Data : 0; }
|
|
|
|
C4ID getC4ID() const;
|
|
|
|
C4Object * getObj() const { return ConvertTo(C4V_C4Object) ? Data.Obj : NULL; }
|
|
|
|
C4PropList * getPropList() const { return ConvertTo(C4V_PropList) ? Data.PropList : NULL; }
|
|
|
|
C4String * getStr() const { return ConvertTo(C4V_String) ? Data.Str : NULL; }
|
|
|
|
C4ValueArray * getArray() const { return ConvertTo(C4V_Array) ? Data.Array : NULL; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Unchecked getters
|
|
|
|
int32_t _getInt() const { return Data.Int; }
|
|
|
|
bool _getBool() const { return !! Data.Int; }
|
|
|
|
C4Object *_getObj() const { return Data.Obj; }
|
|
|
|
C4String *_getStr() const { return Data.Str; }
|
|
|
|
C4ValueArray *_getArray() const { return Data.Array; }
|
2009-05-19 22:12:11 +00:00
|
|
|
C4PropList *_getPropList() const { return Data.PropList; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Template versions
|
|
|
|
|
|
|
|
bool operator ! () const { return !GetData(); }
|
2009-07-20 21:45:31 +00:00
|
|
|
inline operator const void* () const { return GetData()?this:0; } // To allow use of C4Value in conditions
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2011-04-10 00:00:27 +00:00
|
|
|
void Set(const C4Value &nValue) { Set(nValue.Data, nValue.Type); }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void SetInt(int i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
|
|
|
|
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); }
|
|
|
|
void SetString(C4String * Str) { C4V_Data d; d.Str = Str; Set(d, C4V_String); }
|
|
|
|
void SetArray(C4ValueArray * Array) { C4V_Data d; d.Array = Array; Set(d, C4V_Array); }
|
2009-05-19 22:12:11 +00:00
|
|
|
void SetPropList(C4PropList * PropList) { C4V_Data d; d.PropList = PropList; Set(d, C4V_PropList); }
|
2009-05-08 13:28:41 +00:00
|
|
|
void Set0();
|
|
|
|
|
|
|
|
bool operator == (const C4Value& Value2) const;
|
|
|
|
bool operator != (const C4Value& Value2) const;
|
|
|
|
|
|
|
|
// Change and set Type to int in case it was any before (avoids GuessType())
|
2010-04-08 00:47:45 +00:00
|
|
|
C4Value & operator += (int32_t by) { Data.Int += by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator -= (int32_t by) { Data.Int -= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator *= (int32_t by) { Data.Int *= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator /= (int32_t by) { Data.Int /= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator %= (int32_t by) { Data.Int %= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator &= (int32_t by) { Data.Int &= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator ^= (int32_t by) { Data.Int ^= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator |= (int32_t by) { Data.Int |= by; Type=C4V_Int; return *this; }
|
|
|
|
C4Value & operator ++ () { Data.Int++; Type=C4V_Int; return *this; }
|
|
|
|
C4Value operator ++ (int) { C4Value old = *this; ++(*this); return old; }
|
|
|
|
C4Value & operator -- () { Data.Int--; Type=C4V_Int; return *this; }
|
|
|
|
C4Value operator -- (int) { C4Value old = *this; --(*this); return old; }
|
|
|
|
|
|
|
|
// getters
|
|
|
|
C4V_Data GetData() const { return Data; }
|
|
|
|
C4V_Type GetType() const { return Type; }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
const char *GetTypeName() const { return GetC4VName(GetType()); }
|
|
|
|
const char *GetTypeInfo();
|
|
|
|
|
2011-03-26 22:59:35 +00:00
|
|
|
void Denumerate(C4ValueNumbers *);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-09-20 17:49:00 +00:00
|
|
|
StdStrBuf GetDataString() const;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-09-20 17:49:00 +00:00
|
|
|
inline bool ConvertTo(C4V_Type vtToType) const // convert to dest type
|
2010-03-28 17:58:21 +00:00
|
|
|
{
|
2010-09-20 17:49:00 +00:00
|
|
|
switch (C4ScriptCnvMap[Type][vtToType].Function)
|
|
|
|
{
|
|
|
|
case C4VCnvFn::CnvOK: return true;
|
|
|
|
case C4VCnvFn::CnvOK0: return !*this;
|
|
|
|
case C4VCnvFn::CnvError: return false;
|
|
|
|
case C4VCnvFn::CnvObject: return FnCnvObject();
|
|
|
|
}
|
2010-09-29 21:19:43 +00:00
|
|
|
assert(!"C4Value::ConvertTo: Invalid conversion function specified");
|
|
|
|
return false;
|
2010-03-28 17:58:21 +00:00
|
|
|
}
|
2010-03-06 19:49:29 +00:00
|
|
|
inline static bool WarnAboutConversion(C4V_Type vtFromType, C4V_Type vtToType)
|
2010-03-28 17:58:21 +00:00
|
|
|
{
|
2010-03-06 19:49:29 +00:00
|
|
|
return C4ScriptCnvMap[vtFromType][vtToType].Warn;
|
2010-03-28 17:58:21 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Compilation
|
2011-03-26 22:59:35 +00:00
|
|
|
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-12 20:44:09 +00:00
|
|
|
static inline bool IsNullableType(C4V_Type Type)
|
2010-03-28 17:58:21 +00:00
|
|
|
{ return Type == C4V_Int || Type == C4V_Bool; }
|
2009-08-12 20:44:09 +00:00
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
protected:
|
|
|
|
// data
|
|
|
|
C4V_Data Data;
|
|
|
|
|
2010-04-08 00:47:45 +00:00
|
|
|
// proplist reference list
|
|
|
|
C4Value * NextRef;
|
2009-07-20 21:04:29 +00:00
|
|
|
|
2010-12-06 18:04:32 +00:00
|
|
|
// data type
|
|
|
|
C4V_Type Type;
|
|
|
|
|
2010-04-08 00:47:45 +00:00
|
|
|
C4Value(C4V_Data nData, C4V_Type nType): Data(nData), NextRef(NULL)
|
|
|
|
{ Type = (nData || IsNullableType(nType) ? nType : C4V_Any); AddDataRef(); }
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2010-04-08 00:47:45 +00:00
|
|
|
void Set(C4V_Data nData, C4V_Type nType);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void AddDataRef();
|
2010-04-08 00:47:45 +00:00
|
|
|
void DelDataRef(C4V_Data Data, C4V_Type Type, C4Value *pNextRef);
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
static C4VCnvFn C4ScriptCnvMap[C4V_Last+1][C4V_Last+1];
|
2010-09-20 17:49:00 +00:00
|
|
|
bool FnCnvObject() const;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-05-19 22:12:11 +00:00
|
|
|
friend class C4PropList;
|
2009-05-08 13:28:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// converter
|
2011-03-02 22:42:34 +00:00
|
|
|
inline C4Value C4VInt(int32_t i) { return C4Value(i); }
|
|
|
|
inline C4Value C4VBool(bool b) { return C4Value(b); }
|
2009-05-08 13:28:41 +00:00
|
|
|
inline C4Value C4VObj(C4Object *pObj) { return C4Value(pObj); }
|
2009-05-19 22:12:11 +00:00
|
|
|
inline C4Value C4VPropList(C4PropList * p) { return C4Value(p); }
|
2009-05-08 13:28:41 +00:00
|
|
|
inline C4Value C4VString(C4String *pStr) { return C4Value(pStr); }
|
|
|
|
inline C4Value C4VArray(C4ValueArray *pArray) { return C4Value(pArray); }
|
|
|
|
|
|
|
|
C4Value C4VString(StdStrBuf strString);
|
|
|
|
C4Value C4VString(const char *strString);
|
|
|
|
|
2011-03-02 22:42:34 +00:00
|
|
|
#define C4VFalse C4VBool(false)
|
|
|
|
#define C4VTrue C4VBool(true)
|
2009-08-12 20:44:09 +00:00
|
|
|
|
2011-03-02 23:57:38 +00:00
|
|
|
extern const C4Value C4VNull;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2011-03-27 16:14:41 +00:00
|
|
|
// C4Values can contain data structures that have to maintain their
|
|
|
|
// identity across a save/load. During serialization, these get a number
|
2011-03-26 22:59:35 +00:00
|
|
|
class C4ValueNumbers
|
|
|
|
{
|
2011-03-27 16:14:41 +00:00
|
|
|
public:
|
|
|
|
C4ValueNumbers() {}
|
|
|
|
uint32_t GetNumberForValue(C4Value * v);
|
|
|
|
const C4Value & GetValue(uint32_t);
|
|
|
|
void Denumerate();
|
|
|
|
void CompileFunc(StdCompiler *);
|
|
|
|
void CompileValue(StdCompiler *, C4Value *);
|
|
|
|
private:
|
|
|
|
std::list<C4Value *> ValuesToSave;
|
|
|
|
std::vector<C4Value> LoadedValues;
|
|
|
|
std::map<void *, uint32_t> ValueNumbers;
|
2011-03-26 22:59:35 +00:00
|
|
|
};
|
|
|
|
|
2010-10-26 01:05:20 +00:00
|
|
|
/* These are by far the most often called C4Value functions.
|
|
|
|
They also often do redundant checks the compiler should be able to optimize away
|
|
|
|
in common situations because the Type of the new value is known. In any case,
|
|
|
|
inlining them does speed up the script engine on at least one artificial benchmark. */
|
|
|
|
|
2010-12-27 16:05:35 +00:00
|
|
|
#include "C4ValueArray.h"
|
2010-10-26 01:05:20 +00:00
|
|
|
#include "C4PropList.h"
|
|
|
|
|
|
|
|
ALWAYS_INLINE void C4Value::AddDataRef()
|
|
|
|
{
|
|
|
|
assert(Type != C4V_Any || !Data);
|
|
|
|
switch (Type)
|
|
|
|
{
|
|
|
|
case C4V_Array: Data.Array->IncRef(); break;
|
|
|
|
case C4V_String: Data.Str->IncRef(); break;
|
|
|
|
case C4V_C4Object:
|
|
|
|
#ifdef _DEBUG
|
2011-02-06 00:59:49 +00:00
|
|
|
// check if the object actually exists
|
|
|
|
if (!C4PropListNumbered::CheckPropList(Data.PropList))
|
|
|
|
{ LogF("Warning: using wild object ptr %p!", static_cast<void*>(Data.Obj)); }
|
2011-02-06 21:30:31 +00:00
|
|
|
#endif
|
|
|
|
case C4V_PropList:
|
|
|
|
#ifdef _DEBUG
|
|
|
|
assert(C4PropList::PropLists.Has(Data.PropList));
|
2010-10-26 01:05:20 +00:00
|
|
|
if (!Data.PropList->Status)
|
2011-04-13 13:38:49 +00:00
|
|
|
{
|
|
|
|
LogF("Warning: using ptr on deleted object %p (%s)!", static_cast<void*>(Data.PropList), Data.PropList->GetName());
|
|
|
|
AulExec.LogCallStack();
|
|
|
|
}
|
2010-10-26 01:05:20 +00:00
|
|
|
#endif
|
|
|
|
Data.PropList->AddRef(this);
|
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ALWAYS_INLINE void C4Value::DelDataRef(C4V_Data Data, C4V_Type Type, C4Value *pNextRef)
|
|
|
|
{
|
|
|
|
// clean up
|
|
|
|
switch (Type)
|
|
|
|
{
|
|
|
|
case C4V_C4Object: case C4V_PropList: Data.PropList->DelRef(this, pNextRef); break;
|
|
|
|
case C4V_Array: Data.Array->DecRef(); break;
|
|
|
|
case C4V_String: Data.Str->DecRef(); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ALWAYS_INLINE void C4Value::Set(C4V_Data nData, C4V_Type nType)
|
|
|
|
{
|
|
|
|
assert(nType != C4V_Any || !nData);
|
|
|
|
// Do not add this to the same linked list twice.
|
2011-03-31 20:26:07 +00:00
|
|
|
if (Data == nData && Type >= C4V_FirstPointer) return;
|
2010-10-26 01:05:20 +00:00
|
|
|
|
|
|
|
C4V_Data oData = Data;
|
|
|
|
C4V_Type oType = Type;
|
|
|
|
C4Value * oNextRef = NextRef;
|
|
|
|
|
|
|
|
// change
|
|
|
|
Data = nData;
|
|
|
|
Type = nData || IsNullableType(nType) ? nType : C4V_Any;
|
|
|
|
|
|
|
|
// hold new data & clean up old
|
|
|
|
AddDataRef();
|
|
|
|
DelDataRef(oData, oType, oNextRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
ALWAYS_INLINE void C4Value::Set0()
|
|
|
|
{
|
|
|
|
C4V_Data oData = Data;
|
|
|
|
C4V_Type oType = Type;
|
|
|
|
|
|
|
|
// change
|
|
|
|
Data.Obj = 0;
|
|
|
|
Type = C4V_Any;
|
|
|
|
|
|
|
|
// clean up (save even if Data was 0 before)
|
|
|
|
DelDataRef(oData, oType, NextRef);
|
|
|
|
}
|
|
|
|
|
2009-05-08 13:28:41 +00:00
|
|
|
#endif
|
|
|
|
|