BsStringID.cpp 3.9 KB

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