BsStringID.h 4.8 KB

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