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(!dStrcmp(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 table[e].string = (char *) allocator->alloc(dStrlen(string) + 1); 101 dStrcpy(table[e].string, string); 102 table[e].next = hashTable[bucket]; 103 hashTable[bucket] = e; 104 table[e].link = firstValid; 105 table[firstValid].prevLink = e; 106 firstValid = e; 107 table[e].prevLink = 0; 108 return e; 109} 110 111U32 GameAddTaggedString(const char *string) 112{ 113 return gNetStringTable->addString(string); 114} 115 116const char *NetStringTable::lookupString(U32 id) 117{ 118 if(table[id].refCount == 0 && table[id].scriptRefCount == 0) 119 return NULL; 120 return table[id].string; 121} 122 123void NetStringTable::removeString(U32 id, bool script) 124{ 125 if(!script) 126 { 127 AssertFatal(table[id].refCount != 0, "Error, ref count is already 0!!"); 128 if(--table[id].refCount) 129 return; 130 if(table[id].scriptRefCount) 131 return; 132 } 133 else 134 { 135 // If both ref counts are already 0, this id is not valid. Ignore 136 // the remove 137 if (table[id].scriptRefCount == 0 && table[id].refCount == 0) 138 return; 139 140 if(table[id].scriptRefCount == 0 && table[id].refCount) 141 { 142 Con::errorf("removeTaggedString failed! Ref count is already 0 for string: %s", table[id].string); 143 return; 144 } 145 if(--table[id].scriptRefCount) 146 return; 147 if(table[id].refCount) 148 return; 149 } 150 // unlink first: 151 U32 prev = table[id].prevLink; 152 U32 next = table[id].link; 153 if(next) 154 table[next].prevLink = prev; 155 if(prev) 156 table[prev].link = next; 157 else 158 firstValid = next; 159 // remove it from the hash table 160 U32 hash = _StringTable::hashString(table[id].string); 161 U32 bucket = hash % HashTableSize; 162 for(U32 *walk = &hashTable[bucket];*walk; walk = &table[*walk].next) 163 { 164 if(*walk == id) 165 { 166 *walk = table[id].next; 167 break; 168 } 169 } 170 table[id].next = firstFree; 171 firstFree = id; 172} 173 174void NetStringTable::repack() 175{ 176 DataChunker *newAllocator = new DataChunker(DataChunkerSize); 177 for(U32 walk = firstValid; walk; walk = table[walk].link) 178 { 179 const char *prevStr = table[walk].string; 180 181 182 table[walk].string = (char *) newAllocator->alloc(dStrlen(prevStr) + 1); 183 dStrcpy(table[walk].string, prevStr); 184 } 185 delete allocator; 186 allocator = newAllocator; 187} 188 189void NetStringTable::create() 190{ 191 AssertFatal(gNetStringTable == NULL, "Error, calling NetStringTable::create twice."); 192 gNetStringTable = new NetStringTable(); 193} 194 195void NetStringTable::destroy() 196{ 197 AssertFatal(gNetStringTable != NULL, "Error, not calling NetStringTable::create."); 198 delete gNetStringTable; 199 gNetStringTable = NULL; 200} 201 202void NetStringTable::expandString(NetStringHandle &inString, char *buf, U32 bufSize, U32 argc, const char **argv) 203{ 204 buf[0] = StringTagPrefixByte; 205 dSprintf(buf + 1, bufSize - 1, "%d ", inString.getIndex()); 206 207 const char *string = inString.getString(); 208 if (string != NULL) { 209 U32 index = dStrlen(buf); 210 while(index < bufSize) 211 { 212 char c = *string++; 213 if(c == '%') 214 { 215 c = *string++; 216 if(c >= '1' && c <= '9') 217 { 218 U32 strIndex = c - '1'; 219 if(strIndex >= argc) 220 continue; 221 // start copying out of arg index 222 const char *copy = argv[strIndex]; 223 // skip past any tags: 224 if(*copy == StringTagPrefixByte) 225 { 226 while(*copy && *copy != ' ') 227 copy++; 228 if(*copy) 229 copy++; 230 } 231 232 while(*copy && index < bufSize) 233 buf[index++] = *copy++; 234 continue; 235 } 236 } 237 buf[index++] = c; 238 if(!c) 239 break; 240 } 241 buf[bufSize - 1] = 0; 242 } else { 243 dStrcat(buf, "<NULL>"); 244 } 245} 246 247#ifdef TORQUE_DEBUG 248 249void NetStringTable::dumpToConsole() 250{ 251 U32 count = 0; 252 S32 maxIndex = -1; 253 for ( U32 i = 0; i < size; i++ ) 254 { 255 if ( table[i].refCount > 0 || table[i].scriptRefCount > 0) 256 { 257 Con::printf( "%d: \"%c%s%c\" REF: %d", i, 0x10, table[i].string, 0x11, table[i].refCount ); 258 if ( maxIndex == -1 || table[i].refCount > table[maxIndex].refCount ) 259 maxIndex = i; 260 count++; 261 } 262 } 263 Con::printf( ">> STRINGS: %d MAX REF COUNT: %d \"%c%s%c\" <<", 264 count, 265 ( maxIndex == -1 ) ? 0 : table[maxIndex].refCount, 266 0x10, 267 ( maxIndex == -1 ) ? "" : table[maxIndex].string, 268 0x11 ); 269} 270 271 272 273#endif // DEBUG 274 275 276DefineEngineFunction( dumpNetStringTable, void, (),, 277 "@brief Dump the current contents of the networked string table to the console.\n\n" 278 "The results are returned in three columns. The first column is the network string ID. " 279 "The second column is the string itself. The third column is the reference count to the " 280 "network string.\n\n" 281 "@note This function is available only in debug builds.\n\n" 282 "@ingroup Networking" ) 283{ 284#ifdef TORQUE_DEBUG 285 gNetStringTable->dumpToConsole(); 286#endif 287} 288 289
