netStringTable.cpp
Engine/source/sim/netStringTable.cpp
Public Variables
Public Functions
DefineEngineFunction(dumpNetStringTable , void , () , "@brief Dump the current contents of the networked string table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "The results are returned in three columns. The first column is the network string ID. " "The second column is the string itself. The third column is the reference <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1ad43c3812e6d13e0518d9f8b8f463ffcf">count</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the " "network <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n\n</a>" "@note This function is available only in debug <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">builds.\n\n</a>" "@ingroup Networking" )
GameAddTaggedString(const char * string)
Detailed Description
Public Variables
NetStringTable * gNetStringTable
Public Functions
DefineEngineFunction(dumpNetStringTable , void , () , "@brief Dump the current contents of the networked string table <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "The results are returned in three columns. The first column is the network string ID. " "The second column is the string itself. The third column is the reference <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1ad43c3812e6d13e0518d9f8b8f463ffcf">count</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the " "network <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">string.\n\n</a>" "@note This function is available only in debug <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">builds.\n\n</a>" "@ingroup Networking" )
GameAddTaggedString(const char * string)
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#include "core/dnet.h" 25#include "core/strings/stringFunctions.h" 26#include "core/stringTable.h" 27#include "console/engineAPI.h" 28#include "sim/netStringTable.h" 29 30 31NetStringTable *gNetStringTable = NULL; 32 33NetStringTable::NetStringTable() 34{ 35 firstFree = 1; 36 firstValid = 1; 37 38 table = (Entry *) dMalloc(sizeof(Entry) * InitialSize); 39 size = InitialSize; 40 for(U32 i = 0; i < InitialSize; i++) 41 { 42 table[i].next = i + 1; 43 table[i].refCount = 0; 44 table[i].scriptRefCount = 0; 45 } 46 table[InitialSize-1].next = InvalidEntry; 47 for(U32 j = 0; j < HashTableSize; j++) 48 hashTable[j] = 0; 49 allocator = new DataChunker(DataChunkerSize); 50} 51 52NetStringTable::~NetStringTable() 53{ 54 delete allocator; 55 dFree( table ); 56} 57 58void NetStringTable::incStringRef(U32 id) 59{ 60 AssertFatal(table[id].refCount != 0 || table[id].scriptRefCount != 0 , "Cannot inc ref count from zero."); 61 table[id].refCount++; 62} 63 64void NetStringTable::incStringRefScript(U32 id) 65{ 66 AssertFatal(table[id].refCount != 0 || table[id].scriptRefCount != 0 , "Cannot inc ref count from zero."); 67 table[id].scriptRefCount++; 68} 69 70U32 NetStringTable::addString(const char *string) 71{ 72 U32 hash = _StringTable::hashString(string); 73 U32 bucket = hash % HashTableSize; 74 for(U32 walk = hashTable[bucket];walk; walk = table[walk].next) 75 { 76 if(!String::compare(table[walk].string, string)) 77 { 78 table[walk].refCount++; 79 return walk; 80 } 81 } 82 U32 e = firstFree; 83 firstFree = table[e].next; 84 if(firstFree == InvalidEntry) 85 { 86 // in this case, we should expand the table for next time... 87 U32 newSize = size * 2; 88 table = (Entry *) dRealloc(table, newSize * sizeof(Entry)); 89 for(U32 i = size; i < newSize; i++) 90 { 91 table[i].next = i + 1; 92 table[i].refCount = 0; 93 table[i].scriptRefCount = 0; 94 } 95 firstFree = size; 96 table[newSize - 1].next = InvalidEntry; 97 size = newSize; 98 } 99 table[e].refCount++; 100 dsize_t stringLen = dStrlen(string) + 1; 101 table[e].string = (char *) allocator->alloc(stringLen); 102 dStrcpy(table[e].string, string, stringLen); 103 table[e].next = hashTable[bucket]; 104 hashTable[bucket] = e; 105 table[e].link = firstValid; 106 table[firstValid].prevLink = e; 107 firstValid = e; 108 table[e].prevLink = 0; 109 return e; 110} 111 112U32 GameAddTaggedString(const char *string) 113{ 114 return gNetStringTable->addString(string); 115} 116 117const char *NetStringTable::lookupString(U32 id) 118{ 119 if(table[id].refCount == 0 && table[id].scriptRefCount == 0) 120 return NULL; 121 return table[id].string; 122} 123 124void NetStringTable::removeString(U32 id, bool script) 125{ 126 if(!script) 127 { 128 AssertFatal(table[id].refCount != 0, "Error, ref count is already 0!!"); 129 if(--table[id].refCount) 130 return; 131 if(table[id].scriptRefCount) 132 return; 133 } 134 else 135 { 136 // If both ref counts are already 0, this id is not valid. Ignore 137 // the remove 138 if (table[id].scriptRefCount == 0 && table[id].refCount == 0) 139 return; 140 141 if(table[id].scriptRefCount == 0 && table[id].refCount) 142 { 143 Con::errorf("removeTaggedString failed! Ref count is already 0 for string: %s", table[id].string); 144 return; 145 } 146 if(--table[id].scriptRefCount) 147 return; 148 if(table[id].refCount) 149 return; 150 } 151 // unlink first: 152 U32 prev = table[id].prevLink; 153 U32 next = table[id].link; 154 if(next) 155 table[next].prevLink = prev; 156 if(prev) 157 table[prev].link = next; 158 else 159 firstValid = next; 160 // remove it from the hash table 161 U32 hash = _StringTable::hashString(table[id].string); 162 U32 bucket = hash % HashTableSize; 163 for(U32 *walk = &hashTable[bucket];*walk; walk = &table[*walk].next) 164 { 165 if(*walk == id) 166 { 167 *walk = table[id].next; 168 break; 169 } 170 } 171 table[id].next = firstFree; 172 firstFree = id; 173} 174 175void NetStringTable::repack() 176{ 177 DataChunker *newAllocator = new DataChunker(DataChunkerSize); 178 for(U32 walk = firstValid; walk; walk = table[walk].link) 179 { 180 const char *prevStr = table[walk].string; 181 182 183 dsize_t prevStrLen = dStrlen(prevStr) + 1; 184 table[walk].string = (char *) newAllocator->alloc(prevStrLen); 185 dStrcpy(table[walk].string, prevStr, prevStrLen); 186 } 187 delete allocator; 188 allocator = newAllocator; 189} 190 191void NetStringTable::create() 192{ 193 AssertFatal(gNetStringTable == NULL, "Error, calling NetStringTable::create twice."); 194 gNetStringTable = new NetStringTable(); 195} 196 197void NetStringTable::destroy() 198{ 199 AssertFatal(gNetStringTable != NULL, "Error, not calling NetStringTable::create."); 200 delete gNetStringTable; 201 gNetStringTable = NULL; 202} 203 204void NetStringTable::expandString(NetStringHandle &inString, char *buf, U32 bufSize, U32 argc, const char **argv) 205{ 206 buf[0] = StringTagPrefixByte; 207 dSprintf(buf + 1, bufSize - 1, "%d ", inString.getIndex()); 208 209 const char *string = inString.getString(); 210 if (string != NULL) { 211 U32 index = dStrlen(buf); 212 while(index < bufSize) 213 { 214 char c = *string++; 215 if(c == '%') 216 { 217 c = *string++; 218 if(c >= '1' && c <= '9') 219 { 220 U32 strIndex = c - '1'; 221 if(strIndex >= argc) 222 continue; 223 // start copying out of arg index 224 const char *copy = argv[strIndex]; 225 // skip past any tags: 226 if(*copy == StringTagPrefixByte) 227 { 228 while(*copy && *copy != ' ') 229 copy++; 230 if(*copy) 231 copy++; 232 } 233 234 while(*copy && index < bufSize) 235 buf[index++] = *copy++; 236 continue; 237 } 238 } 239 buf[index++] = c; 240 if(!c) 241 break; 242 } 243 buf[bufSize - 1] = 0; 244 } else { 245 dStrcat(buf, "<NULL>", bufSize); 246 } 247} 248 249#ifdef TORQUE_DEBUG 250 251void NetStringTable::dumpToConsole() 252{ 253 U32 count = 0; 254 S32 maxIndex = -1; 255 for ( U32 i = 0; i < size; i++ ) 256 { 257 if ( table[i].refCount > 0 || table[i].scriptRefCount > 0) 258 { 259 Con::printf( "%d: \"%c%s%c\" REF: %d", i, 0x10, table[i].string, 0x11, table[i].refCount ); 260 if ( maxIndex == -1 || table[i].refCount > table[maxIndex].refCount ) 261 maxIndex = i; 262 count++; 263 } 264 } 265 Con::printf( ">> STRINGS: %d MAX REF COUNT: %d \"%c%s%c\" <<", 266 count, 267 ( maxIndex == -1 ) ? 0 : table[maxIndex].refCount, 268 0x10, 269 ( maxIndex == -1 ) ? "" : table[maxIndex].string, 270 0x11 ); 271} 272 273 274 275#endif // DEBUG 276 277 278DefineEngineFunction( dumpNetStringTable, void, (),, 279 "@brief Dump the current contents of the networked string table to the console.\n\n" 280 "The results are returned in three columns. The first column is the network string ID. " 281 "The second column is the string itself. The third column is the reference count to the " 282 "network string.\n\n" 283 "@note This function is available only in debug builds.\n\n" 284 "@ingroup Networking" ) 285{ 286#ifdef TORQUE_DEBUG 287 gNetStringTable->dumpToConsole(); 288#endif 289} 290 291