simFieldDictionary.cpp
Engine/source/console/simFieldDictionary.cpp
Public Variables
Public Functions
compareEntries(const void * a, const void * b)
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