BsStringID.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. #include "BsSpinLock.h"
  4. namespace BansheeEngine
  5. {
  6. /**
  7. * @brief A string identifier that provides very fast comparisons
  8. * to other string ids.
  9. *
  10. * @note Essentially a unique ID is generated for each string and then
  11. * the ID is used for comparisons as if you were using an integer
  12. * or an enum.
  13. *
  14. * Thread safe.
  15. */
  16. class BS_UTILITY_EXPORT StringID
  17. {
  18. static const int HASH_TABLE_SIZE = 4096;
  19. static const int MAX_CHUNK_COUNT = 50;
  20. static const int ELEMENTS_PER_CHUNK = 256;
  21. static const int STRING_SIZE = 256;
  22. /**
  23. * @brief Helper class that performs string actions on both null terminated character
  24. * arrays and standard strings.
  25. */
  26. template<class T>
  27. class StringIDUtil
  28. {
  29. public:
  30. static UINT32 size(T const& input) { return 0; }
  31. static void copy(T const& input, char* dest) { }
  32. static bool compare(T const& a, char* b) { return 0; }
  33. };
  34. /**
  35. * @brief Internal data that is shared by all instances for a specific string.
  36. */
  37. struct InternalData
  38. {
  39. UINT32 id;
  40. InternalData* next;
  41. char chars[STRING_SIZE];
  42. };
  43. /**
  44. * @brief Performs initialization of static members as soon as the library is loaded.
  45. */
  46. struct InitStatics
  47. {
  48. InitStatics();
  49. };
  50. public:
  51. StringID();
  52. StringID(const char* name)
  53. :mData(nullptr)
  54. {
  55. construct(name);
  56. }
  57. StringID(const String& name)
  58. :mData(nullptr)
  59. {
  60. construct(name);
  61. }
  62. template<int N>
  63. StringID(const char name[N])
  64. :mData(nullptr)
  65. {
  66. construct((const char*)name);
  67. }
  68. /**
  69. * @brief Compare to string ids for equality. Uses fast integer comparison.
  70. */
  71. bool operator== (const StringID& rhs) const
  72. {
  73. return mData == rhs.mData;
  74. }
  75. /**
  76. * @brief Compare to string ids for inequality. Uses fast integer comparison.
  77. */
  78. bool operator!= (const StringID& rhs) const
  79. {
  80. return mData != rhs.mData;
  81. }
  82. /**
  83. * @brief Returns true if the string id has no value assigned.
  84. */
  85. bool empty() const
  86. {
  87. return mData == nullptr;
  88. }
  89. /**
  90. * @brief Returns the null-terminated name of the string id.
  91. */
  92. const char* cstr() const
  93. {
  94. if (mData == nullptr)
  95. return nullptr;
  96. return mData->chars;
  97. }
  98. static const StringID NONE;
  99. private:
  100. /**
  101. * @brief Constructs a StringID object in a way that works for pointers to character arrays
  102. * and standard strings.
  103. */
  104. template<class T>
  105. void construct(T const& name);
  106. /**
  107. * @brief Calculates a hash value for the provided null-terminated string.
  108. */
  109. template<class T>
  110. UINT32 calcHash(T const& input);
  111. /**
  112. * @brief Allocates a new string entry and assigns it a unique ID.
  113. * Optionally expands the chunks buffer if the new entry doesn't fit.
  114. */
  115. InternalData* allocEntry();
  116. InternalData* mData;
  117. static volatile InitStatics mInitStatics;
  118. static InternalData* mStringHashTable[HASH_TABLE_SIZE];
  119. static InternalData* mChunks[MAX_CHUNK_COUNT];
  120. static UINT32 mNextId;
  121. static UINT32 mNumChunks;
  122. static SpinLock mSync;
  123. };
  124. template<> struct RTTIPlainType <StringID>
  125. {
  126. enum { id = TID_StringID }; enum { hasDynamicSize = 1 };
  127. static void toMemory(const StringID& data, char* memory)
  128. {
  129. UINT32 size = getDynamicSize(data);
  130. UINT32 curSize = sizeof(UINT32);
  131. memcpy(memory, &size, curSize);
  132. memory += curSize;
  133. bool isEmpty = data.empty();
  134. memory = rttiWriteElem(isEmpty, memory);
  135. if (!isEmpty)
  136. {
  137. UINT32 length = (UINT32)strlen(data.cstr());
  138. memcpy(memory, data.cstr(), length * sizeof(char));
  139. }
  140. }
  141. static UINT32 fromMemory(StringID& data, char* memory)
  142. {
  143. UINT32 size;
  144. memcpy(&size, memory, sizeof(UINT32));
  145. memory += sizeof(UINT32);
  146. bool empty = false;
  147. memory = rttiReadElem(empty, memory);
  148. if (!empty)
  149. {
  150. UINT32 length = (size - sizeof(UINT32) - sizeof(bool)) / sizeof(char);
  151. char* name = (char*)bs_alloc(length + 1);
  152. memcpy(name, memory, length);
  153. name[length] = '\0';
  154. data = StringID(name);
  155. }
  156. return size;
  157. }
  158. static UINT32 getDynamicSize(const StringID& data)
  159. {
  160. UINT32 dataSize = sizeof(bool) + sizeof(UINT32);
  161. bool isEmpty = data.empty();
  162. if (!isEmpty)
  163. {
  164. UINT32 length = (UINT32)strlen(data.cstr());
  165. dataSize += length * sizeof(char);
  166. }
  167. return (UINT32)dataSize;
  168. }
  169. };
  170. }