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 "script/C4Aul.h"
22 #include "object/C4GameObjects.h"
23 #include "control/C4Record.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 (std::vector<C4PropListNumbered *>::iterator i=ShelvedPropLists.begin(); i!=ShelvedPropLists.end(); ++i)
127  (*i)->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  FirstRef(nullptr), prototype(prototype),
277  constant(false), Status(1)
278 {
279 #ifdef _DEBUG
280  PropLists.Add(this);
281 #endif
282 }
283 
285 {
286  //thaw self and all owned properties
287  Thaw();
289  //if (s) LogF("Thaw: %s", s->GetDataString().getData());
290  auto prop_names = GetUnsortedProperties(nullptr, ::ScriptEngine.GetPropList());
291  for (auto prop_name : prop_names)
292  {
293  C4Value child_val;
294  GetPropertyByS(prop_name, &child_val);
295  //LogF(" %s=%s", prop_name->GetCStr(), child_val.GetDataString(1).getData());
296  C4PropList *child_proplist = child_val.getPropList();
297  if (child_proplist && child_proplist->IsFrozen())
298  {
299  child_proplist->ThawRecursively();
300  }
301  }
302 }
303 
304 C4PropListStatic *C4PropList::FreezeAndMakeStaticRecursively(std::vector<C4Value>* prop_lists, const C4PropListStatic *parent, C4String * key)
305 {
306  Freeze();
307  // Already static?
308  C4PropListStatic *this_static = IsStatic();
309  if (!this_static)
310  {
311  // Make self static by creating a copy and replacing all references
312  this_static = NewStatic(GetPrototype(), parent, key);
313  this_static->Properties.Swap(&Properties); // grab properties
314  this_static->Status = Status;
315  C4Value holder = C4VPropList(this);
316  while (FirstRef && FirstRef->NextRef)
317  {
318  C4Value *ref = FirstRef;
319  if (ref == &holder) ref = ref->NextRef;
320  ref->SetPropList(this_static);
321  }
322  // store reference
323  if (prop_lists)
324  {
325  prop_lists->push_back(C4VPropList(this_static));
326  }
327  // "this" should be deleted as holder goes out of scope
328  }
329  // Iterate over sorted list of elements to make static
330  // Must iterate over sorted list because the order must be defined, just in case it's a network game
331  // and a non-static child proplist is available through different paths it should still get the same name
332  auto prop_names = this_static->GetSortedLocalProperties(false);
333  for (auto prop_name : prop_names)
334  {
335  C4Value child_val;
336  this_static->GetPropertyByS(prop_name, &child_val);
337  C4PropList *child_proplist = child_val.getPropList();
338  if (child_proplist)
339  {
340  // Avoid infinite recursion: Only freeze into unfrozen children and "true" static children
341  C4PropListStatic *child_static = child_proplist->IsStatic();
342  if (!child_static || (child_static->GetParent() == this_static && child_static->GetParentKeyName() == prop_name))
343  {
344  child_proplist->FreezeAndMakeStaticRecursively(prop_lists, this_static, prop_name);
345  }
346  }
347  }
348  return this_static;
349 }
350 
352 {
353  const C4Property * p = Properties.First();
354  while (p)
355  {
356  const_cast<C4Value &>(p->Value).Denumerate(numbers);
357  p = Properties.Next(p);
358  }
359  prototype.Denumerate(numbers);
361 }
362 
364 {
365  while (FirstRef)
366  {
367  // Manually kill references so DelRef doesn't destroy us again
368  FirstRef->Data = 0; FirstRef->Type = C4V_Nil;
369  C4Value *ref = FirstRef;
370  FirstRef = FirstRef->NextRef;
371  ref->NextRef = nullptr;
372  }
373 #ifdef _DEBUG
374  assert(PropLists.Has(this));
375  PropLists.Remove(this);
376 #endif
377  assert(!C4PropListNumbered::CheckPropList(this));
378 }
379 
381 {
382  // every numbered proplist has a unique number and is only identical to itself
383  if (this == &b) return true;
384  if (IsNumbered() || b.IsNumbered()) return false;
385  if (Properties.GetSize() != b.Properties.GetSize()) return false;
386  if (GetDef() != b.GetDef()) return false;
387  const C4Property * p = Properties.First();
388  while (p)
389  {
390  const C4Property & bp = b.Properties.Get(p->Key);
391  if (!bp) return false;
392  if (p->Value != bp.Value) return false;
393  p = Properties.Next(p);
394  }
395  return true;
396 }
397 
399 {
400  bool oldFormat = false;
401  // constant proplists are not serialized to savegames, but recreated from the game data instead
402  assert(!constant);
403  if (pComp->isDeserializer() && pComp->hasNaming())
404  {
405  // backwards compat to savegames and scenarios before 5.5
406  try
407  {
408  pComp->Value(constant);
409  oldFormat = true;
410  }
411  catch (StdCompiler::NotFoundException *pEx)
412  {
413  delete pEx;
414  pComp->Value(mkParAdapt(prototype, numbers));
415  }
416  }
417  else
418  pComp->Value(mkParAdapt(prototype, numbers));
420  pComp->Value(mkParAdapt(Properties, numbers));
421  if (oldFormat)
422  {
423  if (Properties.Has(&::Strings.P[P_Prototype]))
424  {
425  prototype = Properties.Get(&::Strings.P[P_Prototype]).Value;
426  Properties.Remove(&::Strings.P[P_Prototype]);
427  }
428  }
429 }
430 
432 {
433  // clear any cyclic prototype chains
434  // Use prototype.getPropList() instead of GetPrototype() because denumeration might not be completed yet
435  for(C4PropList * it = prototype.getPropList(); it; it = it->prototype.getPropList())
436  if(it == this)
437  {
438  prototype.Set0();
439  }
440 }
441 
442 void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers *rPar)
443 {
444  std::unique_ptr<C4PropList> temp(C4PropList::New()); // exception-safety
445  pComp->Value(mkParAdapt(*temp, rPar));
446  pStruct = temp.release();
447 }
448 
449 template<typename T>
451 {
452  bool fNaming = pComp->hasNaming();
453  if (pComp->isDeserializer())
454  {
455  // Compiling: Empty previous
456  Clear();
457  // Read size (binary only)
458  uint32_t iSize;
459  if (!pComp->hasNaming()) pComp->Value(iSize);
460  // Read new
461  do
462  {
463  // No entries left to read?
464  if (!fNaming && !iSize--)
465  break;
466  // Read entries
467  try
468  {
469  T e;
470  // This could use the same technique StdArrayAdapt uses
471  // instead of hardcoding mkParAdapt here
472  pComp->Value(mkParAdapt(e, numbers));
473  Add(e);
474  }
475  catch (StdCompiler::NotFoundException *pEx)
476  {
477  // No value found: Stop reading loop
478  delete pEx;
479  break;
480  }
481  }
482  while (pComp->Separator(StdCompiler::SEP_SEP));
483  }
484  else
485  {
486  // Write size (binary only)
487  if (!fNaming)
488  {
489  int32_t iSize = GetSize();
490  pComp->Value(iSize);
491  }
492  // Write all entries
493  const T * p = First();
494  while (p)
495  {
496  pComp->Value(mkParAdapt(*const_cast<T *>(p), numbers));
497  p = Next(p);
498  if (p) pComp->Separator(StdCompiler::SEP_SEP);
499  }
500  }
501 }
502 
504 {
505  StdStrBuf s;
506  if (!pComp->isDeserializer())
507  s = Key->GetData();
508  pComp->Value(s);
509  if (pComp->isDeserializer())
510  {
511  if (Key) Key->DecRef();
512  Key = ::Strings.RegString(s);
513  Key->IncRef();
514  }
516  pComp->Value(mkParAdapt(Value, numbers));
517 }
518 
519 void C4PropList::AppendDataString(StdStrBuf * out, const char * delim, int depth, bool ignore_reference_parent) const
520 {
521  StdStrBuf & DataString = *out;
522  if (depth <= 0 && Properties.GetSize())
523  {
524  DataString.Append("...");
525  return;
526  }
527  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
528  for (std::list<const C4Property *>::const_iterator p = sorted_props.begin(); p != sorted_props.end(); ++p)
529  {
530  if (p != sorted_props.begin()) DataString.Append(delim);
531  DataString.Append((*p)->Key->GetData());
532  DataString.Append(" = ");
533  DataString.Append((*p)->Value.GetDataString(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
534  }
535 }
536 
537 StdStrBuf C4PropList::ToJSON(int depth, bool ignore_reference_parent) const
538 {
539  if (depth <= 0 && Properties.GetSize())
540  {
541  throw new C4JSONSerializationError("maximum depth reached");
542  }
543  StdStrBuf DataString;
544  DataString = "{";
545  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
546  for (std::list<const C4Property *>::const_iterator p = sorted_props.begin(); p != sorted_props.end(); ++p)
547  {
548  if (p != sorted_props.begin()) DataString.Append(",");
549  DataString.Append(C4Value((*p)->Key).ToJSON());
550  DataString.Append(":");
551  DataString.Append((*p)->Value.ToJSON(depth - 1, ignore_reference_parent ? IsStatic() : nullptr));
552  }
553  DataString.Append("}");
554  return DataString;
555 }
556 
557 std::vector< C4String * > C4PropList::GetSortedLocalProperties(bool add_prototype) const
558 {
559  // return property list without descending into prototype
560  std::list<const C4Property *> sorted_props = Properties.GetSortedListOfElementPointers();
561  std::vector< C4String * > result;
562  result.reserve(sorted_props.size() + add_prototype);
563  if (add_prototype) result.push_back(&::Strings.P[P_Prototype]); // implicit prototype for every prop list
564  for (auto p : sorted_props) result.push_back(p->Key);
565  return result;
566 }
567 
568 std::vector< C4String * > C4PropList::GetSortedLocalProperties(const char *prefix, const C4PropList *ignore_overridden) const
569 {
570  // return property list without descending into prototype
571  // ignore properties that have been overridden by proplist given in ignore_overridden or any of its prototypes up to and excluding this
572  std::vector< C4String * > result;
573  for (const C4Property *pp = Properties.First(); pp; pp = Properties.Next(pp))
574  if (pp->Key != &::Strings.P[P_Prototype])
575  if (!prefix || pp->Key->GetData().BeginsWith(prefix))
576  {
577  // Override check
578  const C4PropList *check = ignore_overridden;
579  bool overridden = false;
580  if (check && check != this)
581  {
582  if (check->HasProperty(pp->Key)) { overridden = true; break; }
583  check = check->GetPrototype();
584  }
585  result.push_back(pp->Key);
586  }
587  // Sort
588  std::sort(result.begin(), result.end(), [](const C4String *a, const C4String *b) -> bool
589  {
590  return strcmp(a->GetCStr(), b->GetCStr()) < 0;
591  });
592  return result;
593 }
594 
595 std::vector< C4String * > C4PropList::GetUnsortedProperties(const char *prefix, C4PropList *ignore_parent) const
596 {
597  // Return property list with descending into prototype
598  // But do not include Prototype property
599  std::vector< C4String * > result;
600  const C4PropList *p = this;
601  do
602  {
603  for (const C4Property *pp = p->Properties.First(); pp; pp = p->Properties.Next(pp))
604  if (pp->Key != &::Strings.P[P_Prototype])
605  if (!prefix || pp->Key->GetData().BeginsWith(prefix))
606  result.push_back(pp->Key);
607  p = p->GetPrototype();
608  if (p == ignore_parent) break;
609  } while (p);
610  return result;
611 }
612 
613 std::vector< C4String * > C4PropList::GetSortedProperties(const char *prefix, C4PropList *ignore_parent) const
614 {
615  // Return property list with descending into prototype
616  // But do not include Prototype property
617  std::vector< C4String * > result = GetUnsortedProperties(prefix, ignore_parent);
618  // Sort
619  std::sort(result.begin(), result.end(), [](const C4String *a, const C4String *b) -> bool
620  {
621  return strcmp(a->GetCStr(), b->GetCStr()) < 0;
622  });
623  return result;
624 }
625 
626 const char * C4PropList::GetName() const
627 {
629  if (!s) return "";
630  return s->GetCStr();
631 }
632 
633 void C4PropList::SetName(const char* NewName)
634 {
635  if (!NewName)
637  else
638  {
639  SetProperty(P_Name, C4VString(NewName));
640  }
641 }
642 
643 
645 {
646  if (GetPrototype()) return GetPrototype()->GetObject();
647  return 0;
648 }
649 
651 {
652  if (GetPrototype()) return GetPrototype()->GetObject();
653  return 0;
654 }
655 
657 {
658  if (GetPrototype()) return GetPrototype()->GetDef();
659  return 0;
660 }
661 
662 C4Def const * C4PropList::GetDef() const
663 {
664  if (GetPrototype()) return GetPrototype()->GetDef();
665  return 0;
666 }
667 
669 {
670  if (GetPrototype()) return GetPrototype()->GetMapScriptLayer();
671  return nullptr;
672 }
673 
675 {
676  if (GetPrototype()) return GetPrototype()->GetMapScriptMap();
677  return nullptr;
678 }
679 
681 {
682  if (GetPrototype()) return GetPrototype()->GetPropListNumbered();
683  return 0;
684 }
685 
687 {
688  if (GetPrototype()) return GetPrototype()->GetEffect();
689  return 0;
690 }
691 
692 template<> template<>
693 unsigned int C4Set<C4Property>::Hash<const C4String *>(C4String const * const & e)
694 {
695  assert(e);
696  unsigned int hash = 4, tmp;
697  hash += ((uintptr_t)e) >> 16;
698  tmp = ((((uintptr_t)e) & 0xffff) << 11) ^ hash;
699  hash = (hash << 16) ^ tmp;
700  hash += hash >> 11;
701  hash ^= hash << 3;
702  hash += hash >> 5;
703  hash ^= hash << 4;
704  hash += hash >> 17;
705  hash ^= hash << 25;
706  hash += hash >> 6;
707  return hash;
708 }
709 
710 template<> template<>
711 unsigned int C4Set<C4Property>::Hash<C4String *>(C4String * const & e)
712 {
713  return Hash<const C4String *>(e);
714 }
715 
716 template<> template<>
717 bool C4Set<C4Property>::Equals<const C4String *>(C4Property const & a, C4String const * const & b)
718 {
719  return a.Key == b;
720 }
721 
722 template<> template<>
723 bool C4Set<C4Property>::Equals<C4String *>(C4Property const & a, C4String * const & b)
724 {
725  return a.Key == b;
726 }
727 
728 template<> template<>
729 unsigned int C4Set<C4Property>::Hash<C4Property>(C4Property const & p)
730 {
731  return C4Set<C4Property>::Hash(p.Key);
732 }
733 
734 bool C4PropList::GetPropertyByS(const C4String * k, C4Value *pResult) const
735 {
736  if (Properties.Has(k))
737  {
738  *pResult = Properties.Get(k).Value;
739  return true;
740  }
741  else if (k == &Strings.P[P_Prototype])
742  {
743  *pResult = prototype;
744  return true;
745  }
746  else if(GetPrototype())
747  return GetPrototype()->GetPropertyByS(k, pResult);
748  else
749  return false;
750 }
751 
753 {
754  C4String * k = &Strings.P[n];
755  if (Properties.Has(k))
756  {
757  return Properties.Get(k).Value.getStr();
758  }
759  if (GetPrototype())
760  {
761  return GetPrototype()->GetPropertyStr(n);
762  }
763  return 0;
764 }
765 
767 {
768  C4String * k = &Strings.P[n];
769  if (Properties.Has(k))
770  {
771  return Properties.Get(k).Value.getArray();
772  }
773  if (GetPrototype())
774  {
775  return GetPrototype()->GetPropertyArray(n);
776  }
777  return 0;
778 }
779 
781 {
782  assert(k);
783  if (Properties.Has(k))
784  {
785  return Properties.Get(k).Value.getFunction();
786  }
787  if (GetPrototype())
788  {
789  return GetPrototype()->GetFunc(k);
790  }
791  return 0;
792 }
793 
794 C4AulFunc * C4PropList::GetFunc(const char * s) const
795 {
796  assert(s);
797  if (s[0] == '~') ++s;
798  C4String * k = Strings.FindString(s);
799  // this string is entirely unused
800  if (!k)
801  return 0;
802  return GetFunc(k);
803 }
804 
805 C4Value C4PropList::Call(C4String * k, C4AulParSet *Pars, bool fPassErrors)
806 {
807  if (!Status) return C4Value();
808  C4AulFunc *pFn = GetFunc(k);
809  if (!pFn) return C4Value();
810  return pFn->Exec(this, Pars, fPassErrors);
811 }
812 
813 C4Value C4PropList::Call(const char * s, C4AulParSet *Pars, bool fPassErrors)
814 {
815  if (!Status) return C4Value();
816  assert(s && s[0]);
817  C4AulFunc *pFn = GetFunc(s);
818  if (!pFn)
819  {
820  if (s[0] != '~')
821  {
822  C4AulExecError err(FormatString("Undefined function: %s", s).getData());
823  if (fPassErrors)
824  throw err;
826  }
827  return C4Value();
828  }
829  return pFn->Exec(this, Pars, fPassErrors);
830 }
831 
833 {
834  C4String * k = &Strings.P[n];
835  if (Properties.Has(k))
836  {
837  C4String * v = Properties.Get(k).Value.getStr();
838  if (v >= &Strings.P[0] && v < &Strings.P[P_LAST])
839  return C4PropertyName(v - &Strings.P[0]);
840  return P_LAST;
841  }
842  if (GetPrototype())
843  {
844  return GetPrototype()->GetPropertyP(n);
845  }
846  return P_LAST;
847 }
848 
849 int32_t C4PropList::GetPropertyBool(C4PropertyName n, bool default_val) const
850 {
851  C4String * k = &Strings.P[n];
852  if (Properties.Has(k))
853  {
854  return Properties.Get(k).Value.getBool();
855  }
856  if (GetPrototype())
857  {
858  return GetPrototype()->GetPropertyBool(n, default_val);
859  }
860  return default_val;
861 }
862 
863 int32_t C4PropList::GetPropertyInt(C4PropertyName n, int32_t default_val) const
864 {
865  C4String * k = &Strings.P[n];
866  if (Properties.Has(k))
867  {
868  return Properties.Get(k).Value.getInt();
869  }
870  if (GetPrototype())
871  {
872  return GetPrototype()->GetPropertyInt(n, default_val);
873  }
874  return default_val;
875 }
876 
878 {
879  C4String * k = &Strings.P[n];
880  if (Properties.Has(k))
881  {
882  return Properties.Get(k).Value.getPropList();
883  }
884  if (GetPrototype())
885  {
886  return GetPrototype()->GetPropertyPropList(n);
887  }
888  return nullptr;
889 }
890 
892 {
893  C4ValueArray * a;
894  int i;
895  if (GetPrototype())
896  {
897  a = GetPrototype()->GetProperties();
898  i = a->GetSize();
899  a->SetSize(i + Properties.GetSize());
900  }
901  else
902  {
903  a = new C4ValueArray(Properties.GetSize());
904  i = 0;
905  }
906  const C4Property * p = Properties.First();
907  while (p)
908  {
909  assert(p->Key != nullptr && "Proplist key is nullpointer");
910  (*a)[i++] = C4VString(p->Key);
911  assert(((*a)[i - 1].GetType() == C4V_String) && "Proplist key is non-string");
912  p = Properties.Next(p);
913  }
914  return a;
915 }
916 
918 {
919  const C4Property * p = prev ? Properties.Next(&Properties.Get(prev)) : Properties.First();
920  while (p)
921  {
922  if (p->Value.getFunction())
923  return p->Key;
924  p = Properties.Next(p);
925  }
926  return 0;
927 }
928 
930 {
931  assert(!constant);
932  if (k == &Strings.P[P_Prototype])
933  {
934  C4PropList * newpt = to.getPropList();
935  for(C4PropList * it = newpt; it; it = it->GetPrototype())
936  if(it == this)
937  throw C4AulExecError("Trying to create cyclic prototype structure");
938  prototype.SetPropList(newpt);
939  }
940  else if (Properties.Has(k))
941  {
942  Properties.Get(k).Value = to;
943  }
944  else
945  {
946  Properties.Add(C4Property(k, to));
947  }
948 }
949 
951 {
952  if (k == &Strings.P[P_Prototype])
953  prototype.Set0();
954  else
955  Properties.Remove(k);
956 }
957 
958 void C4PropList::Iterator::Init()
959 {
960  iter = properties->begin();
961 }
962 
963 void C4PropList::Iterator::Reserve(size_t additionalAmount)
964 {
965  properties->reserve(properties->size() + additionalAmount);
966 }
967 
968 void C4PropList::Iterator::AddProperty(const C4Property * prop)
969 {
970  std::vector<const C4Property*>::size_type i = 0, len = properties->size();
971  for(;i < len; ++i)
972  {
973  const C4Property *oldProperty = (*properties)[i];
974  if (oldProperty->Key == prop->Key)
975  {
976  (*properties)[i] = prop;
977  return;
978  }
979  }
980  // not already in vector?
981  properties->push_back(prop);
982 }
983 
985 {
987 
988  if (GetPrototype())
989  {
990  iter = GetPrototype()->begin();
991  }
992  else
993  {
994  iter.properties = std::make_shared<std::vector<const C4Property*> >();
995  }
996  iter.Reserve(Properties.GetSize());
997 
998  const C4Property * p = Properties.First();
999  while (p)
1000  {
1001  iter.AddProperty(p);
1002  p = Properties.Next(p);
1003  }
1004 
1005  iter.Init();
1006  return iter;
1007 }
1008 
1009 
1010 template<> template<>
1011 unsigned int C4Set<C4PropListNumbered *>::Hash<int>(int const & e)
1012 {
1013  unsigned int hash = 4, tmp;
1014  hash += e >> 16;
1015  tmp = ((e & 0xffff) << 11) ^ hash;
1016  hash = (hash << 16) ^ tmp;
1017  hash += hash >> 11;
1018  hash ^= hash << 3;
1019  hash += hash >> 5;
1020  hash ^= hash << 4;
1021  hash += hash >> 17;
1022  hash ^= hash << 25;
1023  hash += hash >> 6;
1024  return hash;
1025 }
1026 
1027 template<> template<>
1028 unsigned int C4Set<C4PropListNumbered *>::Hash<C4PropList *>(C4PropList * const & e)
1029 {
1030  return Hash(e->GetPropListNumbered()->Number);
1031 }
1032 
1033 template<> template<>
1035 {
1036  return Hash(e->Number);
1037 }
1038 
1039 template<> template<>
1040 bool C4Set<C4PropListNumbered *>::Equals<int>(C4PropListNumbered * const & a, int const & b)
1041 {
1042  return a->Number == b;
1043 }
1044 
1045 template<> template<>
1047 {
1048  return a == b;
1049 }
1050 
1051 template<> template<>
1053 {
1054  return C4Set<C4PropListNumbered *>::Hash(static_cast<int>(reinterpret_cast<intptr_t>(e)));
1055 }
1056 
1057 template<> template<>
1059 {
1060  // since script prop lists are only put in the set for reference keeping, just hash by pointer
1061  // but use only some of the more significant bits because
1062  uintptr_t hash = reinterpret_cast<uintptr_t>(e);
1063  return (unsigned int)(hash / 63);
1064 }
virtual void ResetProperty(C4String *k)
Definition: C4PropList.cpp:950
StdStrBuf ToJSON(int depth=10, bool ignore_reference_parent=false) const
Definition: C4PropList.cpp:537
void RemoveCyclicPrototypes()
Definition: C4PropList.cpp:431
C4PropertyName GetPropertyP(C4PropertyName k) const
Definition: C4PropList.cpp:832
C4String P[P_LAST]
virtual bool Separator(Sep eSep=SEP_SEP)
Definition: StdCompiler.h:129
C4Value Value
Definition: C4PropList.h:57
void CompileFunc(class StdCompiler *pComp, class C4ValueNumbers *)
Definition: C4PropList.cpp:450
StdStrBuf GetData() const
Definition: C4StringTable.h:50
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4PropList.cpp:398
virtual bool hasNaming()
Definition: StdCompiler.h:68
virtual C4PropListNumbered * GetPropListNumbered()
Definition: C4PropList.cpp:175
C4AulErrorHandler * GetErrorHandler() const
Definition: C4Aul.h:175
C4String * EnumerateOwnFuncs(C4String *prev=0) const
Definition: C4PropList.cpp:917
void Thaw()
Definition: C4PropList.h:131
std::list< const T * > GetSortedListOfElementPointers() const
virtual const char * GetName() const
Definition: C4PropList.cpp:267
C4PropListStatic * FreezeAndMakeStaticRecursively(std::vector< C4Value > *prop_lists, const C4PropListStatic *parent=nullptr, C4String *key=nullptr)
Definition: C4PropList.cpp:304
C4PropListStatic * GetPropList()
Definition: C4Aul.h:153
virtual void SetName(const char *NewName=0)
Definition: C4PropList.cpp:633
static C4Set< C4PropListScript * > PropLists
Definition: C4PropList.h:256
C4String * getStr() const
Definition: C4Value.h:117
int32_t Number
Definition: C4Player.h:88
void IncRef()
Definition: C4StringTable.h:27
void excCorrupt(const char *szMessage,...)
Definition: StdCompiler.h:259
T * Add(T const &e)
bool operator==(const C4PropList &b) const
Definition: C4PropList.cpp:380
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
#define b
static void ResetEnumerationIndex()
Definition: C4PropList.cpp:99
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:107
void Freeze()
Definition: C4PropList.h:130
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:167
static C4PropList * GetByNumber(int32_t iNumber)
Definition: C4PropList.cpp:75
void SetProperty(C4PropertyName k, const C4Value &to)
Definition: C4PropList.h:122
static std::vector< C4PropListNumbered * > ShelvedPropLists
Definition: C4PropList.h:239
static void SetEnumerationIndex(int32_t iMaxObjectNumber)
Definition: C4PropList.cpp:93
void Set0()
Definition: C4Value.h:336
virtual class C4PropListStatic * IsStatic()
Definition: C4PropList.h:87
static bool CheckPropList(C4PropList *)
Definition: C4PropList.cpp:80
bool getBool() const
Definition: C4Value.h:113
virtual const char * what() const noexcept
#define a
C4String * GetParentKeyName()
Definition: C4PropList.h:273
void Clear()
Definition: C4PropList.h:68
static C4PropList * New(C4PropList *prototype=0)
Definition: C4PropList.cpp:64
virtual C4Object * GetObject()
Definition: C4PropList.cpp:644
C4PropListNumbered(C4PropList *prototype=0)
Definition: C4PropList.cpp:151
virtual C4Def const * GetDef() const
Definition: C4PropList.cpp:662
void AppendChar(char cChar)
Definition: StdBuf.h:596
void CompileFunc(StdCompiler *pComp, C4ValueNumbers *)
Definition: C4PropList.cpp:503
virtual void Denumerate(C4ValueNumbers *)
Definition: C4PropList.cpp:351
int32_t GetPropertyBool(C4PropertyName n, bool default_val=false) const
Definition: C4PropList.cpp:849
std::vector< C4String * > GetSortedLocalProperties(bool add_prototype=true) const
Definition: C4PropList.cpp:557
T & Get(H e) const
void Denumerate(C4ValueNumbers *)
Definition: C4Value.cpp:253
T const * Next(T const *p) const
unsigned int GetSize() const
int32_t Status
Definition: C4Player.h:84
C4StringTable Strings
Definition: C4Globals.cpp:42
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
Definition: C4PropList.cpp:734
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:245
static void ClearScriptPropLists()
Definition: C4PropList.cpp:207
Iterator begin()
Definition: C4PropList.cpp:984
virtual const char * GetName() const
Definition: C4PropList.cpp:626
static void ClearShelve()
Definition: C4PropList.cpp:131
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:891
C4PropList * GetPrototype() const
Definition: C4PropList.h:83
static void UnshelveNumberedPropLists()
Definition: C4PropList.cpp:123
virtual ~C4PropList()
Definition: C4PropList.cpp:363
void AppendDataString(StdStrBuf *out, const char *delim, int depth=3, bool ignore_reference_parent=false) const
Definition: C4PropList.cpp:519
void Take(char *pnData)
Definition: StdBuf.h:465
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:527
std::vector< C4String * > GetSortedProperties(const char *prefix, C4PropList *ignore_parent=nullptr) const
Definition: C4PropList.cpp:613
void RefCompileFunc(StdCompiler *pComp, C4ValueNumbers *numbers) const
Definition: C4PropList.cpp:240
Definition: C4Def.h:100
const C4PropListStatic * Parent
Definition: C4PropList.h:275
void SetSize(int32_t inSize)
C4Value Exec(C4PropList *p=nullptr, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4AulFunc.h:73
void ThawRecursively()
Definition: C4PropList.cpp:284
int32_t Status
Definition: C4PropList.h:170
C4ValueArray * getArray() const
Definition: C4Value.h:118
virtual class C4MapScriptMap * GetMapScriptMap()
Definition: C4PropList.cpp:674
static C4PropListStatic * NewStatic(C4PropList *prototype, const C4PropListStatic *parent, C4String *key)
Definition: C4PropList.cpp:70
void Value(const T &rStruct)
Definition: StdCompiler.h:171
void Remove(H e)
bool IsFrozen() const
Definition: C4PropList.h:133
static void ShelveNumberedPropLists()
Definition: C4PropList.cpp:105
C4PropertyName
int32_t GetSize() const
Definition: C4ValueArray.h:36
C4ValueArray * GetPropertyArray(C4PropertyName n) const
Definition: C4PropList.cpp:766
virtual C4Effect * GetEffect()
Definition: C4PropList.cpp:686
virtual void OnError(const char *msg)=0
int32_t getInt() const
Definition: C4Value.h:112
virtual bool isDeserializer()
Definition: StdCompiler.h:63
bool HasProperty(C4String *k) const
Definition: C4PropList.h:120
virtual class C4MapScriptLayer * GetMapScriptLayer()
Definition: C4PropList.cpp:668
C4String * Key
Definition: C4PropList.h:56
C4PropList(C4PropList *prototype=0)
Definition: C4PropList.cpp:275
virtual bool Delete()
Definition: C4PropList.h:92
bool Log(const char *szMessage)
Definition: C4Log.cpp:195
C4Player * Next
Definition: C4Player.h:144
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:863
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:456
virtual void SetPropertyByS(C4String *k, const C4Value &to)
Definition: C4PropList.cpp:929
void SetPropList(C4PropList *PropList)
Definition: C4Value.h:141
virtual bool IsNumbered() const
Definition: C4PropList.h:90
static C4Set< C4PropListNumbered * > PropLists
Definition: C4PropList.h:238
T const * First() const
std::vector< C4String * > GetUnsortedProperties(const char *prefix, C4PropList *ignore_parent=nullptr) const
Definition: C4PropList.cpp:595
static int32_t EnumerationIndex
Definition: C4PropList.h:240
void DecRef()
Definition: C4StringTable.h:28
C4Value Call(C4PropertyName k, C4AulParSet *pPars=0, bool fPassErrors=false)
Definition: C4PropList.h:112
virtual C4PropListNumbered * GetPropListNumbered()
Definition: C4PropList.cpp:680
C4String * GetPropertyStr(C4PropertyName k) const
Definition: C4PropList.cpp:752
#define s
C4PropList * GetPropertyPropList(C4PropertyName k) const
Definition: C4PropList.cpp:877
C4AulFunc * getFunction() const
Definition: C4Value.h:119
C4RefCntPointer< C4String > ParentKeyName
Definition: C4PropList.h:276
void CompileNewFunc(C4PropList *&pStruct, StdCompiler *pComp, C4ValueNumbers *rPar)
Definition: C4PropList.cpp:442
const C4PropListStatic * GetParent() const
Definition: C4PropList.h:272
int iSize
Definition: TstC4NetIO.cpp:35
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:277
StdStrBuf GetDataString() const
Definition: C4PropList.cpp:253
C4PropList * getPropList() const
Definition: C4Value.h:116