OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Value.h
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 #ifndef INC_C4Value
17 #define INC_C4Value
18 
19 #include "script/C4StringTable.h"
20 #include "object/C4ObjectPtr.h"
21 
22 // C4Value type
24 {
32 
33  C4V_Enum=8, // enumerated array or proplist
34  C4V_C4ObjectEnum=9, // enumerated object
35 
36  // for typechecks
41 };
42 // last C4V_Type that doesn't vanish in Denumerate
43 #define C4V_Last ((int) C4V_Array)
44 // a C4V_Type >= C4V_FirstPointer and <= C4V_Last is a pointer
45 #define C4V_FirstPointer C4V_PropList
46 
47 const char* GetC4VName(const C4V_Type Type);
48 template<typename T> class Nillable;
49 
50 union C4V_Data
51 {
52  intptr_t Int;
53  void * Ptr;
58  // cheat a little - assume that all members have the same length
59  operator void * () { return Ptr; }
60  operator const void * () const { return Ptr; }
61  C4V_Data &operator = (void *p) { assert(!p); Ptr = p; return *this; }
62 };
63 
64 class C4JSONSerializationError : public std::exception
65 {
66  std::string msg;
67 public:
68  C4JSONSerializationError(const std::string& msg) : msg(msg) {}
69  virtual const char* what() const noexcept override { return msg.c_str(); }
70 };
71 
72 class C4Value
73 {
74 public:
75 
76  C4Value() : NextRef(nullptr), Type(C4V_Nil) { Data = 0; }
77 
78  C4Value(const C4Value &nValue) : Data(nValue.Data), NextRef(nullptr), Type(nValue.Type)
79  { AddDataRef(); }
80  C4Value(C4Value && nValue) noexcept;
81 
82  explicit C4Value(bool data): NextRef(nullptr), Type(C4V_Bool)
83  { Data.Int = data; }
84  explicit C4Value(int data): NextRef(nullptr), Type(C4V_Int)
85  { Data.Int = data; }
86  explicit C4Value(long data): NextRef(nullptr), Type(C4V_Int)
87  { Data.Int = int32_t(data); }
88  explicit C4Value(C4PropListStatic *p);
89  explicit C4Value(C4Def *p);
90  explicit C4Value(C4Object *pObj);
91  explicit C4Value(C4Effect *p);
92  explicit C4Value(C4String *pStr): NextRef(nullptr), Type(pStr ? C4V_String : C4V_Nil)
93  { Data.Str = pStr; AddDataRef(); }
94  explicit C4Value(const char * s): NextRef(nullptr), Type(s ? C4V_String : C4V_Nil)
95  { Data.Str = s ? ::Strings.RegString(s) : nullptr; AddDataRef(); }
96  explicit C4Value(const StdStrBuf & s): NextRef(nullptr), Type(s.isNull() ? C4V_Nil : C4V_String)
97  { Data.Str = s.isNull() ? nullptr: ::Strings.RegString(s); AddDataRef(); }
98  explicit C4Value(C4ValueArray *pArray): NextRef(nullptr), Type(pArray ? C4V_Array : C4V_Nil)
99  { Data.Array = pArray; AddDataRef(); }
100  explicit C4Value(C4AulFunc * pFn): NextRef(nullptr), Type(pFn ? C4V_Function : C4V_Nil)
101  { Data.Fn = pFn; AddDataRef(); }
102  explicit C4Value(C4PropList *p): NextRef(nullptr), Type(p ? C4V_PropList : C4V_Nil)
103  { Data.PropList = p; AddDataRef(); }
104  C4Value(C4ObjectPtr p): C4Value(p.operator C4Object *()) {}
105  template<typename T> C4Value(Nillable<T> v): C4Value(v.IsNil() ? C4Value() : C4Value(v.operator T())) {}
106 
107  C4Value& operator = (const C4Value& nValue) { Set(nValue); return *this; }
108 
109  ~C4Value() { DelDataRef(Data, Type, NextRef); }
110 
111  // Checked getters
112  int32_t getInt() const { return CheckConversion(C4V_Int) ? Data.Int : 0; }
113  bool getBool() const { return CheckConversion(C4V_Bool) ? !! Data : 0; }
114  C4Object * getObj() const;
115  C4Def * getDef() const;
116  C4PropList * getPropList() const { return CheckConversion(C4V_PropList) ? Data.PropList : nullptr; }
117  C4String * getStr() const { return CheckConversion(C4V_String) ? Data.Str : nullptr; }
118  C4ValueArray * getArray() const { return CheckConversion(C4V_Array) ? Data.Array : nullptr; }
119  C4AulFunc * getFunction() const { return CheckConversion(C4V_Function) ? Data.Fn : nullptr; }
120 
121  // Unchecked getters
122  int32_t _getInt() const { return Data.Int; }
123  bool _getBool() const { return !! Data.Int; }
124  C4Object *_getObj() const;
125  C4Def *_getDef() const;
126  C4String *_getStr() const { return Data.Str; }
127  C4ValueArray *_getArray() const { return Data.Array; }
128  C4AulFunc *_getFunction() const { return Data.Fn; }
129  C4PropList *_getPropList() const { return Data.PropList; }
130 
131  bool operator ! () const { return !GetData(); }
132  inline operator const void* () const { return GetData() ? this : 0; } // To allow use of C4Value in conditions
133 
134  void Set(const C4Value &nValue) { Set(nValue.Data, nValue.Type); }
135 
136  void SetInt(int32_t i) { C4V_Data d; d.Int = i; Set(d, C4V_Int); }
137  void SetBool(bool b) { C4V_Data d; d.Int = b; Set(d, C4V_Bool); }
138  void SetString(C4String * Str) { C4V_Data d; d.Str = Str; Set(d, C4V_String); }
139  void SetArray(C4ValueArray * Array) { C4V_Data d; d.Array = Array; Set(d, C4V_Array); }
140  void SetFunction(C4AulFunc * Fn) { C4V_Data d; d.Fn = Fn; Set(d, C4V_Function); }
141  void SetPropList(C4PropList * PropList) { C4V_Data d; d.PropList = PropList; Set(d, C4V_PropList); }
142  void SetObjectEnum(int i) { C4V_Data d; d.Int = i; Set(d, C4V_C4ObjectEnum); }
143  void Set0();
144 
145  bool operator == (const C4Value& Value2) const;
146  bool operator != (const C4Value& Value2) const;
147 
148  // Identical comparison
149  bool IsIdenticalTo(const C4Value &cmp) const { return GetType()==cmp.GetType() && GetData()==cmp.GetData(); }
150 
151  // Change and set Type to int in case it was nil or bool before
152  // Use with care: These don't handle int32_t overflow
153  C4Value & operator += (int32_t by) { Data.Int += by; Type=C4V_Int; return *this; }
154  C4Value & operator ++ () { Data.Int++; Type=C4V_Int; return *this; }
155  C4Value operator ++ (int) { C4Value old = *this; ++(*this); return old; }
156  C4Value & operator -- () { Data.Int--; Type=C4V_Int; return *this; }
157  C4Value operator -- (int) { C4Value old = *this; --(*this); return old; }
158 
159  // getters
160  C4V_Data GetData() const { return Data; }
161  C4V_Type GetType() const { return Type; }
162  C4V_Type GetTypeEx() const; // Return type including types derived from prop list types (such as C4V_Def)
163 
164  const char *GetTypeName() const { return GetC4VName(GetType()); }
165 
166  void Denumerate(C4ValueNumbers *);
167 
168  StdStrBuf GetDataString(int depth = 10, const class C4PropListStatic *ignore_reference_parent = nullptr) const;
169  StdStrBuf ToJSON(int depth = 10, const class C4PropListStatic *ignore_reference_parent = nullptr) const;
170 
171  ALWAYS_INLINE bool CheckParConversion(C4V_Type vtToType) const // convert to dest type
172  {
173  switch (vtToType)
174  {
175  case C4V_Nil: return Type == C4V_Nil || (Type == C4V_Int && !*this);
176  case C4V_Int: return Type == C4V_Int || Type == C4V_Nil || Type == C4V_Bool;
177  case C4V_Bool: return true;
178  case C4V_PropList: return Type == C4V_PropList || Type == C4V_Nil || (Type == C4V_Int && !*this);
179  case C4V_String: return Type == C4V_String || Type == C4V_Nil || (Type == C4V_Int && !*this);
180  case C4V_Array: return Type == C4V_Array || Type == C4V_Nil || (Type == C4V_Int && !*this);
181  case C4V_Function: return Type == C4V_Function || Type == C4V_Nil || (Type == C4V_Int && !*this);
182  case C4V_Any: return true;
183  case C4V_Object: return (Type == C4V_PropList && FnCnvObject()) || Type == C4V_Nil || (Type == C4V_Int && !*this);
184  case C4V_Def: return (Type == C4V_PropList && FnCnvDef()) || Type == C4V_Nil || (Type == C4V_Int && !*this);
185  case C4V_Effect: return (Type == C4V_PropList && FnCnvEffect()) || Type == C4V_Nil || (Type == C4V_Int && !*this);
186  default: assert(!"C4Value::CheckParConversion: impossible conversion target"); return false;
187  }
188  }
189  ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const // convert to dest type
190  {
191  switch (vtToType)
192  {
193  case C4V_Nil: return Type == C4V_Nil;
194  case C4V_Int: return Type == C4V_Nil || Type == C4V_Int || Type == C4V_Bool;
195  case C4V_Bool: return true;
196  case C4V_PropList: return Type == C4V_PropList;
197  case C4V_String: return Type == C4V_String;
198  case C4V_Array: return Type == C4V_Array;
199  case C4V_Function: return Type == C4V_Function;
200  case C4V_Any: return true;
201  case C4V_Object: return Type == C4V_PropList && FnCnvObject();
202  case C4V_Def: return Type == C4V_PropList && FnCnvDef();
203  case C4V_Effect: return Type == C4V_PropList && FnCnvEffect();
204  default: assert(!"C4Value::CheckConversion: impossible conversion target"); return false;
205  }
206  }
207  static bool WarnAboutConversion(C4V_Type Type, C4V_Type vtToType);
208 
209  // Compilation
210  void CompileFunc(StdCompiler *pComp, C4ValueNumbers *);
211 
212  static inline constexpr bool IsNullableType(C4V_Type Type)
213  { return Type == C4V_Int || Type == C4V_Bool; }
214 
215 private:
216  // data
217  C4V_Data Data;
218 
219  // proplist reference list
220  C4Value * NextRef;
221 
222  // data type
223  C4V_Type Type;
224 
225  void Set(C4V_Data nData, C4V_Type nType);
226 
227  void AddDataRef();
228  void DelDataRef(C4V_Data Data, C4V_Type Type, C4Value *pNextRef);
229 
230  bool FnCnvObject() const;
231  bool FnCnvDef() const;
232  bool FnCnvEffect() const;
233  void LogDeletedObjectWarning(C4PropList *);
234 
235  // Prevent unintended type conversions
236  template<typename T> explicit C4Value(T);
237 
238  friend class C4PropList;
239 };
240 
241 // converter
242 inline C4Value C4VInt(int32_t i) { return C4Value(i); }
243 inline C4Value C4VBool(bool b) { return C4Value(b); }
244 C4Value C4VObj(C4Object *pObj);
245 inline C4Value C4VPropList(C4PropList * p) { return C4Value(p); }
246 inline C4Value C4VString(C4String *pStr) { return C4Value(pStr); }
247 inline C4Value C4VString(StdStrBuf strString) { return C4Value(strString); }
248 inline C4Value C4VString(const char *strString) { return C4Value(strString); }
249 inline C4Value C4VArray(C4ValueArray *pArray) { return C4Value(pArray); }
250 inline C4Value C4VFunction(C4AulFunc * pFn) { return C4Value(pFn); }
251 
252 extern const C4Value C4VNull;
253 
254 // C4Values can contain data structures that have to maintain their
255 // identity across a save/load. During serialization, these get a number
257 {
258 public:
260  uint32_t GetNumberForValue(C4Value * v);
261  const C4Value & GetValue(uint32_t);
262  void Denumerate();
263  void CompileFunc(StdCompiler *);
264  void CompileValue(StdCompiler *, C4Value *);
265 private:
266  std::list<C4Value *> ValuesToSave;
267  std::vector<C4Value> LoadedValues;
268  std::map<void *, uint32_t> ValueNumbers;
269 };
270 
271 /* These are by far the most often called C4Value functions.
272  They also often do redundant checks the compiler should be able to optimize away
273  in common situations because the Type of the new value is known. In any case,
274  inlining them does speed up the script engine on at least one artificial benchmark. */
275 
276 #include "script/C4ValueArray.h"
277 #include "script/C4PropList.h"
278 #include "script/C4AulFunc.h"
279 
280 ALWAYS_INLINE void C4Value::AddDataRef()
281 {
282  assert(Type < C4V_Any);
283  assert(Type != C4V_Nil || !Data);
284  switch (Type)
285  {
286  case C4V_PropList:
287 #ifdef _DEBUG
288  assert(C4PropList::PropLists.Has(Data.PropList));
289  if (!Data.PropList->Status)
290  {
291  LogDeletedObjectWarning(Data.PropList);
292  }
293 #endif
294  Data.PropList->AddRef(this);
295  break;
296  case C4V_String: Data.Str->IncRef(); break;
297  case C4V_Array: Data.Array->IncRef(); break;
298  case C4V_Function: Data.Fn->IncRef(); break;
299  default: break;
300  }
301 }
302 
303 ALWAYS_INLINE void C4Value::DelDataRef(C4V_Data Data, C4V_Type Type, C4Value *pNextRef)
304 {
305  assert(Type < C4V_Any);
306  assert(Type != C4V_Nil || !Data);
307  // clean up
308  switch (Type)
309  {
310  case C4V_PropList: Data.PropList->DelRef(this, pNextRef); break;
311  case C4V_String: Data.Str->DecRef(); break;
312  case C4V_Array: Data.Array->DecRef(); break;
313  case C4V_Function: Data.Fn->DecRef(); break;
314  default: break;
315  }
316 }
317 
318 ALWAYS_INLINE void C4Value::Set(C4V_Data nData, C4V_Type nType)
319 {
320  // Do not add this to the same linked list twice.
321  if (Data == nData && Type >= C4V_FirstPointer) return;
322 
323  C4V_Data oData = Data;
324  C4V_Type oType = Type;
325  C4Value * oNextRef = NextRef;
326 
327  // change
328  Data = nData;
329  Type = nData || IsNullableType(nType) ? nType : C4V_Nil;
330 
331  // hold new data & clean up old
332  AddDataRef();
333  DelDataRef(oData, oType, oNextRef);
334 }
335 
337 {
338  C4V_Data oData = Data;
339  C4V_Type oType = Type;
340 
341  // change
342  Data = 0;
343  Type = C4V_Nil;
344 
345  // clean up (save even if Data was 0 before)
346  DelDataRef(oData, oType, NextRef);
347 }
348 
350  Data(nValue.Data), NextRef(nullptr), Type(nValue.Type)
351 {
352  if (Type == C4V_PropList)
353  {
354  Data.PropList->AddRef(this);
355  Data.PropList->DelRef(&nValue, nValue.NextRef);
356  }
357  nValue.Type = C4V_Nil; nValue.Data = 0; nValue.NextRef = nullptr;
358 }
359 
360 #endif
361 
void Denumerate()
Definition: C4Value.cpp:283
C4V_Type
Definition: C4Value.h:23
C4Value & operator=(const C4Value &nValue)
Definition: C4Value.h:107
C4String * getStr() const
Definition: C4Value.h:117
void IncRef()
Definition: C4StringTable.h:27
#define b
bool _getBool() const
Definition: C4Value.h:123
C4Value(long data)
Definition: C4Value.h:86
C4String * RegString(StdStrBuf String)
friend class C4Value
Definition: C4PropList.h:167
C4Value C4VInt(int32_t i)
Definition: C4Value.h:242
C4AulFunc * Fn
Definition: C4Value.h:57
C4V_Data & operator=(void *p)
Definition: C4Value.h:61
C4V_Type GetTypeEx() const
Definition: C4Value.cpp:625
C4String * _getStr() const
Definition: C4Value.h:126
void Set0()
Definition: C4Value.h:336
void SetBool(bool b)
Definition: C4Value.h:137
C4String * Str
Definition: C4Value.h:55
bool operator!() const
Definition: C4Value.h:131
bool getBool() const
Definition: C4Value.h:113
StdStrBuf GetDataString(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:133
void SetObjectEnum(int i)
Definition: C4Value.h:142
void Set(const C4Value &nValue)
Definition: C4Value.h:134
virtual const char * what() const noexceptoverride
Definition: C4Value.h:69
C4Value()
Definition: C4Value.h:76
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:90
C4Value(int data)
Definition: C4Value.h:84
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
Definition: C4Value.h:189
void SetString(C4String *Str)
Definition: C4Value.h:138
C4ValueArray * _getArray() const
Definition: C4Value.h:127
void CompileFunc(StdCompiler *)
Definition: C4Value.cpp:494
C4JSONSerializationError(const std::string &msg)
Definition: C4Value.h:68
bool operator!=(const C4Value &Value2) const
Definition: C4Value.cpp:620
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:253
uint32_t GetNumberForValue(C4Value *v)
Definition: C4Value.cpp:289
C4V_Type GetType() const
Definition: C4Value.h:161
C4Value & operator--()
Definition: C4Value.h:156
intptr_t Int
Definition: C4Value.h:52
C4StringTable Strings
Definition: C4Globals.cpp:42
const char * GetTypeName() const
Definition: C4Value.h:164
C4Object * _getObj() const
Definition: C4Value.cpp:75
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:245
C4Value & operator++()
Definition: C4Value.h:154
void CompileValue(StdCompiler *, C4Value *)
Definition: C4Value.cpp:458
static bool WarnAboutConversion(C4V_Type Type, C4V_Type vtToType)
Definition: C4Value.cpp:113
const C4Value C4VNull
Definition: C4Value.cpp:32
C4Def * _getDef() const
Definition: C4Value.cpp:85
void * Ptr
Definition: C4Value.h:53
int32_t _getInt() const
Definition: C4Value.h:122
C4Value(C4ValueArray *pArray)
Definition: C4Value.h:98
Definition: C4Def.h:100
ALWAYS_INLINE bool CheckParConversion(C4V_Type vtToType) const
Definition: C4Value.h:171
#define C4V_FirstPointer
Definition: C4Value.h:45
void SetArray(C4ValueArray *Array)
Definition: C4Value.h:139
int32_t Status
Definition: C4PropList.h:170
C4ValueArray * getArray() const
Definition: C4Value.h:118
C4Value C4VArray(C4ValueArray *pArray)
Definition: C4Value.h:249
C4Value(const StdStrBuf &s)
Definition: C4Value.h:96
void SetInt(int32_t i)
Definition: C4Value.h:136
#define ALWAYS_INLINE
int32_t getInt() const
Definition: C4Value.h:112
C4Value C4VBool(bool b)
Definition: C4Value.h:243
static constexpr bool IsNullableType(C4V_Type Type)
Definition: C4Value.h:212
void SetFunction(C4AulFunc *Fn)
Definition: C4Value.h:140
C4Value(Nillable< T > v)
Definition: C4Value.h:105
C4Value(C4String *pStr)
Definition: C4Value.h:92
const char * GetC4VName(const C4V_Type Type)
Definition: C4Value.cpp:34
C4AulFunc * _getFunction() const
Definition: C4Value.h:128
bool isNull() const
Definition: StdBuf.h:449
C4Value(const char *s)
Definition: C4Value.h:94
C4Value(C4AulFunc *pFn)
Definition: C4Value.h:100
C4Value(C4ObjectPtr p)
Definition: C4Value.h:104
C4Value(C4PropList *p)
Definition: C4Value.h:102
C4Def * getDef() const
Definition: C4Value.cpp:80
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
~C4Value()
Definition: C4Value.h:109
C4ValueArray * Array
Definition: C4Value.h:56
StdStrBuf ToJSON(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:191
C4Value & operator+=(int32_t by)
Definition: C4Value.h:153
C4V_Data GetData() const
Definition: C4Value.h:160
C4Value C4VFunction(C4AulFunc *pFn)
Definition: C4Value.h:250
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4Value.cpp:302
bool IsIdenticalTo(const C4Value &cmp) const
Definition: C4Value.h:149
void SetPropList(C4PropList *PropList)
Definition: C4Value.h:141
C4Value(const C4Value &nValue)
Definition: C4Value.h:78
const C4Value & GetValue(uint32_t)
Definition: C4Value.cpp:245
void DecRef()
Definition: C4StringTable.h:28
C4PropList * _getPropList() const
Definition: C4Value.h:129
bool operator==(const C4Value &Value2) const
Definition: C4Value.cpp:572
#define s
C4AulFunc * getFunction() const
Definition: C4Value.h:119
C4Object * getObj() const
Definition: C4Value.cpp:70
C4PropList * PropList
Definition: C4Value.h:54
C4PropList * getPropList() const
Definition: C4Value.h:116