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  struct sort_cmp {
635  bool operator() (const C4String *a, const C4String *b) const
636  {
637  return strcmp(a->GetCStr(), b->GetCStr()) < 0;
638  }
639  };
640  // Return property list with descending into prototype
641  // But do not include Prototype property
642  std::vector< C4String * > result = GetUnsortedProperties(prefix, ignore_parent);
643  // Sort and remove duplicates
644  std::set< C4String *, sort_cmp > result_set(result.begin(), result.end());
645  result.assign(result_set.begin(), result_set.end());
646  return result;
647 }
648 
649 const char * C4PropList::GetName() const
650 {
652  if (!s) return "";
653  return s->GetCStr();
654 }
655 
656 void C4PropList::SetName(const char* NewName)
657 {
658  if (!NewName)
660  else
661  {
662  SetProperty(P_Name, C4VString(NewName));
663  }
664 }
665 
666 
668 {
669  if (GetPrototype()) return GetPrototype()->GetObject();
670  return nullptr;
671 }
672 
674 {
675  if (GetPrototype()) return GetPrototype()->GetObject();
676  return nullptr;
677 }
678 
680 {
681  if (GetPrototype()) return GetPrototype()->GetDef();
682  return nullptr;
683 }
684 
685 C4Def const * C4PropList::GetDef() const
686 {
687  if (GetPrototype()) return GetPrototype()->GetDef();
688  return nullptr;
689 }
690 
692 {
693  if (GetPrototype()) return GetPrototype()->GetMapScriptLayer();
694  return nullptr;
695 }
696 
698 {
699  if (GetPrototype()) return GetPrototype()->GetMapScriptMap();
700  return nullptr;
701 }
702 
704 {
705  if (GetPrototype()) return GetPrototype()->GetPropListNumbered();
706  return nullptr;
707 }
708 
710 {
711  if (GetPrototype()) return GetPrototype()->GetEffect();
712  return nullptr;
713 }
714 
715 template<> template<>
716 unsigned int C4Set<C4Property>::Hash<const C4String *>(C4String const * const & e)
717 {
718  assert(e);
719  unsigned int hash = 4, tmp;
720  hash += ((uintptr_t)e) >> 16;
721  tmp = ((((uintptr_t)e) & 0xffff) << 11) ^ hash;
722  hash = (hash << 16) ^ tmp;
723  hash += hash >> 11;
724  hash ^= hash << 3;
725  hash += hash >> 5;
726  hash ^= hash << 4;
727  hash += hash >> 17;
728  hash ^= hash << 25;
729  hash += hash >> 6;
730  return hash;
731 }
732 
733 template<> template<>
734 unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
735 {
736  return Hash<const C4String *>(e);
737 }
738 
739 template<> template<>
740 bool C4Set<C4Property>::Equals<const C4String *>(C4Property const & a, C4String const * const & b)
741 {
742  return a.Key == b;
743 }
744 
745 template<> template<>
746 bool C4Set<C4Property>::Equals<C4String *>(C4Property const & a, C4String * const & b)
747 {
748  return a.Key == b;
749 }
750 
751 template<> template<>
752 unsigned int C4Set<C4Property>::Hash<C4Property>(C4Property const & p)
753 {
754  return C4Set<C4Property>::Hash(p.Key);
755 }
756 
757 bool C4PropList::GetPropertyByS(const C4String * k, C4Value *pResult) const
758 {
759  if (Properties.Has(k))
760  {
761  *pResult = Properties.Get(k).Value;
762  return true;
763  }
764  else if (k == &Strings.P[P_Prototype])
765  {
766  *pResult = prototype;
767  return true;
768  }
769  else if(GetPrototype())
770  return GetPrototype()->GetPropertyByS(k, pResult);
771  else
772  return false;
773 }
774 
776 {
777  C4String * k = &Strings.P[n];
778  if (Properties.Has(k))
779  {
780  return Properties.Get(k).Value.getStr();
781  }
782  if (GetPrototype())
783  {
784  return GetPrototype()->GetPropertyStr(n);
785  }
786  return nullptr;
787 }
788 
790 {
791  C4String * k = &Strings.P[n];
792  if (Properties.Has(k))
793  {
794  return Properties.Get(k).Value.getArray();
795  }
796  if (GetPrototype())
797  {
798  return GetPrototype()->GetPropertyArray(n);
799  }
800  return nullptr;
801 }
802 
804 {
805  assert(k);
806  if (Properties.Has(k))
807  {
808  return Properties.Get(k).Value.getFunction();
809  }
810  if (GetPrototype())
811  {
812  return GetPrototype()->GetFunc(k);
813  }
814  return nullptr;
815 }
816 
817 C4AulFunc * C4PropList::GetFunc(const char * s) const
818 {
819  assert(s);
820  if (s[0] == '~') ++s;
821  C4String * k = Strings.FindString(s);
822  // this string is entirely unused
823  if (!k)
824  return nullptr;
825  return GetFunc(k);
826 }
827 
828 C4Value C4PropList::Call(C4String * k, C4AulParSet *Pars, bool fPassErrors)
829 {
830  if (!Status) return C4Value();
831  C4AulFunc *pFn = GetFunc(k);
832  if (!pFn) return C4Value();
833  return pFn->Exec(this, Pars, fPassErrors);
834 }
835 
836 C4Value C4PropList::Call(const char * s, C4AulParSet *Pars, bool fPassErrors)
837 {
838  if (!Status) return C4Value();
839  assert(s && s[0]);
840  C4AulFunc *pFn = GetFunc(s);
841  if (!pFn)
842  {
843  if (s[0] != '~')
844  {
845  C4AulExecError err(FormatString("Undefined function: %s", s).getData());
846  if (fPassErrors)
847  throw err;
849  }
850  return C4Value();
851  }
852  return pFn->Exec(this, Pars, fPassErrors);
853 }
854 
856 {
857  C4String * k = &Strings.P[n];
858  if (Properties.Has(k))
859  {
860  C4String * v = Properties.Get(k).Value.getStr();
861  if (v >= &Strings.P[0] && v < &Strings.P[P_LAST])
862  return C4PropertyName(v - &Strings.P[0]);
863  return P_LAST;
864  }
865  if (GetPrototype())
866  {
867  return GetPrototype()->GetPropertyP(n);
868  }
869  return P_LAST;
870 }
871 
872 int32_t C4PropList::GetPropertyBool(C4PropertyName n, bool default_val) const
873 {
874  C4String * k = &Strings.P[n];
875  if (Properties.Has(k))
876  {
877  return Properties.Get(k).Value.getBool();
878  }
879  if (GetPrototype())
880  {
881  return GetPrototype()->GetPropertyBool(n, default_val);
882  }
883  return default_val;
884 }
885 
886 int32_t C4PropList::GetPropertyInt(C4PropertyName n, int32_t default_val) const
887 {
888  C4String * k = &Strings.P[n];
889  if (Properties.Has(k))
890  {
891  return Properties.Get(k).Value.getInt();
892  }
893  if (GetPrototype())
894  {
895  return GetPrototype()->GetPropertyInt(n, default_val);
896  }
897  return default_val;
898 }
899 
901 {
902  C4String * k = &Strings.P[n];
903  if (Properties.Has(k))
904  {
905  return Properties.Get(k).Value.getPropList();
906  }
907  if (GetPrototype())
908  {
909  return GetPrototype()->GetPropertyPropList(n);
910  }
911  return nullptr;
912 }
913 
915 {
916  C4ValueArray * a;
917  int i;
918  if (GetPrototype())
919  {
920  a = GetPrototype()->GetProperties();
921  i = a->GetSize();
922  a->SetSize(i + Properties.GetSize());
923  }
924  else
925  {
926  a = new C4ValueArray(Properties.GetSize());
927  i = 0;
928  }
929  const C4Property * p = Properties.First();
930  while (p)
931  {
932  assert(p->Key != nullptr && "Proplist key is nullpointer");
933  (*a)[i++] = C4VString(p->Key);
934  assert(((*a)[i - 1].GetType() == C4V_String) && "Proplist key is non-string");
935  p = Properties.Next(p);
936  }
937  return a;
938 }
939 
941 {
942  const C4Property * p = prev ? Properties.Next(&Properties.Get(prev)) : Properties.First();
943  while (p)
944  {
945  if (p->Value.getFunction())
946  return p->Key;
947  p = Properties.Next(p);
948  }
949  return nullptr;
950 }
951 
953 {
954  assert(!constant);
955  if (k == &Strings.P[P_Prototype])
956  {
957  C4PropList * newpt = to.getPropList();
958  for(C4PropList * it = newpt; it; it = it->GetPrototype())
959  if(it == this)
960  throw C4AulExecError("Trying to create cyclic prototype structure");
961  prototype.SetPropList(newpt);
962  }
963  else if (Properties.Has(k))
964  {
965  Properties.Get(k).Value = to;
966  }
967  else
968  {
969  Properties.Add(C4Property(k, to));
970  }
971 }
972 
974 {
975  if (k == &Strings.P[P_Prototype])
976  prototype.Set0();
977  else
978  Properties.Remove(k);
979 }
980 
981 void C4PropList::Iterator::Init()
982 {
983  iter = properties->begin();
984 }
985 
986 void C4PropList::Iterator::Reserve(size_t additionalAmount)
987 {
988  properties->reserve(properties->size() + additionalAmount);
989 }
990 
991 void C4PropList::Iterator::AddProperty(const C4Property * prop)
992 {
993  std::vector<const C4Property*>::size_type i = 0, len = properties->size();
994  for(;i < len; ++i)
995  {
996  const C4Property *oldProperty = (*properties)[i];
997  if (oldProperty->Key == prop->Key)
998  {
999  (*properties)[i] = prop;
1000  return;
1001  }
1002  }
1003  // not already in vector?
1004  properties->push_back(prop);
1005 }
1006 
1008 {
1009  C4PropList::Iterator iter;
1010 
1011  if (GetPrototype())
1012  {
1013  iter = GetPrototype()->begin();
1014  }
1015  else
1016  {
1017  iter.properties = std::make_shared<std::vector<const C4Property*> >();
1018  }
1019  iter.Reserve(Properties.GetSize());
1020 
1021  const C4Property * p = Properties.First();
1022  while (p)
1023  {
1024  iter.AddProperty(p);
1025  p = Properties.Next(p);
1026  }
1027 
1028  iter.Init();
1029  return iter;
1030 }
1031 
1032 
1033 template<> template<>
1034 unsigned int C4Set<C4PropListNumbered *>::Hash<int>(int const & e)
1035 {
1036  unsigned int hash = 4, tmp;
1037  hash += e >> 16;
1038  tmp = ((e & 0xffff) << 11) ^ hash;
1039  hash = (hash << 16) ^ tmp;
1040  hash += hash >> 11;
1041  hash ^= hash << 3;
1042  hash += hash >> 5;
1043  hash ^= hash << 4;
1044  hash += hash >> 17;
1045  hash ^= hash << 25;
1046  hash += hash >> 6;
1047  return hash;
1048 }
1049 
1050 template<> template<>
1051 unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropList *>(C4PropList * const & e)
1052 {
1053  return Hash(e->GetPropListNumbered()->Number);
1054 }
1055 
1056 template<> template<>
1058 {
1059  return Hash(e->Number);
1060 }
1061 
1062 template<> template<>
1063 bool C4Set<C4PropListNumbered *>::Equals<int>(C4PropListNumbered * const & a, int const & b)
1064 {
1065  return a->Number == b;
1066 }
1067 
1068 template<> template<>
1070 {
1071  return a == b;
1072 }
1073 
1074 template<> template<>
1076 {
1077  return C4Set<C4PropListNumbered *>::Hash(static_cast<int>(reinterpret_cast<intptr_t>(e)));
1078 }
1079 
1080 template<> template<>
1082 {
1083  // since script prop lists are only put in the set for reference keeping, just hash by pointer
1084  // but use only some of the more significant bits because
1085  uintptr_t hash = reinterpret_cast<uintptr_t>(e);
1086  return (unsigned int)(hash / 63);
1087 }
virtual void ResetProperty(C4String *k)
Definition: C4PropList.cpp:973
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:855
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:667
const char * GetName() const override
Definition: C4PropList.cpp:267
virtual C4Def const * GetDef() const
Definition: C4PropList.cpp:685
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:872
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:757
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:649
static void ClearShelve()
Definition: C4PropList.cpp:131
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:914
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:940
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:72
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:697
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:789
virtual C4Effect * GetEffect()
Definition: C4PropList.cpp:709
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:691
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:886
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:952
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:703
~C4PropListNumbered() override
Definition: C4PropList.cpp:199
C4String * GetPropertyStr(C4PropertyName k) const
Definition: C4PropList.cpp:775
#define s
C4PropList * GetPropertyPropList(C4PropertyName k) const
Definition: C4PropList.cpp:900
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:656