OpenClonk
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 "object/C4ObjectPtr.h"
20 #include "script/C4StringTable.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  const char* what() const noexcept override { return msg.c_str(); }
70 };
71 
72 class C4Value
73 {
74 public:
75 
76  C4Value() { Data = nullptr; }
77 
78  C4Value(const C4Value &nValue) : Data(nValue.Data), Type(nValue.Type)
79  { AddDataRef(); }
80  C4Value(C4Value && nValue) noexcept;
81 
82  explicit C4Value(bool data): Type(C4V_Bool)
83  { Data.Int = data; }
84  explicit C4Value(int data): Type(C4V_Int)
85  { Data.Int = data; }
86  explicit C4Value(long data): 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): Type(pStr ? C4V_String : C4V_Nil)
93  { Data.Str = pStr; AddDataRef(); }
94  explicit C4Value(const char * s): Type(s ? C4V_String : C4V_Nil)
95  { Data.Str = s ? ::Strings.RegString(s) : nullptr; AddDataRef(); }
96  explicit C4Value(const StdStrBuf & s): Type(s.isNull() ? C4V_Nil : C4V_String)
97  { Data.Str = s.isNull() ? nullptr: ::Strings.RegString(s); AddDataRef(); }
98  explicit C4Value(C4ValueArray *pArray): Type(pArray ? C4V_Array : C4V_Nil)
99  { Data.Array = pArray; AddDataRef(); }
100  explicit C4Value(C4AulFunc * pFn): Type(pFn ? C4V_Function : C4V_Nil)
101  { Data.Fn = pFn; AddDataRef(); }
102  explicit C4Value(C4PropList *p): 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); }
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 : false; }
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 : nullptr; } // 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  // data type
220  C4V_Type Type{C4V_Nil};
221 
222  void Set(C4V_Data nData, C4V_Type nType);
223 
224  void AddDataRef();
225  void DelDataRef(C4V_Data Data, C4V_Type Type);
226 
227  bool FnCnvObject() const;
228  bool FnCnvDef() const;
229  bool FnCnvEffect() const;
230  void LogDeletedObjectWarning(C4PropList *);
231 
232  // Prevent unintended type conversions
233  template<typename T> explicit C4Value(T);
234 
235  friend class C4PropList;
236 };
237 
238 // converter
239 inline C4Value C4VInt(int32_t i) { return C4Value(i); }
240 inline C4Value C4VBool(bool b) { return C4Value(b); }
241 C4Value C4VObj(C4Object *pObj);
242 inline C4Value C4VPropList(C4PropList * p) { return C4Value(p); }
243 inline C4Value C4VString(C4String *pStr) { return C4Value(pStr); }
244 inline C4Value C4VString(StdStrBuf strString) { return C4Value(strString); }
245 inline C4Value C4VString(const char *strString) { return C4Value(strString); }
246 inline C4Value C4VArray(C4ValueArray *pArray) { return C4Value(pArray); }
247 inline C4Value C4VFunction(C4AulFunc * pFn) { return C4Value(pFn); }
248 
249 extern const C4Value C4VNull;
250 
251 // C4Values can contain data structures that have to maintain their
252 // identity across a save/load. During serialization, these get a number
254 {
255 public:
256  C4ValueNumbers() = default;
257  uint32_t GetNumberForValue(C4Value * v);
258  const C4Value & GetValue(uint32_t);
259  void Denumerate();
260  void CompileFunc(StdCompiler *);
261  void CompileValue(StdCompiler *, C4Value *);
262 private:
263  std::list<C4Value *> ValuesToSave;
264  std::vector<C4Value> LoadedValues;
265  std::map<void *, uint32_t> ValueNumbers;
266 };
267 
268 /* These are by far the most often called C4Value functions.
269  They also often do redundant checks the compiler should be able to optimize away
270  in common situations because the Type of the new value is known. In any case,
271  inlining them does speed up the script engine on at least one artificial benchmark. */
272 
273 #include "script/C4ValueArray.h"
274 #include "script/C4PropList.h"
275 #include "script/C4AulFunc.h"
276 
277 ALWAYS_INLINE void C4Value::AddDataRef()
278 {
279  assert(Type < C4V_Any);
280  assert(Type != C4V_Nil || !Data);
281  switch (Type)
282  {
283  case C4V_PropList:
284 #ifdef _DEBUG
285  assert(C4PropList::PropLists.Has(Data.PropList));
286  if (!Data.PropList->Status)
287  {
288  LogDeletedObjectWarning(Data.PropList);
289  }
290 #endif
291  Data.PropList->AddRef(this);
292  break;
293  case C4V_String: Data.Str->IncRef(); break;
294  case C4V_Array: Data.Array->IncRef(); break;
295  case C4V_Function: Data.Fn->IncRef(); break;
296  default: break;
297  }
298 }
299 
300 ALWAYS_INLINE void C4Value::DelDataRef(C4V_Data Data, C4V_Type Type)
301 {
302  assert(Type < C4V_Any);
303  assert(Type != C4V_Nil || !Data);
304  // clean up
305  switch (Type)
306  {
307  case C4V_PropList: Data.PropList->DelRef(this); break;
308  case C4V_String: Data.Str->DecRef(); break;
309  case C4V_Array: Data.Array->DecRef(); break;
310  case C4V_Function: Data.Fn->DecRef(); break;
311  default: break;
312  }
313 }
314 
315 ALWAYS_INLINE void C4Value::Set(C4V_Data nData, C4V_Type nType)
316 {
317  // Do not add this to the same linked list twice.
318  if (Data == nData && Type >= C4V_FirstPointer) return;
319 
320  C4V_Data oData = Data;
321  C4V_Type oType = Type;
322 
323  // change
324  Data = nData;
325  Type = nData || IsNullableType(nType) ? nType : C4V_Nil;
326 
327  // hold new data & clean up old
328  AddDataRef();
329  DelDataRef(oData, oType);
330 }
331 
333 {
334  C4V_Data oData = Data;
335  C4V_Type oType = Type;
336 
337  // change
338  Data = nullptr;
339  Type = C4V_Nil;
340 
341  // clean up (save even if Data was 0 before)
342  DelDataRef(oData, oType);
343 }
344 
346  Data(nValue.Data), Type(nValue.Type)
347 {
348  if (Type == C4V_PropList)
349  {
350  Data.PropList->AddRef(this);
351  Data.PropList->DelRef(&nValue);
352  }
353  nValue.Type = C4V_Nil; nValue.Data = nullptr;
354 }
355 
356 #endif
357 
#define s
C4StringTable Strings
Definition: C4Globals.cpp:42
#define b
C4Value C4VFunction(C4AulFunc *pFn)
Definition: C4Value.h:247
const char * GetC4VName(const C4V_Type Type)
Definition: C4Value.cpp:32
C4Value C4VBool(bool b)
Definition: C4Value.h:240
C4Value C4VArray(C4ValueArray *pArray)
Definition: C4Value.h:246
#define C4V_FirstPointer
Definition: C4Value.h:45
C4V_Type
Definition: C4Value.h:24
@ C4V_Function
Definition: C4Value.h:31
@ C4V_Int
Definition: C4Value.h:26
@ C4V_PropList
Definition: C4Value.h:28
@ C4V_Object
Definition: C4Value.h:38
@ C4V_Any
Definition: C4Value.h:37
@ C4V_Bool
Definition: C4Value.h:27
@ C4V_Def
Definition: C4Value.h:39
@ C4V_C4ObjectEnum
Definition: C4Value.h:34
@ C4V_Effect
Definition: C4Value.h:40
@ C4V_Array
Definition: C4Value.h:30
@ C4V_Nil
Definition: C4Value.h:25
@ C4V_String
Definition: C4Value.h:29
@ C4V_Enum
Definition: C4Value.h:33
C4Value C4VInt(int32_t i)
Definition: C4Value.h:239
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:242
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:243
C4Value C4VObj(C4Object *pObj)
Definition: C4Value.cpp:88
const C4Value C4VNull
Definition: C4Value.cpp:30
#define ALWAYS_INLINE
Definition: C4Def.h:99
C4JSONSerializationError(const std::string &msg)
Definition: C4Value.h:68
const char * what() const noexcept override
Definition: C4Value.h:69
int32_t Status
Definition: C4PropList.h:173
friend class C4Value
Definition: C4PropList.h:170
void DecRef()
Definition: C4StringTable.h:28
void IncRef()
Definition: C4StringTable.h:27
C4String * RegString(StdStrBuf String)
C4Value & operator--()
Definition: C4Value.h:156
C4Value(const C4Value &nValue)
Definition: C4Value.h:78
C4Value(C4ValueArray *pArray)
Definition: C4Value.h:98
C4ValueArray * getArray() const
Definition: C4Value.h:118
C4Value(long data)
Definition: C4Value.h:86
C4Value(C4PropList *p)
Definition: C4Value.h:102
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
Definition: C4Value.h:189
void SetPropList(C4PropList *PropList)
Definition: C4Value.h:141
static constexpr bool IsNullableType(C4V_Type Type)
Definition: C4Value.h:212
C4V_Type GetTypeEx() const
Definition: C4Value.cpp:623
C4Object * getObj() const
Definition: C4Value.cpp:68
int32_t getInt() const
Definition: C4Value.h:112
C4Value(Nillable< T > v)
Definition: C4Value.h:105
StdStrBuf ToJSON(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:189
C4Value(const char *s)
Definition: C4Value.h:94
C4Value(C4String *pStr)
Definition: C4Value.h:92
C4Value(C4ObjectPtr p)
Definition: C4Value.h:104
bool operator!() const
Definition: C4Value.h:131
C4Def * _getDef() const
Definition: C4Value.cpp:83
C4V_Data GetData() const
Definition: C4Value.h:160
StdStrBuf GetDataString(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:131
C4PropList * _getPropList() const
Definition: C4Value.h:129
C4Value & operator++()
Definition: C4Value.h:154
C4Value(int data)
Definition: C4Value.h:84
~C4Value()
Definition: C4Value.h:109
C4String * getStr() const
Definition: C4Value.h:117
static bool WarnAboutConversion(C4V_Type Type, C4V_Type vtToType)
Definition: C4Value.cpp:111
void SetBool(bool b)
Definition: C4Value.h:137
bool _getBool() const
Definition: C4Value.h:123
C4V_Type GetType() const
Definition: C4Value.h:161
ALWAYS_INLINE bool CheckParConversion(C4V_Type vtToType) const
Definition: C4Value.h:171
void Set0()
Definition: C4Value.h:332
C4AulFunc * _getFunction() const
Definition: C4Value.h:128
C4Value()
Definition: C4Value.h:76
bool operator!=(const C4Value &Value2) const
Definition: C4Value.cpp:618
C4Value(C4AulFunc *pFn)
Definition: C4Value.h:100
C4Value(bool data)
Definition: C4Value.h:82
C4Value(const StdStrBuf &s)
Definition: C4Value.h:96
int32_t _getInt() const
Definition: C4Value.h:122
void SetArray(C4ValueArray *Array)
Definition: C4Value.h:139
void SetInt(int32_t i)
Definition: C4Value.h:136
C4ValueArray * _getArray() const
Definition: C4Value.h:127
C4Value & operator+=(int32_t by)
Definition: C4Value.h:153
C4Value & operator=(const C4Value &nValue)
Definition: C4Value.h:107
bool operator==(const C4Value &Value2) const
Definition: C4Value.cpp:570
bool IsIdenticalTo(const C4Value &cmp) const
Definition: C4Value.h:149
void Set(const C4Value &nValue)
Definition: C4Value.h:134
C4AulFunc * getFunction() const
Definition: C4Value.h:119
C4String * _getStr() const
Definition: C4Value.h:126
void SetObjectEnum(int i)
Definition: C4Value.h:142
bool getBool() const
Definition: C4Value.h:113
C4PropList * getPropList() const
Definition: C4Value.h:116
void SetString(C4String *Str)
Definition: C4Value.h:138
C4Def * getDef() const
Definition: C4Value.cpp:78
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4Value.cpp:300
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:251
const char * GetTypeName() const
Definition: C4Value.h:164
C4Object * _getObj() const
Definition: C4Value.cpp:73
void SetFunction(C4AulFunc *Fn)
Definition: C4Value.h:140
void Denumerate()
Definition: C4Value.cpp:281
void CompileValue(StdCompiler *, C4Value *)
Definition: C4Value.cpp:456
C4ValueNumbers()=default
void CompileFunc(StdCompiler *)
Definition: C4Value.cpp:492
const C4Value & GetValue(uint32_t)
Definition: C4Value.cpp:243
uint32_t GetNumberForValue(C4Value *v)
Definition: C4Value.cpp:287
intptr_t Int
Definition: C4Value.h:52
C4String * Str
Definition: C4Value.h:55
C4PropList * PropList
Definition: C4Value.h:54
C4V_Data & operator=(void *p)
Definition: C4Value.h:61
C4AulFunc * Fn
Definition: C4Value.h:57
void * Ptr
Definition: C4Value.h:53
C4ValueArray * Array
Definition: C4Value.h:56