// Code by Frederik Omlor (2023) // -------------------------- HEADER ------------------------------- #pragma once #include "../Core.h" #include #include #include "../Analysis/Debug.h" namespace CCE { struct CCE_API String // 8 bytes { String(const char* str = ""); ~String(); void ClearGlobalStringTable(); String& operator=(const String& other) { // check if both refs are the same instance if (this == &other) { return *this; } this->sId = other.sId; return *this; } String& operator=(const char* other) { *this = String(other); return *this; } bool operator==(const String& other) { // compare strings by their string id return this->sId == other.sId; } bool operator!=(const String& other) { // compare strings by their string id return this->sId != other.sId; } bool operator==(const char* other) { return this->sId == GetStringID(other); } bool operator!=(const char* other) { return this->sId != GetStringID(other); } size_t Length() const; const char* Value() const; public: unsigned long long sId = 0; // 8 bytes private: static std::unordered_map gStringTable; private: const unsigned long long GetStringID(const char* str); }; } // ------------------------------- DEFINITION -------------------------------- #include "String.h" #include "../Utilities/CRCHash.h" namespace CCE { String::String(const char* str) { sId = GetStringID(str); #ifdef DEBUG auto keyVal = gStringTable.find(sId); bool idInStringTable = keyVal != gStringTable.end(); // incoming string id is in string table if (idInStringTable) { bool sEqual = keyVal->second == NULL ? false : (strcmp(keyVal->second, str) == 0); // strings are equal bool diff = sEqual && !idInStringTable; bool collision = !sEqual && idInStringTable; if (diff) { printf("Different hash values on strings \"%s\" and \"%s\".", str, gStringTable[sId]); } if (collision) { printf("Hash-Collision on strings \"%s\" and \"%s\".", str, gStringTable[sId]); } DASSERT(!collision, "There has been a hash function collision!"); DASSERT(!diff, "There has been different hashes for the same string!"); } #endif // DEBUG // Add String if it doesn't exist already (move str) gStringTable.try_emplace(sId, std::move(str)); } String::~String() { } void String::ClearGlobalStringTable() { std::unordered_map::iterator it; // Free all the memory allocated by std::move for (it = gStringTable.begin(); it != gStringTable.end(); it++) { free((void*)it->second); } gStringTable.clear(); } size_t String::Length() const { if (gStringTable[sId] == NULL) { DERROR(GetLastError()); return -1; } return strlen(gStringTable[sId]); } const char* String::Value() const { return gStringTable[sId] == NULL ? "" : gStringTable[sId]; } const unsigned long long String::GetStringID(const char* str) { return CCE::Math::CRCHash::HashValue(str, strlen(str)); } std::unordered_map String::gStringTable; }