NameKeyGenerator.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: NameKeyGenerator.cpp /////////////////////////////////////////////////////////////////////
  24. // Created: Michael Booth, May 2001
  25. // Colin Day, May 2001
  26. // Desc: Name key system to translate between names and unique key ids
  27. ///////////////////////////////////////////////////////////////////////////////////////////////////
  28. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  29. // Public Data ////////////////////////////////////////////////////////////////////////////////////
  30. NameKeyGenerator *TheNameKeyGenerator = NULL; ///< name key gen. singleton
  31. //-------------------------------------------------------------------------------------------------
  32. NameKeyGenerator::NameKeyGenerator()
  33. {
  34. m_nextID = (UnsignedInt)NAMEKEY_INVALID; // uninitialized system
  35. for (Int i = 0; i < SOCKET_COUNT; ++i)
  36. m_sockets[i] = NULL;
  37. } // end NameKeyGenerator
  38. //-------------------------------------------------------------------------------------------------
  39. NameKeyGenerator::~NameKeyGenerator()
  40. {
  41. // free all system data
  42. freeSockets();
  43. } // end ~NameKeyGenerator
  44. //-------------------------------------------------------------------------------------------------
  45. void NameKeyGenerator::init()
  46. {
  47. DEBUG_ASSERTCRASH(m_nextID == (UnsignedInt)NAMEKEY_INVALID, ("NameKeyGen already inited"));
  48. // start keys at the beginning again
  49. freeSockets();
  50. m_nextID = 1;
  51. } // end init
  52. //-------------------------------------------------------------------------------------------------
  53. void NameKeyGenerator::reset()
  54. {
  55. freeSockets();
  56. m_nextID = 1;
  57. } // end reset
  58. //-------------------------------------------------------------------------------------------------
  59. void NameKeyGenerator::freeSockets()
  60. {
  61. for (Int i = 0; i < SOCKET_COUNT; ++i)
  62. {
  63. Bucket *next;
  64. for (Bucket *b = m_sockets[i]; b; b = next)
  65. {
  66. next = b->m_nextInSocket;
  67. b->deleteInstance();
  68. }
  69. m_sockets[i] = NULL;
  70. }
  71. } // end freeSockets
  72. /* ------------------------------------------------------------------------ */
  73. inline UnsignedInt calcHashForString(const char* p)
  74. {
  75. UnsignedInt result = 0;
  76. Byte *pp = (Byte*)p;
  77. while (*pp)
  78. result = (result << 5) + result + *pp++;
  79. return result;
  80. }
  81. /* ------------------------------------------------------------------------ */
  82. inline UnsignedInt calcHashForLowercaseString(const char* p)
  83. {
  84. UnsignedInt result = 0;
  85. Byte *pp = (Byte*)p;
  86. while (*pp)
  87. result = (result << 5) + result + tolower(*pp++);
  88. return result;
  89. }
  90. //-------------------------------------------------------------------------------------------------
  91. AsciiString NameKeyGenerator::keyToName(NameKeyType key)
  92. {
  93. for (Int i = 0; i < SOCKET_COUNT; ++i)
  94. {
  95. for (Bucket *b = m_sockets[i]; b; b = b->m_nextInSocket)
  96. {
  97. if (key == b->m_key)
  98. return b->m_nameString;
  99. }
  100. }
  101. return AsciiString::TheEmptyString;
  102. }
  103. //-------------------------------------------------------------------------------------------------
  104. NameKeyType NameKeyGenerator::nameToKey(const char* nameString)
  105. {
  106. Bucket *b;
  107. UnsignedInt hash = calcHashForString(nameString) % SOCKET_COUNT;
  108. // hmm, do we have it already?
  109. for (b = m_sockets[hash]; b; b = b->m_nextInSocket)
  110. {
  111. if (strcmp(nameString, b->m_nameString.str()) == 0)
  112. return b->m_key;
  113. }
  114. // nope, guess not. let's allocate it.
  115. b = newInstance(Bucket);
  116. b->m_key = (NameKeyType)m_nextID++;
  117. b->m_nameString = nameString;
  118. b->m_nextInSocket = m_sockets[hash];
  119. m_sockets[hash] = b;
  120. NameKeyType result = b->m_key;
  121. #if defined(_DEBUG) || defined(_INTERNAL)
  122. // reality-check to be sure our hasher isn't going bad.
  123. const Int maxThresh = 3;
  124. Int numOverThresh = 0;
  125. for (Int i = 0; i < SOCKET_COUNT; ++i)
  126. {
  127. Int numInThisSocket = 0;
  128. for (b = m_sockets[i]; b; b = b->m_nextInSocket)
  129. ++numInThisSocket;
  130. if (numInThisSocket > maxThresh)
  131. ++numOverThresh;
  132. }
  133. // if more than a small percent of the sockets are getting deep, probably want to increase the socket count.
  134. if (numOverThresh > SOCKET_COUNT/20)
  135. {
  136. DEBUG_CRASH(("hmm, might need to increase the number of bucket-sockets for NameKeyGenerator (numOverThresh %d = %f%%)\n",numOverThresh,(Real)numOverThresh/(Real)(SOCKET_COUNT/20)));
  137. }
  138. #endif
  139. return result;
  140. } // end nameToKey
  141. //-------------------------------------------------------------------------------------------------
  142. NameKeyType NameKeyGenerator::nameToLowercaseKey(const char* nameString)
  143. {
  144. Bucket *b;
  145. UnsignedInt hash = calcHashForLowercaseString(nameString) % SOCKET_COUNT;
  146. // hmm, do we have it already?
  147. for (b = m_sockets[hash]; b; b = b->m_nextInSocket)
  148. {
  149. if (_stricmp(nameString, b->m_nameString.str()) == 0)
  150. return b->m_key;
  151. }
  152. // nope, guess not. let's allocate it.
  153. b = newInstance(Bucket);
  154. b->m_key = (NameKeyType)m_nextID++;
  155. b->m_nameString = nameString;
  156. b->m_nextInSocket = m_sockets[hash];
  157. m_sockets[hash] = b;
  158. NameKeyType result = b->m_key;
  159. #if defined(_DEBUG) || defined(_INTERNAL)
  160. // reality-check to be sure our hasher isn't going bad.
  161. const Int maxThresh = 3;
  162. Int numOverThresh = 0;
  163. for (Int i = 0; i < SOCKET_COUNT; ++i)
  164. {
  165. Int numInThisSocket = 0;
  166. for (b = m_sockets[i]; b; b = b->m_nextInSocket)
  167. ++numInThisSocket;
  168. if (numInThisSocket > maxThresh)
  169. ++numOverThresh;
  170. }
  171. // if more than a small percent of the sockets are getting deep, probably want to increase the socket count.
  172. if (numOverThresh > SOCKET_COUNT/20)
  173. {
  174. DEBUG_CRASH(("hmm, might need to increase the number of bucket-sockets for NameKeyGenerator (numOverThresh %d = %f%%)\n",numOverThresh,(Real)numOverThresh/(Real)(SOCKET_COUNT/20)));
  175. }
  176. #endif
  177. return result;
  178. } // end nameToLowercaseKey
  179. //-------------------------------------------------------------------------------------------------
  180. // Get a string out of the INI. Store it into a NameKeyType
  181. //-------------------------------------------------------------------------------------------------
  182. void NameKeyGenerator::parseStringAsNameKeyType( INI *ini, void *instance, void *store, const void* userData )
  183. {
  184. *(NameKeyType *)store = TheNameKeyGenerator->nameToKey( ini->getNextToken() );
  185. }
  186. //-------------------------------------------------------------------------------------------------
  187. NameKeyType StaticNameKey::key() const
  188. {
  189. if (m_key == NAMEKEY_INVALID)
  190. {
  191. DEBUG_ASSERTCRASH(TheNameKeyGenerator, ("no TheNameKeyGenerator yet"));
  192. if (TheNameKeyGenerator)
  193. m_key = TheNameKeyGenerator->nameToKey(m_name);
  194. }
  195. return m_key;
  196. }