Torque3D Documentation / _generateds / simFieldDictionary.cpp

simFieldDictionary.cpp

Engine/source/console/simFieldDictionary.cpp

More...

Public Functions

Detailed Description

Public Variables

Chunker< SimFieldDictionary::Entry > fieldChunker 

Public Functions

compareEntries(const void * a, const void * b)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
 26// Copyright (C) 2015 Faust Logic, Inc.
 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 28
 29#include "platform/platform.h"
 30#include "console/simFieldDictionary.h"
 31
 32#include "console/console.h"
 33#include "console/consoleInternal.h"
 34#include "core/frameAllocator.h"
 35
 36SimFieldDictionary::Entry *SimFieldDictionary::smFreeList = NULL;
 37
 38static Chunker<SimFieldDictionary::Entry> fieldChunker;
 39
 40U32 SimFieldDictionary::getHashValue(StringTableEntry slotName)
 41{
 42   return HashPointer(slotName) % HashTableSize;
 43}
 44
 45U32 SimFieldDictionary::getHashValue(const String& fieldName)
 46{
 47   return getHashValue(StringTable->insert(fieldName));
 48}
 49
 50SimFieldDictionary::Entry *SimFieldDictionary::addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value)
 51{
 52   Entry* ret;
 53   if (smFreeList)
 54   {
 55      ret = smFreeList;
 56      smFreeList = ret->next;
 57   }
 58   else
 59      ret = fieldChunker.alloc();
 60
 61   ret->next = mHashTable[bucket];
 62   ret->slotName = slotName;
 63   ret->type = type;
 64   ret->value = value;
 65
 66   mHashTable[bucket] = ret;
 67   mNumFields++;
 68   mVersion++;
 69
 70   return ret;
 71}
 72
 73void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
 74{
 75   ent->next = smFreeList;
 76   smFreeList = ent;
 77
 78   mNumFields--;
 79}
 80
 81SimFieldDictionary::SimFieldDictionary()
 82   : mNumFields(0),
 83   mVersion(0)
 84{
 85   dMemset(mHashTable, 0, sizeof(mHashTable));
 86}
 87
 88SimFieldDictionary::~SimFieldDictionary()
 89{
 90   for (U32 i = 0; i < HashTableSize; i++)
 91   {
 92      for (Entry *walk = mHashTable[i]; walk;)
 93      {
 94         Entry *temp = walk;
 95         walk = temp->next;
 96
 97         if (temp->value)
 98            dFree(temp->value);
 99         freeEntry(temp);
100      }
101   }
102
103   AssertFatal(mNumFields == 0, "Incorrect count on field dictionary");
104}
105
106void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
107{
108   ConsoleBaseType *cbt = ConsoleBaseType::getTypeByName(typeString);
109   setFieldType(slotName, cbt);
110}
111
112void SimFieldDictionary::setFieldType(StringTableEntry slotName, const U32 typeId)
113{
114   ConsoleBaseType *cbt = ConsoleBaseType::getType(typeId);
115   setFieldType(slotName, cbt);
116}
117
118void SimFieldDictionary::setFieldType(StringTableEntry slotName, ConsoleBaseType *type)
119{
120   // If the field exists on the object, set the type
121   U32 bucket = getHashValue(slotName);
122
123   for (Entry *walk = mHashTable[bucket]; walk; walk = walk->next)
124   {
125      if (walk->slotName == slotName)
126      {
127         // Found and type assigned, let's bail
128         walk->type = type;
129         return;
130      }
131   }
132
133   // Otherwise create the field, and set the type. Assign a null value.
134   addEntry(bucket, slotName, type);
135}
136
137U32 SimFieldDictionary::getFieldType(StringTableEntry slotName) const
138{
139   U32 bucket = getHashValue(slotName);
140
141   for (Entry *walk = mHashTable[bucket]; walk; walk = walk->next)
142      if (walk->slotName == slotName)
143         return walk->type ? walk->type->getTypeID() : TypeString;
144
145   return TypeString;
146}
147
148SimFieldDictionary::Entry  *SimFieldDictionary::findDynamicField(const String &fieldName) const
149{
150   U32 bucket = getHashValue(fieldName);
151
152   for (Entry *walk = mHashTable[bucket]; walk; walk = walk->next)
153   {
154      if (fieldName.equal(walk->slotName, String::NoCase))
155         return walk;
156   }
157
158   return NULL;
159}
160
161SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(StringTableEntry fieldName) const
162{
163   U32 bucket = getHashValue(fieldName);
164
165   for (Entry *walk = mHashTable[bucket]; walk; walk = walk->next)
166   {
167      if (walk->slotName == fieldName)
168      {
169         return walk;
170      }
171   }
172
173   return NULL;
174}
175
176
177void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
178{
179   U32 bucket = getHashValue(slotName);
180   Entry **walk = &mHashTable[bucket];
181   while (*walk && (*walk)->slotName != slotName)
182      walk = &((*walk)->next);
183
184   Entry *field = *walk;
185   if (!value || !*value)
186   {
187      if (field)
188      {
189         mVersion++;
190
191         if (field->value)
192            dFree(field->value);
193
194         *walk = field->next;
195         freeEntry(field);
196      }
197   }
198   else
199   {
200      if (field)
201      {
202         if (field->value)
203            dFree(field->value);
204
205         field->value = dStrdup(value);
206      }
207      else
208         addEntry(bucket, slotName, 0, dStrdup(value));
209   }
210}
211
212const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
213{
214   U32 bucket = getHashValue(slotName);
215
216   for (Entry *walk = mHashTable[bucket]; walk; walk = walk->next)
217      if (walk->slotName == slotName)
218         return walk->value;
219
220   return NULL;
221}
222
223void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
224{
225   mVersion++;
226
227   for (U32 i = 0; i < HashTableSize; i++)
228   {
229      for (Entry *walk = dict->mHashTable[i]; walk; walk = walk->next)
230      {
231         setFieldValue(walk->slotName, walk->value);
232         setFieldType(walk->slotName, walk->type);
233      }
234   }
235}
236
237static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
238{
239   SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
240   SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
241   return dStricmp(fa->slotName, fb->slotName);
242}
243
244void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
245{
246   const AbstractClassRep::FieldList &list = obj->getFieldList();
247   Vector<Entry*> flist(__FILE__, __LINE__);
248
249   for (U32 curEntry = 0; curEntry < HashTableSize; curEntry++)
250   {
251      for (Entry *walk = mHashTable[curEntry]; walk; walk = walk->next)
252      {
253         // make sure we haven't written this out yet:
254         U32 curField;
255         for (curField = 0; curField < list.size(); curField++)
256            if (list[curField].pFieldname == walk->slotName)
257               break;
258
259         if (curField != list.size())
260            continue;
261
262
263         if (!obj->writeField(walk->slotName, walk->value))
264            continue;
265
266         flist.push_back(walk);
267      }
268   }
269
270   // Sort Entries to prevent version control conflicts
271   dQsort(flist.address(), flist.size(), sizeof(Entry *), compareEntries);
272
273   // Save them out
274   for (Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
275   {
276      U32 nBufferSize = (dStrlen((*itr)->value) * 2) + dStrlen((*itr)->slotName) + 16;
277      FrameTemp<char> expandedBuffer(nBufferSize);
278
279      stream.writeTabs(tabStop + 1);
280
281      const char *typeName = (*itr)->type && (*itr)->type->getTypeID() != TypeString ? (*itr)->type->getTypeName() : "";
282      dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", (*itr)->slotName);
283      if ((*itr)->value)
284         expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
285      dStrcat(expandedBuffer, "\";\r\n", nBufferSize);
286
287      stream.write(dStrlen(expandedBuffer), expandedBuffer);
288   }
289
290}
291void SimFieldDictionary::printFields(SimObject *obj)
292{
293   const AbstractClassRep::FieldList &list = obj->getFieldList();
294   char expandedBuffer[4096];
295   Vector<Entry*> flist(__FILE__, __LINE__);
296
297   for (U32 curEntry = 0; curEntry < HashTableSize; curEntry++)
298   {
299      for (Entry *walk = mHashTable[curEntry]; walk; walk = walk->next)
300      {
301         // make sure we haven't written this out yet:
302         U32 curField;
303         for (curField = 0; curField < list.size(); curField++)
304            if (list[curField].pFieldname == walk->slotName)
305               break;
306
307         if (curField != list.size())
308            continue;
309
310         flist.push_back(walk);
311      }
312   }
313   dQsort(flist.address(), flist.size(), sizeof(Entry *), compareEntries);
314
315   for (Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
316   {
317      const char* type = "string";
318      if ((*itr)->type)
319         type = (*itr)->type->getTypeClassName();
320
321      dSprintf(expandedBuffer, sizeof(expandedBuffer), "  %s %s = \"", type, (*itr)->slotName);
322      if ((*itr)->value)
323         expandEscape(expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
324      Con::printf("%s\"", expandedBuffer);
325   }
326}
327
328SimFieldDictionary::Entry  *SimFieldDictionary::operator[](U32 index)
329{
330   AssertFatal(index < mNumFields, "out of range");
331
332   if (index > mNumFields)
333      return NULL;
334
335   SimFieldDictionaryIterator itr(this);
336
337   for (S32 i = 0; i < index && *itr; i++)
338      ++itr;
339
340   return (*itr);
341}
342
343//------------------------------------------------------------------------------
344SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
345{
346   mDictionary = dictionary;
347   mHashIndex = -1;
348   mEntry = 0;
349   operator++();
350}
351
352SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
353{
354   if (!mDictionary)
355      return(mEntry);
356
357   if (mEntry)
358      mEntry = mEntry->next;
359
360   while (!mEntry && (mHashIndex < (SimFieldDictionary::HashTableSize - 1)))
361      mEntry = mDictionary->mHashTable[++mHashIndex];
362
363   return(mEntry);
364}
365
366SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
367{
368   return(mEntry);
369}
370// A variation of the stock SimFieldDictionary::setFieldValue(), this method adds the
371// <no_replace> argument which, when true, prohibits the replacement of fields that
372// already have a value. 
373//
374// AFX uses this when an effects-choreographer (afxMagicSpell, afxEffectron) is created 
375// using the new operator. It prevents any in-line effect parameters from being overwritten
376// by default parameters that are copied over later.
377void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value, ConsoleBaseType *type, bool no_replace)
378{
379   if (!no_replace)
380   {
381      setFieldValue(slotName, value);
382      return;
383   }
384
385   if (!value || !*value)
386      return;
387
388   U32 bucket = getHashValue(slotName);
389   Entry **walk = &mHashTable[bucket];
390   while (*walk && (*walk)->slotName != slotName)
391      walk = &((*walk)->next);
392
393   Entry *field = *walk;
394   if (field)
395      return;
396
397   addEntry(bucket, slotName, type, dStrdup(value));
398}
399// A variation of the stock SimFieldDictionary::assignFrom(), this method adds <no_replace>
400// and <filter> arguments. When true, <no_replace> prohibits the replacement of fields that already
401// have a value. When <filter> is specified, only fields with leading characters that exactly match
402// the characters in <filter> are copied.
403void SimFieldDictionary::assignFrom(SimFieldDictionary *dict, const char* filter, bool no_replace)
404{
405   dsize_t filter_len = (filter) ? dStrlen(filter) : 0;
406   if (filter_len == 0 && !no_replace)
407   {
408      assignFrom(dict);
409      return;
410   }
411
412   mVersion++;
413
414   if (filter_len == 0)
415   {
416      for (U32 i = 0; i < HashTableSize; i++)
417         for (Entry *walk = dict->mHashTable[i]; walk; walk = walk->next)
418            setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
419   }
420   else
421   {
422      for (U32 i = 0; i < HashTableSize; i++)
423         for (Entry *walk = dict->mHashTable[i]; walk; walk = walk->next)
424            if (dStrncmp(walk->slotName, filter, filter_len) == 0)
425               setFieldValue(walk->slotName, walk->value, walk->type, no_replace);
426   }
427}
428