OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4PropList.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2004, Peter Wortmann
5  * Copyright (c) 2007, G√ľnther Brammer
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 #include "C4Include.h"
19 #include "script/C4PropList.h"
20 
21 #include "control/C4Record.h"
22 #include "object/C4GameObjects.h"
23 #include "script/C4Aul.h"
24 
25 void C4PropList::AddRef(C4Value *pRef)
26 {
27 #ifdef _DEBUG
28  C4Value * pVal = FirstRef;
29  while (pVal)
30  {
31  assert(pVal != pRef);
32  pVal = pVal->NextRef;
33  }
34 #endif
35  pRef->NextRef = FirstRef;
36  FirstRef = pRef;
37 }
38 
39 void C4PropList::DelRef(const C4Value * pRef, C4Value * pNextRef)
40 {
41  assert(FirstRef);
42  // References to objects never have HasBaseArray set
43  if (pRef == FirstRef)
44  {
45  FirstRef = pNextRef;
46  if (pNextRef) return;
47  }
48  else
49  {
50  C4Value *pPrev = FirstRef;
51  while (pPrev->NextRef != pRef)
52  {
53  pPrev = pPrev->NextRef;
54  assert(pPrev);
55  }
56  pPrev->NextRef = pNextRef;
57  return;
58  }
59  // Only pure script proplists are garbage collected here, host proplists
60  // like definitions and effects have their own memory management.
61  if (Delete()) delete this;
62 }
63 
65 {
66  C4PropList * r = new C4PropListScript(prototype);
67  return r;
68 }
69 
71 {
72  return new C4PropListStatic(prototype, parent, key);
73 }
74 
76 {
77  return PropLists.Get(iNumber);
78 }
79 
81 {
82  if (!pObj) return false;
83  C4PropListNumbered * const * p = PropLists.First();
84  while (p)
85  {
86  if (*p == pObj)
87  return true;
88  p = PropLists.Next(p);
89  }
90  return false;
91 }
92 
93 void C4PropListNumbered::SetEnumerationIndex(int32_t iMaxObjectNumber)
94 {
95  // update object enumeration index now, because calls like OnSynchronized might create objects
96  EnumerationIndex = std::max(EnumerationIndex, iMaxObjectNumber);
97 }
98 
100 {
101  assert(!PropLists.GetSize());
102  EnumerationIndex = 0;
103 }
104 
106 {
107  // unnumber all proplists and put them on the shelve. To be used on remaining objects before a savegame load.
108  assert(ShelvedPropLists.empty());
110  C4PropListNumbered *const* p_next = PropLists.First(), *const* p;
111  while ((p = p_next))
112  {
113  p_next = PropLists.Next(p);
114  C4PropListNumbered *pl = *p;
115  if (pl->Number != -1)
116  {
117  pl->ClearNumber();
118  ShelvedPropLists.push_back(pl);
119  }
120  }
121 }
122 
124 {
125  // re-insert shelved proplists into main list and give them a number
126  for (auto & ShelvedPropList : ShelvedPropLists)
127  ShelvedPropList->AcquireNumber();
128  ShelvedPropLists.clear();
129 }
130 
132 {
133  // cleanup shelve - used in game clear, un unsuccessful section load, etc.
134  ShelvedPropLists.clear();
135 }
136 
138 {
139  // empty all proplists to ensure safe deletion of proplists with circular references
140  // note that this the call to Clear() might delete some prop lists. So it is assumed that
141  // PropLists does not shrink its table as the number of values goes down
142  C4PropListNumbered *const* p_next = PropLists.First(), *const* p;
143  while ((p = p_next))
144  {
145  p_next = PropLists.Next(p);
146  // check *p since it might have been deleted by clearing the previous prop list
147  if (*p) (*p)->Clear();
148  }
149 }
150 
152 {
153 }
154 
156 {
157  // Enumerate object
158  do
160  while (PropLists.Get(Number));
161  // Add to list
162  PropLists.Add(this);
163 }
164 
166 {
167  // Make proplist invisible during denumeration process
168  if (Number != -1)
169  {
170  PropLists.Remove(this);
171  Number = -1;
172  }
173 }
174 
176 {
177  return this;
178 }
179 
181 {
182  int32_t n = Number;
183  pComp->Value(n);
185  C4PropList::CompileFunc(pComp, numbers);
186  if (pComp->isDeserializer())
187  {
188  if (PropLists.Get(n))
189  {
190  pComp->excCorrupt("multiple PropLists with Number %d", n);
191  return;
192  }
193  // Once this proplist has a Number, it has to be in PropLists. See the destructor below.
194  Number = n;
195  PropLists.Add(this);
196  }
197 }
198 
200 {
201  if (Number != -1)
202  PropLists.Remove(this);
203  else
204  Log("removing numbered proplist without number");
205 }
206 
208 {
209  // empty all proplists to ensure safe deletion of proplists with circular references
210  // note that this the call to Clear() might delete some prop lists. So it is assumed that
211  // PropLists does not shrink its table as the number of values goes down
212  // However, some values may be skipped due to table consolidation. Just fix it by iterating over the table until it's empty.
213  C4PropListScript *const* p_next, *const* p;
214  while ((p_next = PropLists.First()))
215  {
216  size_t prev_size = PropLists.GetSize();
217  while ((p = p_next))
218  {
219  p_next = PropLists.Next(p);
220  // check *p since it might have been deleted by clearing the previous prop list
221  if (*p)
222  {
223  C4Value ref(C4VPropList(*p)); // keep a reference because prop list might delete itself within clearing method otherwise
224  (*p)->Clear();
225  }
226  }
227  if (PropLists.GetSize() >= prev_size)
228  {
229  // Looks like there's a rogue C4Value pointer somewhere.
230  // Could just delete the prop list and let ref counting do the job
231  // However, it might be better to keep the dead pointer to find the leak in debug mode
232 #ifdef _DEBUG
233  assert(0);
234 #endif
235  break;
236  }
237  }
238 }
239 
241 {
242  assert(!pComp->isDeserializer());
243  if (Parent)
244  {
245  Parent->RefCompileFunc(pComp, numbers);
247  }
248  if (!ParentKeyName)
249  pComp->excCorrupt("C4PropListStatic::RefCompileFunc without ParentKeyName");
251 }
252 
254 {
255  StdStrBuf r;
256  if (Parent)
257  {
258  r.Take(Parent->GetDataString());
259  r.AppendChar('.');
260  }
261  assert(ParentKeyName);
262  if (ParentKeyName)
264  return r;
265 }
266 
267 const char *C4PropListStatic::GetName() const
268 {
269  const C4String * s = GetPropertyStr(P_Name);
270  if (!s) s = ParentKeyName;
271  if (!s) return "";
272  return s->GetCStr();
273 }
274 
276  prototype(prototype)
277 {
278 #ifdef _DEBUG
279  PropLists.Add(this);
280 #endif
281 }
282 
284 {
285  //thaw self and all owned properties
286  Thaw();
288  //if (s) LogF("Thaw: %s", s->GetDataString().getData());
289  auto prop_names = GetUnsortedProperties(nullptr, ::ScriptEngine.GetPropList());
290  for (auto prop_name : prop_names)
291  {
292  C4Value child_val;
293  GetPropertyByS(prop_name, &child_val);
294  //LogF(" %s=%s", prop_name->GetCStr(), child_val.GetDataString(1).getData());
295  C4PropList *child_proplist = child_val.getPropList();
296  if (child_proplist && child_proplist->IsFrozen())
297  {
298  child_proplist->ThawRecursively();
299  }
300  }
301 }
302 
303 C4PropListStatic *C4PropList::FreezeAndMakeStaticRecursively(std::vector<C4Value>* prop_lists, const C4PropListStatic *parent, C4String * key)
304 {
305  Freeze();
306  // Already static?
307  C4PropListStatic *this_static = IsStatic();
308  if (!this_static)
309  {
310  // Make self static by creating a copy and replacing all references
311  this_static = NewStatic(GetPrototype(), parent, key);
312  this_static->Properties.Swap(&Properties); // grab properties
313  this_static->Status = Status;
314  C4Value holder = C4VPropList(this);
315  while (FirstRef && FirstRef->NextRef)
316  {
317  C4Value *ref = FirstRef;
318  if (ref == &holder) ref = ref->NextRef;
319  ref->SetPropList(this_static);
320  }
321  // store reference
322  if (prop_lists)
323  {
324  prop_lists->push_back(C4VPropList(this_static));
325  }
326  // "this" should be deleted as holder goes out of scope
327  }
328  // Iterate over sorted list of elements to make static
329  // Must iterate over sorted list because the order must be defined, just in case it's a network game
330  // and a non-static child proplist is available through different paths it should still get the same name
331  auto prop_names = this_static->GetSortedLocalProperties(false);
332  for (auto prop_name : prop_names)
333  {
334  C4Value child_val;
335  this_static->GetPropertyByS(prop_name, &child_val);
336  C4PropList *child_proplist = child_val.getPropList();
337  if (child_proplist)
338  {
339  // Avoid infinite recursion: Only freeze into unfrozen children and "true" static children
340  C4PropListStatic *child_static = child_proplist->IsStatic();
341  if (!child_static || (child_static->GetParent() == this_static && child_static->GetParentKeyName() == prop_name))
342  {
343  child_proplist->FreezeAndMakeStaticRecursively(prop_lists, this_static, prop_name);
344  }
345  }
346  }
347  return this_static;
348 }
349 
351 {
352  const C4Property * p = Properties.First();
353  while (p)
354  {
355  const_cast<C4Value &>(p->Value).Denumerate(numbers);
356  p = Properties.Next(p);
357  }
358  prototype.Denumerate(numbers);
360 }
361 
363 {
364  while (FirstRef)
365  {
366  // Manually kill references so DelRef doesn't destroy us again
367  FirstRef->Data = nullptr; FirstRef->Type = C4V_Nil;
368  C4Value *ref = FirstRef;
369  FirstRef = FirstRef->NextRef;
370  ref->NextRef = nullptr;
371  }
372 #ifdef _DEBUG
373  assert(PropLists.Has(this));
374  PropLists.Remove(this);
375 #endif
376  assert(!C4PropListNumbered::CheckPropList(this));
377 }
378 
380 {
381  // every numbered proplist has a unique number and is only identical to itself
382  if (this == &b) return true;
383  if (IsNumbered() || b.IsNumbered()) return false;
384  if (Properties.GetSize() != b.Properties.GetSize()) return false;
385  if (GetDef() != b.GetDef()) return false;
386  const C4Property * p = Properties.First();
387  while (p)
388  {
389  const C4Property & bp = b.Properties.Get(p->Key);
390  if (!bp) return false;
391  if (p->Value != bp.Value) return false;
392  p = Properties.Next(p);
393  }
394  return true;
395 }
396 
398 {
399  bool oldFormat = false;
400  // constant proplists are not serialized to savegames, but recreated from the game data instead
401  assert(!constant);
402  if (pComp->isDeserializer() && pComp->hasNaming())
403  {
404  // backwards compat to savegames and scenarios before 5.5
405  try
406  {
407  pComp->Value(constant);
408  oldFormat = true;
409  }
410  catch (StdCompiler::NotFoundException *pEx)
411  {
412  delete pEx;
413  pComp->Value(mkParAdapt(prototype, numbers));
414  }
415  }
416  else
417  pComp->Value(mkParAdapt(prototype, numbers));
419  pComp->Value(mkParAdapt(Properties, numbers));
420  if (oldFormat)
421  {
422  if (Properties.Has(&::Strings.P[P_Prototype]))
423  {
424  prototype = Properties.Get(&::Strings.P[P_Prototype]).Value;
425  Properties.Remove(&::Strings.P[P_Prototype]);
426  }
427  }
428 }
429 
431 {
432  // clear any cyclic prototype chains
433  // Use prototype.getPropList() instead of GetPrototype() because denumeration might not be completed yet
434  for(C4PropList * it = prototype.getPropList(); it; it = it->prototype.getPropList())
435  if(it == this)
436  {
437  prototype.Set0();
438  }
439 }
440 
441 void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers *rPar)
442 {
443  std::unique_ptr<C4PropList> temp(C4PropList::New()); // exception-safety
444  pComp->Value(mkParAdapt(*temp, rPar));
445  pStruct = temp.release();
446 }
447 
448 template<typename T>
450 {
451  bool fNaming = pComp->hasNaming();
452  if (pComp->isDeserializer())
453  {
454  // Compiling: Empty previous
455  Clear();
456  // Read size (binary only)
457  uint32_t iSize;
458  if (!pComp->hasNaming()) pComp->Value(iSize);
459  // Read new
460  do
461  {
462  // No entries left to read?
463  if (!fNaming && !iSize--)
464  break;
465  // Read entries
466  try
467  {
468  T e;
469  // This could use the same technique StdArrayAdapt uses
470  // instead of hardcoding mkParAdapt here
471  pComp->Value(mkParAdapt(e, numbers));
472  Add(e);
473  }
474  catch (StdCompiler::NotFoundException *pEx)
475  {
476  // No value found: Stop reading loop
477  delete pEx;
478  break;
479  }
480  }
481  while (pComp->Separator(StdCompiler::SEP_SEP));
482  }
483  else
484  {
485  // Write size (binary only)
486  if (!fNaming)
487  {
488  int32_t iSize = GetSize();
489  pComp->Value(iSize);
490  }
491  // Write all entries
492  const T * p = First();
493  while (p)
494  {
495  pComp->Value(mkParAdapt(*const_cast<T *>(p), numbers));
496  p = Next(p);
497  if (p) pComp->Separator(StdCompiler::SEP_SEP);
498  }
499  }
500 }
501 
503 {
504  StdStrBuf s;
505  if (!pComp->isDeserializer())
506  s = Key->GetData();
507  pComp->Value(s);
508  if (pComp->isDeserializer())
509  {
510  if (Key) Key->DecRef();
511  Key = ::Strings.RegString(s);
512  Key->IncRef();
513  }
515  pComp->Value(mkParAdapt(Value, numbers));
516 }
517 
518 void C4PropList::AppendDataString(StdStrBuf * out, const char * delim, int depth, bool ignore_reference_parent) const
519 {
520  StdStrBuf & DataString = *out;
521  if (depth <= 0 && Properties.GetSize())
522  {
523  DataString.Append("...");
524  return;
525  }
526  bool has_elements = false;
527  // Append prototype
528  if (prototype)
529  {
530  DataString.Append("Prototype = ");
531  DataString.Append(prototype.GetDataString(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
532  has_elements = true;
533  }
534  // Append other properties
535  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
536  for (std::list<const C4Property *>::const_iterator p = sorted_props.begin(); p != sorted_props.end(); ++p)
537  {
538  if (has_elements) DataString.Append(delim);
539  DataString.Append((*p)->Key->GetData());
540  DataString.Append(" = ");
541  DataString.Append((*p)->Value.GetDataString(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
542  has_elements = true;
543  }
544 }
545 
546 StdStrBuf C4PropList::ToJSON(int depth, bool ignore_reference_parent) const
547 {
548  if (depth <= 0 && Properties.GetSize())
549  {
550  throw new C4JSONSerializationError("maximum depth reached");
551  }
552  StdStrBuf DataString;
553  DataString = "{";
554  bool has_elements = false;
555  // Append prototype
556  if (prototype)
557  {
558  DataString.Append("Prototype:");
559  DataString.Append(prototype.ToJSON(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
560  has_elements = true;
561  }
562  // Append other properties
563  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
564  for (std::list<const C4Property *>::const_iterator p = sorted_props.begin(); p != sorted_props.end(); ++p)
565  {
566  if (has_elements) DataString.Append(",");
567  DataString.Append(C4Value((*p)->Key).ToJSON());
568  DataString.Append(":");
569  DataString.Append((*p)->Value.ToJSON(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
570  has_elements = true;
571  }
572  DataString.Append("}");
573  return DataString;
574 }
575 
576 std::vector< C4String * > C4PropList::GetSortedLocalProperties(bool add_prototype) const
577 {
578  // return property list without descending into prototype
579  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
580  std::vector< C4String * > result;
581  result.reserve(sorted_props.size() + add_prototype);
582  if (add_prototype) result.push_back(&::Strings.P[P_Prototype]); // implicit prototype for every prop list
583  for (auto p : sorted_props) result.push_back(p->Key);
584  return result;
585 }
586 
587 std::vector< C4String * > C4PropList::GetSortedLocalProperties(const char *prefix, const C4PropList *ignore_overridden) const
588 {
589  // return property list without descending into prototype
590  // ignore properties that have been overridden by proplist given in ignore_overridden or any of its prototypes up to and excluding this
591  std::vector< C4String * > result;
592  for (const C4Property *pp = Properties.First(); pp; pp = Properties.Next(pp))
593  if (pp->Key != &::Strings.P[P_Prototype])
594  if (!prefix || pp->Key->GetData().BeginsWith(prefix))
595  {
596  // Override check
597  const C4PropList *check = ignore_overridden;
598  bool overridden = false;
599  if (check && check != this)
600  {
601  if (check->HasProperty(pp->Key)) { overridden = true; break; }
602  check = check->GetPrototype();
603  }
604  result.push_back(pp->Key);
605  }
606  // Sort
607  std::sort(result.begin(), result.end(), [](const C4String *a, const C4String *b) -> bool
608  {
609  return strcmp(a->GetCStr(), b->GetCStr()) < 0;
610  });
611  return result;
612 }
613 
614 std::vector< C4String * > C4PropList::GetUnsortedProperties(const char *prefix, C4PropList *ignore_parent) const
615 {
616  // Return property list with descending into prototype
617  // But do not include Prototype property
618  std::vector< C4String * > result;
619  const C4PropList *p = this;
620  do
621  {
622  for (const C4Property *pp = p->Properties.First(); pp; pp = p->Properties.Next(pp))
623  if (pp->Key != &::Strings.P[P_Prototype])
624  if (!prefix || pp->Key->GetData().BeginsWith(prefix))
625  result.push_back(pp->Key);
626  p = p->GetPrototype();
627  if (p == ignore_parent) break;
628  } while (p);
629  return result;
630 }
631 
632 std::vector< C4String * > C4PropList::GetSortedProperties(const char *prefix, C4PropList *ignore_parent) const
633 {
634  // Return property list with descending into prototype
635  // But do not include Prototype property
636  std::vector< C4String * > result = GetUnsortedProperties(prefix, ignore_parent);
637  // Sort
638  std::sort(result.begin(), result.end(), [](const C4String *a, const C4String *b) -> bool
639  {
640  return strcmp(a->GetCStr(), b->GetCStr()) < 0;
641  });
642  return result;
643 }
644 
645 const char * C4PropList::GetName() const
646 {
648  if (!s) return "";
649  return s->GetCStr();
650 }
651 
652 void C4PropList::SetName(const char* NewName)
653 {
654  if (!NewName)
656  else
657  {
658  SetProperty(P_Name, C4VString(NewName));
659  }
660 }
661 
662 
664 {
665  if (GetPrototype()) return GetPrototype()->GetObject();
666  return nullptr;
667 }
668 
670 {
671  if (GetPrototype()) return GetPrototype()->GetObject();
672  return nullptr;
673 }
674 
676 {
677  if (GetPrototype()) return GetPrototype()->GetDef();
678  return nullptr;
679 }
680 
681 C4Def const * C4PropList::GetDef() const
682 {
683  if (GetPrototype()) return GetPrototype()->GetDef();
684  return nullptr;
685 }
686 
688 {
689  if (GetPrototype()) return GetPrototype()->GetMapScriptLayer();
690  return nullptr;
691 }
692 
694 {
695  if (GetPrototype()) return GetPrototype()->GetMapScriptMap();
696  return nullptr;
697 }
698 
700 {
701  if (GetPrototype()) return GetPrototype()->GetPropListNumbered();
702  return nullptr;
703 }
704 
706 {
707  if (GetPrototype()) return GetPrototype()->GetEffect();
708  return nullptr;
709 }
710 
711 template<> template<>
712 unsigned int C4Set<C4Property>::Hash<const C4String *>(C4String const * const & e)
713 {
714  assert(e);
715  unsigned int hash = 4, tmp;
716  hash += ((uintptr_t)e) >> 16;
717  tmp = ((((uintptr_t)e) & 0xffff) << 11) ^ hash;
718  hash = (hash << 16) ^ tmp;
719  hash += hash >> 11;
720  hash ^= hash << 3;
721  hash += hash >> 5;
722  hash ^= hash << 4;
723  hash += hash >> 17;
724  hash ^= hash << 25;
725  hash += hash >> 6;
726  return hash;
727 }
728 
729 template<> template<>
730 unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
731 {
732  return Hash<const C4String *>(e);
733 }
734 
735 template<> template<>
736 bool C4Set<C4Property>::Equals<const C4String *>(C4Property const & a, C4String const * const & b)
737 {
738  return a.Key == b;
739 }
740 
741 template<> template<>
742 bool C4Set<C4Property>::Equals<C4String *>(C4Property const & a, C4String * const & b)
743 {
744  return a.Key == b;
745 }
746 
747 template<> template<>
748 unsigned int C4Set<C4Property>::Hash<C4Property>(C4Property const & p)
749 {
750  return C4Set<C4Property>::Hash(p.Key);
751 }
752 
753 bool C4PropList::GetPropertyByS(const C4String * k, C4Value *pResult) const
754 {
755  if (Properties.Has(k))
756  {
757  *pResult = Properties.Get(k).Value;
758  return true;
759  }
760  else if (k == &Strings.P[P_Prototype])
761  {
762  *pResult = prototype;
763  return true;
764  }
765  else if(GetPrototype())
766  return GetPrototype()->GetPropertyByS(k, pResult);
767  else
768  return false;
769 }
770 
772 {
773  C4String * k = &Strings.P[n];
774  if (Properties.Has(k))
775  {
776  return Properties.Get(k).Value.getStr();
777  }
778  if (GetPrototype())
779  {
780  return GetPrototype()->GetPropertyStr(n);
781  }
782  return nullptr;
783 }
784 
786 {
787  C4String * k = &Strings.P[n];
788  if (Properties.Has(k))
789  {
790  return Properties.Get(k).Value.getArray();
791  }
792  if (GetPrototype())
793  {
794  return GetPrototype()->GetPropertyArray(n);
795  }
796  return nullptr;
797 }
798 
800 {
801  assert(k);
802  if (Properties.Has(k))
803  {
804  return Properties.Get(k).Value.getFunction();
805  }
806  if (GetPrototype())
807  {
808  return GetPrototype()->GetFunc(k);
809  }
810  return nullptr;
811 }
812 
813 C4AulFunc * C4PropList::GetFunc(const char * s) const
814 {
815  assert(s);
816  if (s[0] == '~') ++s;
817  C4String * k = Strings.FindString(s);
818  // this string is entirely unused
819  if (!k)
820  return nullptr;
821  return GetFunc(k);
822 }
823 
824 C4Value C4PropList::Call(C4String * k, C4AulParSet *Pars, bool fPassErrors)
825 {
826  if (!Status) return C4Value();
827  C4AulFunc *pFn = GetFunc(k);
828  if (!pFn) return C4Value();
829  return pFn->Exec(this, Pars, fPassErrors);
830 }
831 
832 C4Value C4PropList::Call(const char * s, C4AulParSet *Pars, bool fPassErrors)
833 {
834  if (!Status) return C4Value();
835  assert(s && s[0]);
836  C4AulFunc *pFn = GetFunc(s);
837  if (!pFn)
838  {
839  if (s[0] != '~')
840  {
841  C4AulExecError err(FormatString("Undefined function: %s", s).getData());
842  if (fPassErrors)
843  throw err;
845  }
846  return C4Value();
847  }
848  return pFn->Exec(this, Pars, fPassErrors);
849 }
850 
852 {
853  C4String * k = &Strings.P[n];
854  if (Properties.Has(k))
855  {
856  C4String * v = Properties.Get(k).Value.getStr();
857  if (v >= &Strings.P[0] && v < &Strings.P[P_LAST])
858  return C4PropertyName(v - &Strings.P[0]);
859  return P_LAST;
860  }
861  if (GetPrototype())
862  {
863  return GetPrototype()->GetPropertyP(n);
864  }
865  return P_LAST;
866 }
867 
868 int32_t C4PropList::GetPropertyBool(C4PropertyName n, bool default_val) const
869 {
870  C4String * k = &Strings.P[n];
871  if (Properties.Has(k))
872  {
873  return Properties.Get(k).Value.getBool();
874  }
875  if (GetPrototype())
876  {
877  return GetPrototype()->GetPropertyBool(n, default_val);
878  }
879  return default_val;
880 }
881 
882 int32_t C4PropList::GetPropertyInt(C4PropertyName n, int32_t default_val) const
883 {
884  C4String * k = &Strings.P[n];
885  if (Properties.Has(k))
886  {
887  return Properties.Get(k).Value.getInt();
888  }
889  if (GetPrototype())
890  {
891  return GetPrototype()->GetPropertyInt(n, default_val);
892  }
893  return default_val;
894 }
895 
897 {
898  C4String * k = &Strings.P[n];
899  if (Properties.Has(k))
900  {
901  return Properties.Get(k).Value.getPropList();
902  }
903  if (GetPrototype())
904  {
905  return GetPrototype()->GetPropertyPropList(n);
906  }
907  return nullptr;
908 }
909 
911 {
912  C4ValueArray * a;
913  int i;
914  if (GetPrototype())
915  {
916  a = GetPrototype()->GetProperties();
917  i = a->GetSize();
918  a->SetSize(i + Properties.GetSize());
919  }
920  else
921  {
922  a = new C4ValueArray(Properties.GetSize());
923  i = 0;
924  }
925  const C4Property * p = Properties.First();
926  while (p)
927  {
928  assert(p->Key != nullptr && "Proplist key is nullpointer");
929  (*a)[i++] = C4VString(p->Key);
930  assert(((*a)[i - 1].GetType() == C4V_String) && "Proplist key is non-string");
931  p = Properties.Next(p);
932  }
933  return a;
934 }
935 
937 {
938  const C4Property * p = prev ? Properties.Next(&Properties.Get(prev)) : Properties.First();
939  while (p)
940  {
941  if (p->Value.getFunction())
942  return p->Key;
943  p = Properties.Next(p);
944  }
945  return nullptr;
946 }
947 
949 {
950  assert(!constant);
951  if (k == &Strings.P[P_Prototype])
952  {
953  C4PropList * newpt = to.getPropList();
954  for(C4PropList * it = newpt; it; it = it->GetPrototype())
955  if(it == this)
956  throw C4AulExecError("Trying to create cyclic prototype structure");
957  prototype.SetPropList(newpt);
958  }
959  else if (Properties.Has(k))
960  {
961  Properties.Get(k).Value = to;
962  }
963  else
964  {
965  Properties.Add(C4Property(k, to));
966  }
967 }
968 
970 {
971  if (k == &Strings.P[P_Prototype])
972  prototype.Set0();
973  else
974  Properties.Remove(k);
975 }
976 
977 void C4PropList::Iterator::Init()
978 {
979  iter = properties->begin();
980 }
981 
982 void C4PropList::Iterator::Reserve(size_t additionalAmount)
983 {
984  properties->reserve(properties->size() + additionalAmount);
985 }
986 
987 void C4PropList::Iterator::AddProperty(const C4Property * prop)
988 {
989  std::vector<const C4Property*>::size_type i = 0, len = properties->size();
990  for(;i < len; ++i)
991  {
992  const C4Property *oldProperty = (*properties)[i];
993  if (oldProperty->Key == prop->Key)
994  {
995  (*properties)[i] = prop;
996  return;
997  }
998  }
999  // not already in vector?
1000  properties->push_back(prop);
1001 }
1002 
1004 {
1005  C4PropList::Iterator iter;
1006 
1007  if (GetPrototype())
1008  {
1009  iter = GetPrototype()->begin();
1010  }
1011  else
1012  {
1013  iter.properties = std::make_shared<std::vector<const C4Property*> >();
1014  }
1015  iter.Reserve(Properties.GetSize());
1016 
1017  const C4Property * p = Properties.First();
1018  while (p)
1019  {
1020  iter.AddProperty(p);
1021  p = Properties.Next(p);
1022  }
1023 
1024  iter.Init();
1025  return iter;
1026 }
1027 
1028 
1029 template<> template<>
1030 unsigned int C4Set<C4PropListNumbered *>::Hash<int>(int const & e)
1031 {
1032  unsigned int hash = 4, tmp;
1033  hash += e >> 16;
1034  tmp = ((e & 0xffff) << 11) ^ hash;
1035  hash = (hash << 16) ^ tmp;
1036  hash += hash >> 11;
1037  hash ^= hash << 3;
1038  hash += hash >> 5;
1039  hash ^= hash << 4;
1040  hash += hash >> 17;
1041  hash ^= hash << 25;
1042  hash += hash >> 6;
1043  return hash;
1044 }
1045 
1046 template<> template<>
1047 unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropList *>(C4PropList * const & e)
1048 {
1049  return Hash(e->GetPropListNumbered()->Number);
1050 }
1051 
1052 template<> template<>
1054 {
1055  return Hash(e->Number);
1056 }
1057 
1058 template<> template<>
1059 bool C4Set<C4PropListNumbered *>::Equals<int>(C4PropListNumbered * const & a, int const & b)
1060 {
1061  return a->Number == b;
1062 }
1063 
1064 template<> template<>
1066 {
1067  return a == b;
1068 }
1069 
1070 template<> template<>
1072 {
1073  return C4Set<C4PropListNumbered *>::Hash(static_cast<int>(reinterpret_cast<intptr_t>(e)));
1074 }
1075 
1076 template<> template<>
1078 {
1079  // since script prop lists are only put in the set for reference keeping, just hash by pointer
1080  // but use only some of the more significant bits because
1081  uintptr_t hash = reinterpret_cast<uintptr_t>(e);
1082  return (unsigned int)(hash / 63);
1083 }
virtual void ResetProperty(C4String *k)
Definition: C4PropList.cpp:969
StdStrBuf ToJSON(int depth=10, bool ignore_reference_parent=false) const
Definition: C4PropList.cpp:546
void RemoveCyclicPrototypes()
Definition: C4PropList.cpp:430
C4PropertyName GetPropertyP(C4PropertyName k) const
Definition: C4PropList.cpp:851
C4String P[P_LAST]
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:119
C4Value Value
Definition: C4PropList.h:55
void CompileFunc(class StdCompiler *pComp, class C4ValueNumbers *)
Definition: C4PropList.cpp:449
StdStrBuf GetData() const
Definition: C4StringTable.h:50
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4PropList.cpp:397
virtual bool hasNaming()
Definition: StdCompiler.h:58
C4AulErrorHandler * GetErrorHandler() const
Definition: C4Aul.h:173
void Thaw()
Definition: C4PropList.h:129
std::list< const T * > GetSortedListOfElementPointers() const
C4PropListStatic * FreezeAndMakeStaticRecursively(std::vector< C4Value > *prop_lists, const C4PropListStatic *parent=nullptr, C4String *key=nullptr)
Definition: C4PropList.cpp:303
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
static C4Set< C4PropListScript * > PropLists
Definition: C4PropList.h:254
C4String * getStr() const
Definition: C4Value.h:117
void IncRef()
Definition: C4StringTable.h:27
void excCorrupt(const char *szMessage,...)
Definition: StdCompiler.h:249
T * Add(T const &e)
bool operator==(const C4PropList &b) const
Definition: C4PropList.cpp:379
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
#define b
static void ResetEnumerationIndex()
Definition: C4PropList.cpp:99
C4PropList(C4PropList *prototype=nullptr)
Definition: C4PropList.cpp:275
C4String * FindString(const char *strString) const
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *numbers)
Definition: C4PropList.cpp:180
bool Has(H e) const
static unsigned int Hash(const H &)
C4AulFunc * GetFunc(C4PropertyName k) const
Definition: C4PropList.h:105
void Freeze()
Definition: C4PropList.h:128
static void ClearNumberedPropLists()
Definition: C4PropList.cpp:137
const char * GetCStr() const
Definition: C4StringTable.h:49
C4String * RegString(StdStrBuf String)
friend class C4Value
Definition: C4PropList.h:165
static C4PropList * GetByNumber(int32_t iNumber)
Definition: C4PropList.cpp:75
void SetProperty(C4PropertyName k, const C4Value &to)
Definition: C4PropList.h:120
static std::vector< C4PropListNumbered * > ShelvedPropLists
Definition: C4PropList.h:237
static void SetEnumerationIndex(int32_t iMaxObjectNumber)
Definition: C4PropList.cpp:93
void Set0()
Definition: C4Value.h:336
virtual class C4PropListStatic * IsStatic()
Definition: C4PropList.h:85
static bool CheckPropList(C4PropList *)
Definition: C4PropList.cpp:80
bool getBool() const
Definition: C4Value.h:113
StdStrBuf GetDataString(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:131
#define a
C4String * GetParentKeyName()
Definition: C4PropList.h:271
void Clear()
Definition: C4PropList.h:66
virtual C4Object * GetObject()
Definition: C4PropList.cpp:663
const char * GetName() const override
Definition: C4PropList.cpp:267
virtual C4Def const * GetDef() const
Definition: C4PropList.cpp:681
void AppendChar(char cChar)
Definition: StdBuf.h:588
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4PropList.cpp:502
virtual void Denumerate(C4ValueNumbers *)
Definition: C4PropList.cpp:350
int32_t GetPropertyBool(C4PropertyName n, bool default_val=false) const
Definition: C4PropList.cpp:868
std::vector< C4String * > GetSortedLocalProperties(bool add_prototype=true) const
Definition: C4PropList.cpp:576
T & Get(H e) const
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:251
T const * Next(T const *p) const
unsigned int GetSize() const
C4StringTable Strings
Definition: C4Globals.cpp:42
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
Definition: C4PropList.cpp:753
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:245
static void ClearScriptPropLists()
Definition: C4PropList.cpp:207
Iterator begin()
virtual const char * GetName() const
Definition: C4PropList.cpp:645
static void ClearShelve()
Definition: C4PropList.cpp:131
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:910
C4PropList * GetPrototype() const
Definition: C4PropList.h:81
static void UnshelveNumberedPropLists()
Definition: C4PropList.cpp:123
virtual ~C4PropList()
Definition: C4PropList.cpp:362
void AppendDataString(StdStrBuf *out, const char *delim, int depth=3, bool ignore_reference_parent=false) const
Definition: C4PropList.cpp:518
void Take(char *pnData)
Definition: StdBuf.h:457
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
const char * what() const noexceptoverride
C4String * EnumerateOwnFuncs(C4String *prev=nullptr) const
Definition: C4PropList.cpp:936
std::vector< C4String * > GetSortedProperties(const char *prefix, C4PropList *ignore_parent=nullptr) const
Definition: C4PropList.cpp:632
void RefCompileFunc(StdCompiler *pComp, C4ValueNumbers *numbers) const
Definition: C4PropList.cpp:240
Definition: C4Def.h:98
const C4PropListStatic * Parent
Definition: C4PropList.h:273
void SetSize(int32_t inSize)
C4PropListNumbered(C4PropList *prototype=nullptr)
Definition: C4PropList.cpp:151
C4Value Exec(C4PropList *p=nullptr, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4AulFunc.h:73
void ThawRecursively()
Definition: C4PropList.cpp:283
int32_t Status
Definition: C4PropList.h:168
C4ValueArray * getArray() const
Definition: C4Value.h:118
virtual class C4MapScriptMap * GetMapScriptMap()
Definition: C4PropList.cpp:693
static C4PropListStatic * NewStatic(C4PropList *prototype, const C4PropListStatic *parent, C4String *key)
Definition: C4PropList.cpp:70
void Value(const T &rStruct)
Definition: StdCompiler.h:161
void Remove(H e)
bool IsFrozen() const
Definition: C4PropList.h:131
static void ShelveNumberedPropLists()
Definition: C4PropList.cpp:105
C4PropertyName
int32_t GetSize() const
Definition: C4ValueArray.h:36
C4ValueArray * GetPropertyArray(C4PropertyName n) const
Definition: C4PropList.cpp:785
virtual C4Effect * GetEffect()
Definition: C4PropList.cpp:705
virtual void OnError(const char *msg)=0
int32_t getInt() const
Definition: C4Value.h:112
virtual bool isDeserializer()
Definition: StdCompiler.h:53
bool HasProperty(C4String *k) const
Definition: C4PropList.h:118
virtual class C4MapScriptLayer * GetMapScriptLayer()
Definition: C4PropList.cpp:687
C4String * Key
Definition: C4PropList.h:54
virtual bool Delete()
Definition: C4PropList.h:90
bool Log(const char *szMessage)
Definition: C4Log.cpp:192
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:882
C4PropListNumbered * GetPropListNumbered() override
Definition: C4PropList.cpp:175
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:458
StdStrBuf ToJSON(int depth=10, const class C4PropListStatic *ignore_reference_parent=nullptr) const
Definition: C4Value.cpp:189
virtual void SetPropertyByS(C4String *k, const C4Value &to)
Definition: C4PropList.cpp:948
void SetPropList(C4PropList *PropList)
Definition: C4Value.h:141
virtual bool IsNumbered() const
Definition: C4PropList.h:88
static C4Set< C4PropListNumbered * > PropLists
Definition: C4PropList.h:236
T const * First() const
std::vector< C4String * > GetUnsortedProperties(const char *prefix, C4PropList *ignore_parent=nullptr) const
Definition: C4PropList.cpp:614
static int32_t EnumerationIndex
Definition: C4PropList.h:238
void DecRef()
Definition: C4StringTable.h:28
virtual C4PropListNumbered * GetPropListNumbered()
Definition: C4PropList.cpp:699
~C4PropListNumbered() override
Definition: C4PropList.cpp:199
C4String * GetPropertyStr(C4PropertyName k) const
Definition: C4PropList.cpp:771
#define s
C4PropList * GetPropertyPropList(C4PropertyName k) const
Definition: C4PropList.cpp:896
C4AulFunc * getFunction() const
Definition: C4Value.h:119
C4RefCntPointer< C4String > ParentKeyName
Definition: C4PropList.h:274
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers *rPar)
Definition: C4PropList.cpp:441
const C4PropListStatic * GetParent() const
Definition: C4PropList.h:270
static C4PropList * New(C4PropList *prototype=nullptr)
Definition: C4PropList.cpp:64
int iSize
Definition: TstC4NetIO.cpp:32
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:110
StdStrBuf GetDataString() const
Definition: C4PropList.cpp:253
C4PropList * getPropList() const
Definition: C4Value.h:116
virtual void SetName(const char *NewName=nullptr)
Definition: C4PropList.cpp:652