BsStringID.h 4.4 KB

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