NameKeyGenerator.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. ** Command & Conquer Generals(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. AsciiString NameKeyGenerator::keyToName(NameKeyType key)
  83. {
  84. for (Int i = 0; i < SOCKET_COUNT; ++i)
  85. {
  86. for (Bucket *b = m_sockets[i]; b; b = b->m_nextInSocket)
  87. {
  88. if (key == b->m_key)
  89. return b->m_nameString;
  90. }
  91. }
  92. return AsciiString::TheEmptyString;
  93. }
  94. //-------------------------------------------------------------------------------------------------
  95. NameKeyType NameKeyGenerator::nameToKey(const char* nameString)
  96. {
  97. Bucket *b;
  98. UnsignedInt hash = calcHashForString(nameString) % SOCKET_COUNT;
  99. // hmm, do we have it already?
  100. for (b = m_sockets[hash]; b; b = b->m_nextInSocket)
  101. {
  102. if (strcmp(nameString, b->m_nameString.str()) == 0)
  103. return b->m_key;
  104. }
  105. // nope, guess not. let's allocate it.
  106. b = newInstance(Bucket);
  107. b->m_key = (NameKeyType)m_nextID++;
  108. b->m_nameString = nameString;
  109. b->m_nextInSocket = m_sockets[hash];
  110. m_sockets[hash] = b;
  111. NameKeyType result = b->m_key;
  112. #if defined(_DEBUG) || defined(_INTERNAL)
  113. // reality-check to be sure our hasher isn't going bad.
  114. const Int maxThresh = 3;
  115. Int numOverThresh = 0;
  116. for (Int i = 0; i < SOCKET_COUNT; ++i)
  117. {
  118. Int numInThisSocket = 0;
  119. for (b = m_sockets[i]; b; b = b->m_nextInSocket)
  120. ++numInThisSocket;
  121. if (numInThisSocket > maxThresh)
  122. ++numOverThresh;
  123. }
  124. // if more than a small percent of the sockets are getting deep, probably want to increase the socket count.
  125. if (numOverThresh > SOCKET_COUNT/20)
  126. {
  127. 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)));
  128. }
  129. #endif
  130. return result;
  131. } // end nameToKey
  132. //-------------------------------------------------------------------------------------------------
  133. NameKeyType StaticNameKey::key() const
  134. {
  135. if (m_key == NAMEKEY_INVALID)
  136. {
  137. DEBUG_ASSERTCRASH(TheNameKeyGenerator, ("no TheNameKeyGenerator yet"));
  138. if (TheNameKeyGenerator)
  139. m_key = TheNameKeyGenerator->nameToKey(m_name);
  140. }
  141. return m_key;
  142. }