Torque3D Documentation / _generateds / stringTable.cpp

stringTable.cpp

Engine/source/core/stringTable.cpp

More...

Public Variables

Detailed Description

Public Variables

_StringTable * _gStringTable 
  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/strings/stringFunctions.h"
 25#include "core/stringTable.h"
 26#include "platform/profiler.h"
 27
 28_StringTable *_gStringTable = NULL;
 29const U32 _StringTable::csm_stInitSize = 29;
 30
 31//---------------------------------------------------------------
 32//
 33// StringTable functions
 34//
 35//---------------------------------------------------------------
 36
 37namespace {
 38bool sgInitTable = true;
 39U8   sgHashTable[256];
 40
 41void initTolowerTable()
 42{
 43   for (U32 i = 0; i < 256; i++) {
 44      U8 c = dTolower(i);
 45      sgHashTable[i] = c * c;
 46   }
 47
 48   sgInitTable = false;
 49}
 50
 51} // namespace {}
 52
 53U32 _StringTable::hashString(const char* str)
 54{
 55   if (sgInitTable)
 56      initTolowerTable();
 57
 58   if(!str) return -1;
 59
 60   U32 ret = 0;
 61   char c;
 62   while((c = *str++) != 0) {
 63      ret <<= 1;
 64      ret ^= sgHashTable[static_cast<U8>(c)];
 65   }
 66   return ret;
 67}
 68
 69U32 _StringTable::hashStringn(const char* str, S32 len)
 70{
 71   if (sgInitTable)
 72      initTolowerTable();
 73
 74   U32 ret = 0;
 75   char c;
 76   while((c = *str++) != 0 && len--) {
 77      ret <<= 1;
 78      ret ^= sgHashTable[static_cast<U8>(c)];
 79   }
 80   return ret;
 81}
 82
 83//--------------------------------------
 84_StringTable::_StringTable()
 85{
 86   buckets = (Node **) dMalloc(csm_stInitSize * sizeof(Node *));
 87   for(U32 i = 0; i < csm_stInitSize; i++) {
 88      buckets[i] = 0;
 89   }
 90
 91   numBuckets = csm_stInitSize;
 92   itemCount = 0;
 93}
 94
 95//--------------------------------------
 96_StringTable::~_StringTable()
 97{
 98   dFree(buckets);
 99}
100
101
102//--------------------------------------
103void _StringTable::create()
104{
105   //AssertFatal(_gStringTable == NULL, "StringTable::create: StringTable already exists.");
106   if(!_gStringTable)
107   {
108      _gStringTable = new _StringTable;
109      _gStringTable->_EmptyString = _gStringTable->insert("");
110   }
111}
112
113
114//--------------------------------------
115void _StringTable::destroy()
116{
117   AssertFatal(StringTable != NULL, "StringTable::destroy: StringTable does not exist.");
118   delete _gStringTable;
119   _gStringTable = NULL;
120}
121
122
123//--------------------------------------
124StringTableEntry _StringTable::insert(const char* _val, const bool caseSens)
125{
126   PROFILE_SCOPE(StringTableInsert);
127
128   // Added 3/29/2007 -- If this is undesirable behavior, let me know -patw
129   const char *val = _val;
130   if( val == NULL )
131      val = "";
132   //-
133
134   Node **walk, *temp;
135   U32 key = hashString(val);
136   walk = &buckets[key % numBuckets];
137   while((temp = *walk) != NULL)   {
138      if(caseSens && !dStrcmp(temp->val, val))
139         return temp->val;
140      else if(!caseSens && !dStricmp(temp->val, val))
141         return temp->val;
142      walk = &(temp->next);
143   }
144   char *ret = 0;
145   if(!*walk) {
146      *walk = (Node *) mempool.alloc(sizeof(Node));
147      (*walk)->next = 0;
148      (*walk)->val = (char *) mempool.alloc(dStrlen(val) + 1);
149      dStrcpy((*walk)->val, val);
150      ret = (*walk)->val;
151      itemCount ++;
152   }
153   if(itemCount > 2 * numBuckets) {
154      resize(4 * numBuckets - 1);
155   }
156   return ret;
157}
158
159//--------------------------------------
160StringTableEntry _StringTable::insertn(const char* src, S32 len, const bool  caseSens)
161{
162   char val[256];
163   AssertFatal(len < 255, "Invalid string to insertn");
164   dStrncpy(val, src, len);
165   val[len] = 0;
166   return insert(val, caseSens);
167}
168
169//--------------------------------------
170StringTableEntry _StringTable::lookup(const char* val, const bool  caseSens)
171{
172   PROFILE_SCOPE(StringTableLookup);
173
174   Node **walk, *temp;
175   U32 key = hashString(val);
176   walk = &buckets[key % numBuckets];
177   while((temp = *walk) != NULL)   {
178      if(caseSens && !dStrcmp(temp->val, val))
179            return temp->val;
180      else if(!caseSens && !dStricmp(temp->val, val))
181         return temp->val;
182      walk = &(temp->next);
183   }
184   return NULL;
185}
186
187//--------------------------------------
188StringTableEntry _StringTable::lookupn(const char* val, S32 len, const bool  caseSens)
189{
190   PROFILE_SCOPE(StringTableLookupN);
191
192   Node **walk, *temp;
193   U32 key = hashStringn(val, len);
194   walk = &buckets[key % numBuckets];
195   while((temp = *walk) != NULL) {
196      if(caseSens && !dStrncmp(temp->val, val, len) && temp->val[len] == 0)
197         return temp->val;
198      else if(!caseSens && !dStrnicmp(temp->val, val, len) && temp->val[len] == 0)
199         return temp->val;
200      walk = &(temp->next);
201   }
202   return NULL;
203}
204
205//--------------------------------------
206void _StringTable::resize(const U32 _newSize)
207{
208   /// avoid a possible 0 division
209   const U32 newSize = _newSize ? _newSize : 1;
210
211   Node *head = NULL, *walk, *temp;
212   U32 i;
213   // reverse individual bucket lists
214   // we do this because new strings are added at the end of bucket
215   // lists so that case sens strings are always after their
216   // corresponding case insens strings
217
218   for(i = 0; i < numBuckets; i++) {
219      walk = buckets[i];
220      while(walk)
221      {
222         temp = walk->next;
223         walk->next = head;
224         head = walk;
225         walk = temp;
226      }
227   }
228   buckets = (Node **) dRealloc(buckets, newSize * sizeof(Node));
229   for(i = 0; i < newSize; i++) {
230      buckets[i] = 0;
231   }
232   numBuckets = newSize;
233   walk = head;
234   while(walk) {
235      U32 key;
236      Node *temp = walk;
237
238      walk = walk->next;
239      key = hashString(temp->val);
240      temp->next = buckets[key % newSize];
241      buckets[key % newSize] = temp;
242   }
243}
244
245