BsStringID.h 4.4 KB

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