| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- #pragma once
- #include "BsPrerequisitesUtil.h"
- #include "BsSpinLock.h"
- namespace BansheeEngine
- {
- /**
- * @brief A string identifier that provides very fast comparisons
- * to other string ids.
- *
- * @note Essentially a unique ID is generated for each string and then
- * the ID is used for comparisons as if you were using an integer
- * or an enum.
- *
- * Thread safe.
- */
- class BS_UTILITY_EXPORT StringID
- {
- static const int HASH_TABLE_SIZE = 4096;
- static const int MAX_CHUNK_COUNT = 50;
- static const int ELEMENTS_PER_CHUNK = 256;
- static const int STRING_SIZE = 256;
- /**
- * @brief Helper class that performs string actions on both null terminated character
- * arrays and standard strings.
- */
- template<class T>
- class StringIDUtil
- {
- public:
- static UINT32 size(T const& input) { return 0; }
- static void copy(T const& input, char* dest) { }
- static bool compare(T const& a, char* b) { return 0; }
- };
- /**
- * @brief Internal data that is shared by all instances for a specific string.
- */
- struct InternalData
- {
- UINT32 id;
- InternalData* next;
- char chars[STRING_SIZE];
- };
- /**
- * @brief Performs initialization of static members as soon as the library is loaded.
- */
- struct InitStatics
- {
- InitStatics();
- };
- public:
- StringID();
- StringID(const char* name)
- :mData(nullptr)
- {
- construct(name);
- }
- StringID(const String& name)
- :mData(nullptr)
- {
- construct(name);
- }
- template<int N>
- StringID(const char name[N])
- :mData(nullptr)
- {
- construct((const char*)name);
- }
- /**
- * @brief Compare to string ids for equality. Uses fast integer comparison.
- */
- bool operator== (const StringID& rhs) const
- {
- return mData == rhs.mData;
- }
- /**
- * @brief Compare to string ids for inequality. Uses fast integer comparison.
- */
- bool operator!= (const StringID& rhs) const
- {
- return mData != rhs.mData;
- }
- /**
- * @brief Returns true if the string id has no value assigned.
- */
- bool empty() const
- {
- return mData == nullptr;
- }
- /**
- * @brief Returns the null-terminated name of the string id.
- */
- const char* cstr() const
- {
- if (mData == nullptr)
- return nullptr;
- return mData->chars;
- }
- static const StringID NONE;
- private:
- /**
- * @brief Constructs a StringID object in a way that works for pointers to character arrays
- * and standard strings.
- */
- template<class T>
- void construct(T const& name);
- /**
- * @brief Calculates a hash value for the provided null-terminated string.
- */
- template<class T>
- UINT32 calcHash(T const& input);
- /**
- * @brief Allocates a new string entry and assigns it a unique ID.
- * Optionally expands the chunks buffer if the new entry doesn't fit.
- */
- InternalData* allocEntry();
- InternalData* mData;
- static volatile InitStatics mInitStatics;
- static InternalData* mStringHashTable[HASH_TABLE_SIZE];
- static InternalData* mChunks[MAX_CHUNK_COUNT];
- static UINT32 mNextId;
- static UINT32 mNumChunks;
- static SpinLock mSync;
- };
- template<> struct RTTIPlainType <StringID>
- {
- enum { id = TID_StringID }; enum { hasDynamicSize = 1 };
- static void toMemory(const StringID& data, char* memory)
- {
- UINT32 size = getDynamicSize(data);
- UINT32 curSize = sizeof(UINT32);
- memcpy(memory, &size, curSize);
- memory += curSize;
- bool isEmpty = data.empty();
- memory = rttiWriteElem(isEmpty, memory);
- if (!isEmpty)
- {
- UINT32 length = (UINT32)strlen(data.cstr());
- memcpy(memory, data.cstr(), length * sizeof(char));
- }
- }
- static UINT32 fromMemory(StringID& data, char* memory)
- {
- UINT32 size;
- memcpy(&size, memory, sizeof(UINT32));
- memory += sizeof(UINT32);
- bool empty = false;
- memory = rttiReadElem(empty, memory);
- if (!empty)
- {
- UINT32 length = (size - sizeof(UINT32) - sizeof(bool)) / sizeof(char);
- char* name = (char*)bs_alloc(length + 1);
- memcpy(name, memory, length);
- name[length] = '\0';
- data = StringID(name);
- }
- return size;
- }
- static UINT32 getDynamicSize(const StringID& data)
- {
- UINT32 dataSize = sizeof(bool) + sizeof(UINT32);
- bool isEmpty = data.empty();
- if (!isEmpty)
- {
- UINT32 length = (UINT32)strlen(data.cstr());
- dataSize += length * sizeof(char);
- }
- return (UINT32)dataSize;
- }
- };
- }
|