simFieldDictionary.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/simFieldDictionary.h"
  24. #include "console/console.h"
  25. #include "console/consoleInternal.h"
  26. #include "core/frameAllocator.h"
  27. SimFieldDictionary::Entry *SimFieldDictionary::smFreeList = NULL;
  28. static Chunker<SimFieldDictionary::Entry> fieldChunker;
  29. U32 SimFieldDictionary::getHashValue( StringTableEntry slotName )
  30. {
  31. return HashPointer( slotName ) % HashTableSize;
  32. }
  33. U32 SimFieldDictionary::getHashValue( const String& fieldName )
  34. {
  35. return getHashValue( StringTable->insert( fieldName ) );
  36. }
  37. SimFieldDictionary::Entry *SimFieldDictionary::addEntry( U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value )
  38. {
  39. Entry* ret;
  40. if(smFreeList)
  41. {
  42. ret = smFreeList;
  43. smFreeList = ret->next;
  44. }
  45. else
  46. ret = fieldChunker.alloc();
  47. ret->next = mHashTable[ bucket ];
  48. ret->slotName = slotName;
  49. ret->type = type;
  50. ret->value = value;
  51. mHashTable[ bucket ] = ret;
  52. mNumFields ++;
  53. mVersion ++;
  54. return ret;
  55. }
  56. void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
  57. {
  58. ent->next = smFreeList;
  59. smFreeList = ent;
  60. mNumFields --;
  61. }
  62. SimFieldDictionary::SimFieldDictionary()
  63. : mNumFields( 0 ),
  64. mVersion( 0 )
  65. {
  66. dMemset( mHashTable, 0, sizeof( mHashTable ) );
  67. }
  68. SimFieldDictionary::~SimFieldDictionary()
  69. {
  70. for(U32 i = 0; i < HashTableSize; i++)
  71. {
  72. for(Entry *walk = mHashTable[i]; walk;)
  73. {
  74. Entry *temp = walk;
  75. walk = temp->next;
  76. if( temp->value )
  77. dFree(temp->value);
  78. freeEntry(temp);
  79. }
  80. }
  81. AssertFatal( mNumFields == 0, "Incorrect count on field dictionary" );
  82. }
  83. void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
  84. {
  85. ConsoleBaseType *cbt = ConsoleBaseType::getTypeByName( typeString );
  86. setFieldType(slotName, cbt);
  87. }
  88. void SimFieldDictionary::setFieldType(StringTableEntry slotName, const U32 typeId)
  89. {
  90. ConsoleBaseType *cbt = ConsoleBaseType::getType(typeId);
  91. setFieldType(slotName, cbt);
  92. }
  93. void SimFieldDictionary::setFieldType(StringTableEntry slotName, ConsoleBaseType *type)
  94. {
  95. // If the field exists on the object, set the type
  96. U32 bucket = getHashValue( slotName );
  97. for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
  98. {
  99. if( walk->slotName == slotName )
  100. {
  101. // Found and type assigned, let's bail
  102. walk->type = type;
  103. return;
  104. }
  105. }
  106. // Otherwise create the field, and set the type. Assign a null value.
  107. addEntry( bucket, slotName, type );
  108. }
  109. U32 SimFieldDictionary::getFieldType(StringTableEntry slotName) const
  110. {
  111. U32 bucket = getHashValue( slotName );
  112. for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
  113. if( walk->slotName == slotName )
  114. return walk->type ? walk->type->getTypeID() : TypeString;
  115. return TypeString;
  116. }
  117. SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(const String &fieldName) const
  118. {
  119. U32 bucket = getHashValue( fieldName );
  120. for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
  121. {
  122. if( fieldName.equal(walk->slotName, String::NoCase) )
  123. return walk;
  124. }
  125. return NULL;
  126. }
  127. SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField( StringTableEntry fieldName) const
  128. {
  129. U32 bucket = getHashValue( fieldName );
  130. for( Entry *walk = mHashTable[bucket]; walk; walk = walk->next )
  131. {
  132. if( walk->slotName == fieldName )
  133. {
  134. return walk;
  135. }
  136. }
  137. return NULL;
  138. }
  139. void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
  140. {
  141. U32 bucket = getHashValue(slotName);
  142. Entry **walk = &mHashTable[bucket];
  143. while(*walk && (*walk)->slotName != slotName)
  144. walk = &((*walk)->next);
  145. Entry *field = *walk;
  146. if( !value || !*value )
  147. {
  148. if(field)
  149. {
  150. mVersion++;
  151. if( field->value )
  152. dFree(field->value);
  153. *walk = field->next;
  154. freeEntry(field);
  155. }
  156. }
  157. else
  158. {
  159. if(field)
  160. {
  161. if( field->value )
  162. dFree(field->value);
  163. field->value = dStrdup(value);
  164. }
  165. else
  166. addEntry( bucket, slotName, 0, dStrdup( value ) );
  167. }
  168. }
  169. const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
  170. {
  171. U32 bucket = getHashValue(slotName);
  172. for(Entry *walk = mHashTable[bucket];walk;walk = walk->next)
  173. if(walk->slotName == slotName)
  174. return walk->value;
  175. return NULL;
  176. }
  177. void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
  178. {
  179. mVersion++;
  180. for(U32 i = 0; i < HashTableSize; i++)
  181. {
  182. for(Entry *walk = dict->mHashTable[i];walk; walk = walk->next)
  183. {
  184. setFieldValue(walk->slotName, walk->value);
  185. setFieldType(walk->slotName, walk->type);
  186. }
  187. }
  188. }
  189. static S32 QSORT_CALLBACK compareEntries(const void* a,const void* b)
  190. {
  191. SimFieldDictionary::Entry *fa = *((SimFieldDictionary::Entry **)a);
  192. SimFieldDictionary::Entry *fb = *((SimFieldDictionary::Entry **)b);
  193. return dStricmp(fa->slotName, fb->slotName);
  194. }
  195. void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
  196. {
  197. const AbstractClassRep::FieldList &list = obj->getFieldList();
  198. Vector<Entry *> flist(__FILE__, __LINE__);
  199. for(U32 i = 0; i < HashTableSize; i++)
  200. {
  201. for(Entry *walk = mHashTable[i];walk; walk = walk->next)
  202. {
  203. // make sure we haven't written this out yet:
  204. U32 i;
  205. for(i = 0; i < list.size(); i++)
  206. if(list[i].pFieldname == walk->slotName)
  207. break;
  208. if(i != list.size())
  209. continue;
  210. if (!obj->writeField(walk->slotName, walk->value))
  211. continue;
  212. flist.push_back(walk);
  213. }
  214. }
  215. // Sort Entries to prevent version control conflicts
  216. dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
  217. // Save them out
  218. for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
  219. {
  220. U32 nBufferSize = (dStrlen( (*itr)->value ) * 2) + dStrlen( (*itr)->slotName ) + 16;
  221. FrameTemp<char> expandedBuffer( nBufferSize );
  222. stream.writeTabs(tabStop+1);
  223. const char *typeName = (*itr)->type && (*itr)->type->getTypeID() != TypeString ? (*itr)->type->getTypeName() : "";
  224. dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", (*itr)->slotName);
  225. if ( (*itr)->value )
  226. expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
  227. dStrcat(expandedBuffer, "\";\r\n");
  228. stream.write(dStrlen(expandedBuffer),expandedBuffer);
  229. }
  230. }
  231. void SimFieldDictionary::printFields(SimObject *obj)
  232. {
  233. const AbstractClassRep::FieldList &list = obj->getFieldList();
  234. char expandedBuffer[4096];
  235. Vector<Entry *> flist(__FILE__, __LINE__);
  236. for(U32 i = 0; i < HashTableSize; i++)
  237. {
  238. for(Entry *walk = mHashTable[i];walk; walk = walk->next)
  239. {
  240. // make sure we haven't written this out yet:
  241. U32 i;
  242. for(i = 0; i < list.size(); i++)
  243. if(list[i].pFieldname == walk->slotName)
  244. break;
  245. if(i != list.size())
  246. continue;
  247. flist.push_back(walk);
  248. }
  249. }
  250. dQsort(flist.address(),flist.size(),sizeof(Entry *),compareEntries);
  251. for(Vector<Entry *>::iterator itr = flist.begin(); itr != flist.end(); itr++)
  252. {
  253. const char* type = "string";
  254. if( ( *itr )->type )
  255. type = ( *itr )->type->getTypeClassName();
  256. dSprintf( expandedBuffer, sizeof( expandedBuffer ), " %s %s = \"", type, ( *itr )->slotName );
  257. if ( (*itr)->value )
  258. expandEscape(expandedBuffer + dStrlen(expandedBuffer), (*itr)->value);
  259. Con::printf("%s\"", expandedBuffer);
  260. }
  261. }
  262. SimFieldDictionary::Entry *SimFieldDictionary::operator[](U32 index)
  263. {
  264. AssertFatal ( index < mNumFields, "out of range" );
  265. if ( index > mNumFields )
  266. return NULL;
  267. SimFieldDictionaryIterator itr(this);
  268. for (S32 i = 0; i < index && *itr; i++)
  269. ++itr;
  270. return (*itr);
  271. }
  272. //------------------------------------------------------------------------------
  273. SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
  274. {
  275. mDictionary = dictionary;
  276. mHashIndex = -1;
  277. mEntry = 0;
  278. operator++();
  279. }
  280. SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
  281. {
  282. if(!mDictionary)
  283. return(mEntry);
  284. if(mEntry)
  285. mEntry = mEntry->next;
  286. while(!mEntry && (mHashIndex < (SimFieldDictionary::HashTableSize-1)))
  287. mEntry = mDictionary->mHashTable[++mHashIndex];
  288. return(mEntry);
  289. }
  290. SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
  291. {
  292. return(mEntry);
  293. }