BsStringID.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #include "BsStringID.h"
  2. namespace BansheeEngine
  3. {
  4. const StringID StringID::NONE = StringID();
  5. volatile StringID::InitStatics StringID::mInitStatics = StringID::InitStatics();
  6. StringID::InternalData* StringID::mStringHashTable[HASH_TABLE_SIZE];
  7. StringID::InternalData* StringID::mChunks[MAX_CHUNK_COUNT];
  8. UINT32 StringID::mNextId = 0;
  9. UINT32 StringID::mNumChunks = 0;
  10. SpinLock StringID::mSync = SpinLock();
  11. StringID::InitStatics::InitStatics()
  12. {
  13. ScopedSpinLock lock(mSync);
  14. memset(mStringHashTable, 0, sizeof(mStringHashTable));
  15. memset(mChunks, 0, sizeof(mChunks));
  16. mChunks[0] = (InternalData*)bs_alloc(sizeof(InternalData) * ELEMENTS_PER_CHUNK);
  17. memset(mChunks[0], 0, sizeof(InternalData) * ELEMENTS_PER_CHUNK);
  18. mNumChunks++;
  19. }
  20. StringID::StringID()
  21. :mData(nullptr)
  22. { }
  23. template<class T>
  24. void StringID::construct(T const& name)
  25. {
  26. assert(StringIDUtil<T>::size(name) <= STRING_SIZE);
  27. UINT32 hash = calcHash(name) & (sizeof(mStringHashTable) / sizeof(mStringHashTable[0]) - 1);
  28. InternalData* existingEntry = mStringHashTable[hash];
  29. while (existingEntry != nullptr)
  30. {
  31. if (StringIDUtil<T>::compare(name, existingEntry->chars))
  32. {
  33. mData = existingEntry;
  34. return;
  35. }
  36. existingEntry = existingEntry->next;
  37. }
  38. ScopedSpinLock lock(mSync);
  39. // Search for the value again in case other thread just added it
  40. existingEntry = mStringHashTable[hash];
  41. InternalData* lastEntry = nullptr;
  42. while (existingEntry != nullptr)
  43. {
  44. if (StringIDUtil<T>::compare(name, existingEntry->chars))
  45. {
  46. mData = existingEntry;
  47. return;
  48. }
  49. lastEntry = existingEntry;
  50. existingEntry = existingEntry->next;
  51. }
  52. mData = allocEntry();
  53. StringIDUtil<T>::copy(name, mData->chars);
  54. if (lastEntry == nullptr)
  55. mStringHashTable[hash] = mData;
  56. else
  57. lastEntry->next = mData;
  58. }
  59. template<class T>
  60. UINT32 StringID::calcHash(T const& input)
  61. {
  62. UINT32 size = StringIDUtil<T>::size(input);
  63. UINT32 hash = 0;
  64. for (UINT32 i = 0; i < size; i++)
  65. hash = hash * 101 + input[i];
  66. return hash;
  67. }
  68. StringID::InternalData* StringID::allocEntry()
  69. {
  70. UINT32 chunkIdx = mNextId / ELEMENTS_PER_CHUNK;
  71. assert(chunkIdx < MAX_CHUNK_COUNT);
  72. assert(chunkIdx <= mNumChunks); // Can only increment sequentially
  73. if (chunkIdx >= mNumChunks)
  74. {
  75. mChunks[chunkIdx] = (InternalData*)bs_alloc(sizeof(InternalData) * ELEMENTS_PER_CHUNK);
  76. memset(mChunks[chunkIdx], 0, sizeof(InternalData) * ELEMENTS_PER_CHUNK);
  77. mNumChunks++;
  78. }
  79. InternalData* chunk = mChunks[chunkIdx];
  80. UINT32 chunkSpecificIndex = mNextId % ELEMENTS_PER_CHUNK;
  81. InternalData* newEntry = &chunk[chunkSpecificIndex];
  82. newEntry->id = mNextId++;
  83. newEntry->next = nullptr;
  84. return newEntry;
  85. }
  86. template<>
  87. class StringID::StringIDUtil<const char*>
  88. {
  89. public:
  90. static UINT32 size(const char* const& input) { return (UINT32)strlen(input); }
  91. static void copy(const char* const& input, char* dest) { memcpy(dest, input, strlen(input) + 1); }
  92. static bool compare(const char* const& a, char* b) { return strcmp(a, b) == 0; }
  93. };
  94. template<>
  95. class StringID::StringIDUtil <String>
  96. {
  97. public:
  98. static UINT32 size(String const& input) { return (UINT32)input.length(); }
  99. static void copy(String const& input, char* dest)
  100. {
  101. UINT32 len = (UINT32)input.length();
  102. input.copy(dest, len);
  103. dest[len] = '\0';
  104. }
  105. static bool compare(String const& a, char* b) { return a.compare(b) == 0; }
  106. };
  107. template class StringID::StringIDUtil <const char*>;
  108. template class StringID::StringIDUtil <String>;
  109. template BS_UTILITY_EXPORT void StringID::construct(const char* const&);
  110. template BS_UTILITY_EXPORT void StringID::construct(String const&);
  111. template BS_UTILITY_EXPORT UINT32 StringID::calcHash(const char* const&);
  112. template BS_UTILITY_EXPORT UINT32 StringID::calcHash(String const&);
  113. }