simFieldDictionary.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "console/simFieldDictionary.h"
  28. #include "console/console.h"
  29. #include "console/consoleInternal.h"
  30. #include "core/frameAllocator.h"
  31. U32 SimFieldDictionary::getHashValue(StringTableEntry slotName)
  32. {
  33. return HashPointer(slotName) % HashTableSize;
  34. }
  35. U32 SimFieldDictionary::getHashValue(const String& fieldName)
  36. {
  37. return getHashValue(StringTable->insert(fieldName));
  38. }
  39. SimFieldDictionary::Entry *SimFieldDictionary::addEntry(U32 bucket, StringTableEntry slotName, ConsoleBaseType* type, char* value)
  40. {
  41. Entry ret;
  42. ret.slotName = slotName;
  43. ret.type = type;
  44. ret.value = value;
  45. mNumFields++;
  46. mVersion++;
  47. mHashTable[bucket].push_back(std::move(ret));
  48. return &mHashTable[bucket].back();
  49. }
  50. void SimFieldDictionary::freeEntry(SimFieldDictionary::Entry *ent)
  51. {
  52. auto &vec = mHashTable[getHashValue(ent->slotName)];
  53. // Find the slot.
  54. auto iter = std::find_if(vec.begin(), vec.end(), [&](const Entry &ref) -> bool {
  55. return ref.slotName == ent->slotName;
  56. });
  57. if (iter != vec.end())
  58. {
  59. vec.erase(iter);
  60. mNumFields--;
  61. }
  62. }
  63. SimFieldDictionary::SimFieldDictionary()
  64. : mNumFields(0),
  65. mVersion(0)
  66. {
  67. }
  68. SimFieldDictionary::~SimFieldDictionary()
  69. {
  70. }
  71. void SimFieldDictionary::setFieldType(StringTableEntry slotName, const char *typeString)
  72. {
  73. ConsoleBaseType *cbt = ConsoleBaseType::getTypeByName(typeString);
  74. setFieldType(slotName, cbt);
  75. }
  76. void SimFieldDictionary::setFieldType(StringTableEntry slotName, const U32 typeId)
  77. {
  78. ConsoleBaseType *cbt = ConsoleBaseType::getType(typeId);
  79. setFieldType(slotName, cbt);
  80. }
  81. void SimFieldDictionary::setFieldType(StringTableEntry slotName, ConsoleBaseType *type)
  82. {
  83. // If the field exists on the object, set the type
  84. U32 bucket = getHashValue(slotName);
  85. for (Entry &ref : mHashTable[bucket])
  86. {
  87. if (ref.slotName == slotName)
  88. {
  89. // Found and type assigned, let's bail
  90. ref.type = type;
  91. return;
  92. }
  93. }
  94. // Otherwise create the field, and set the type. Assign a null value.
  95. addEntry(bucket, slotName, type);
  96. }
  97. U32 SimFieldDictionary::getFieldType(StringTableEntry slotName) const
  98. {
  99. U32 bucket = getHashValue(slotName);
  100. const std::vector<Entry> &vec = mHashTable[bucket];
  101. size_t size = vec.size();
  102. for (size_t i = 0; i < size; ++i)
  103. {
  104. const Entry &ref = vec[i];
  105. if (ref.slotName == slotName)
  106. return ref.type ? ref.type->getTypeID() : TypeString;
  107. }
  108. return TypeString;
  109. }
  110. SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(const String &fieldName) const
  111. {
  112. U32 bucket = getHashValue(fieldName);
  113. const std::vector<Entry> &vec = mHashTable[bucket];
  114. size_t size = vec.size();
  115. for (size_t i = 0; i < size; ++i)
  116. {
  117. const Entry &ref = vec[i];
  118. if (fieldName.equal(ref.slotName, String::NoCase))
  119. return const_cast<Entry*>(&ref);
  120. }
  121. return NULL;
  122. }
  123. SimFieldDictionary::Entry *SimFieldDictionary::findDynamicField(StringTableEntry fieldName) const
  124. {
  125. U32 bucket = getHashValue(fieldName);
  126. const std::vector<Entry> &vec = mHashTable[bucket];
  127. size_t size = vec.size();
  128. for (size_t i = 0; i < size; ++i)
  129. {
  130. if (vec[i].slotName == fieldName)
  131. {
  132. return const_cast<Entry*>(&vec[i]);
  133. }
  134. }
  135. return NULL;
  136. }
  137. void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value)
  138. {
  139. U32 bucket = getHashValue(slotName);
  140. for (Entry &ref : mHashTable[bucket])
  141. {
  142. if (ref.slotName == slotName)
  143. {
  144. if (!value || !*value)
  145. {
  146. mVersion++;
  147. if (ref.value)
  148. dFree(ref.value);
  149. freeEntry(&ref);
  150. }
  151. else
  152. {
  153. if (ref.value)
  154. dFree(ref.value);
  155. ref.value = dStrdup(value);
  156. }
  157. return;
  158. }
  159. }
  160. // no field, add entry.
  161. addEntry(bucket, slotName, 0, dStrdup(value));
  162. }
  163. const char *SimFieldDictionary::getFieldValue(StringTableEntry slotName)
  164. {
  165. U32 bucket = getHashValue(slotName);
  166. for (const Entry &ref : mHashTable[bucket])
  167. if (ref.slotName == slotName)
  168. return ref.value;
  169. return NULL;
  170. }
  171. void SimFieldDictionary::assignFrom(SimFieldDictionary *dict)
  172. {
  173. mVersion++;
  174. for (U32 i = 0; i < HashTableSize; i++)
  175. {
  176. for (const Entry &ref : mHashTable[i])
  177. {
  178. setFieldValue(ref.slotName, ref.value);
  179. setFieldType(ref.slotName, ref.type);
  180. }
  181. }
  182. }
  183. static S32 QSORT_CALLBACK compareEntries(const void* a, const void* b)
  184. {
  185. const SimFieldDictionary::Entry *fa = reinterpret_cast<const SimFieldDictionary::Entry*>(a);
  186. const SimFieldDictionary::Entry *fb = reinterpret_cast<const SimFieldDictionary::Entry*>(b);
  187. return dStricmp(fa->slotName, fb->slotName);
  188. }
  189. void SimFieldDictionary::writeFields(SimObject *obj, Stream &stream, U32 tabStop)
  190. {
  191. const AbstractClassRep::FieldList &list = obj->getFieldList();
  192. Vector<Entry> flist(__FILE__, __LINE__);
  193. for (U32 i = 0; i < HashTableSize; i++)
  194. {
  195. for (const Entry &walk : mHashTable[i])
  196. {
  197. // make sure we haven't written this out yet:
  198. U32 j;
  199. for (j = 0; j < list.size(); j++)
  200. if (list[j].pFieldname == walk.slotName)
  201. break;
  202. if (j != list.size())
  203. continue;
  204. if (!obj->writeField(walk.slotName, walk.value))
  205. continue;
  206. flist.push_back(walk);
  207. }
  208. }
  209. // Sort Entries to prevent version control conflicts
  210. dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
  211. // Save them out
  212. for (const Entry &ref : flist)
  213. {
  214. U32 nBufferSize = (dStrlen(ref.value) * 2) + dStrlen(ref.slotName) + 16;
  215. FrameTemp<char> expandedBuffer(nBufferSize);
  216. stream.writeTabs(tabStop + 1);
  217. const char *typeName = ref.type && ref.type->getTypeID() != TypeString ? ref.type->getTypeName() : "";
  218. dSprintf(expandedBuffer, nBufferSize, "%s%s%s = \"", typeName, *typeName ? " " : "", ref.slotName);
  219. if (ref.value)
  220. expandEscape((char*)expandedBuffer + dStrlen(expandedBuffer), ref.value);
  221. dStrcat(expandedBuffer, "\";\r\n");
  222. stream.write(dStrlen(expandedBuffer), expandedBuffer);
  223. }
  224. }
  225. void SimFieldDictionary::printFields(SimObject *obj)
  226. {
  227. const AbstractClassRep::FieldList &list = obj->getFieldList();
  228. char expandedBuffer[4096];
  229. Vector<Entry> flist(__FILE__, __LINE__);
  230. for (U32 i = 0; i < HashTableSize; i++)
  231. {
  232. for (const Entry &walk : mHashTable[i])
  233. {
  234. // make sure we haven't written this out yet:
  235. U32 j;
  236. for (j = 0; j < list.size(); j++)
  237. if (list[i].pFieldname == walk.slotName)
  238. break;
  239. if (j != list.size())
  240. continue;
  241. flist.push_back(walk);
  242. }
  243. }
  244. dQsort(flist.address(), flist.size(), sizeof(Entry), compareEntries);
  245. for (const Entry &ref : flist)
  246. {
  247. const char* type = "string";
  248. if (ref.type)
  249. type = ref.type->getTypeClassName();
  250. dSprintf(expandedBuffer, sizeof(expandedBuffer), " %s %s = \"", type, ref.slotName);
  251. if (ref.value)
  252. expandEscape(expandedBuffer + dStrlen(expandedBuffer), ref.value);
  253. Con::printf("%s\"", expandedBuffer);
  254. }
  255. }
  256. SimFieldDictionary::Entry *SimFieldDictionary::operator[](U32 index)
  257. {
  258. AssertFatal(index < mNumFields, "out of range");
  259. if (index > mNumFields)
  260. return NULL;
  261. SimFieldDictionaryIterator itr(this);
  262. for (S32 i = 0; i < index && *itr; i++)
  263. ++itr;
  264. return (*itr);
  265. }
  266. //------------------------------------------------------------------------------
  267. SimFieldDictionaryIterator::SimFieldDictionaryIterator(SimFieldDictionary * dictionary)
  268. {
  269. mDictionary = dictionary;
  270. mHashIndex = 0;
  271. mVecIndex = -1; // -1 since we immediately call operator++
  272. mEntry = NULL;
  273. operator++();
  274. }
  275. SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator++()
  276. {
  277. if (!mDictionary || mHashIndex >= SimFieldDictionary::HashTableSize)
  278. {
  279. mEntry = NULL;
  280. return NULL;
  281. }
  282. std::vector<SimFieldDictionary::Entry> &vec = mDictionary->mHashTable[mHashIndex];
  283. while (vec.size() == 0 && mHashIndex < (SimFieldDictionary::HashTableSize - 1))
  284. {
  285. vec = mDictionary->mHashTable[++mHashIndex];
  286. mVecIndex = 0;
  287. }
  288. if (mVecIndex >= vec.size() || mHashIndex >= SimFieldDictionary::HashTableSize)
  289. {
  290. mEntry = NULL;
  291. return NULL;
  292. }
  293. mEntry = &vec[mVecIndex];
  294. ++mVecIndex;
  295. return mEntry;
  296. }
  297. SimFieldDictionary::Entry* SimFieldDictionaryIterator::operator*()
  298. {
  299. return mEntry;
  300. }
  301. // A variation of the stock SimFieldDictionary::setFieldValue(), this method adds the
  302. // <no_replace> argument which, when true, prohibits the replacement of fields that
  303. // already have a value.
  304. //
  305. // AFX uses this when an effects-choreographer (afxMagicSpell, afxEffectron) is created
  306. // using the new operator. It prevents any in-line effect parameters from being overwritten
  307. // by default parameters that are copied over later.
  308. void SimFieldDictionary::setFieldValue(StringTableEntry slotName, const char *value, ConsoleBaseType *type, bool no_replace)
  309. {
  310. if (!no_replace)
  311. {
  312. setFieldValue(slotName, value);
  313. return;
  314. }
  315. if (!value || !*value)
  316. return;
  317. U32 bucket = getHashValue(slotName);
  318. for (const Entry &walk : mHashTable[bucket])
  319. {
  320. if (walk.slotName == slotName)
  321. {
  322. return;
  323. }
  324. }
  325. addEntry(bucket, slotName, type, dStrdup(value));
  326. }
  327. // A variation of the stock SimFieldDictionary::assignFrom(), this method adds <no_replace>
  328. // and <filter> arguments. When true, <no_replace> prohibits the replacement of fields that already
  329. // have a value. When <filter> is specified, only fields with leading characters that exactly match
  330. // the characters in <filter> are copied.
  331. void SimFieldDictionary::assignFrom(SimFieldDictionary *dict, const char* filter, bool no_replace)
  332. {
  333. dsize_t filter_len = (filter) ? dStrlen(filter) : 0;
  334. if (filter_len == 0 && !no_replace)
  335. {
  336. assignFrom(dict);
  337. return;
  338. }
  339. mVersion++;
  340. if (filter_len == 0)
  341. {
  342. for (U32 i = 0; i < HashTableSize; i++)
  343. {
  344. for (const Entry &walk : dict->mHashTable[i])
  345. {
  346. setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
  347. }
  348. }
  349. }
  350. else
  351. {
  352. for (U32 i = 0; i < HashTableSize; i++)
  353. {
  354. for (const Entry &walk : dict->mHashTable[i])
  355. {
  356. if (dStrncmp(walk.slotName, filter, filter_len) == 0)
  357. setFieldValue(walk.slotName, walk.value, walk.type, no_replace);
  358. }
  359. }
  360. }
  361. }