diff --git a/PolyEngine/Core/Src/pe/core/storage/IndexedString.cpp b/PolyEngine/Core/Src/pe/core/storage/IndexedString.cpp index 4c1b4f2a..c3338884 100644 --- a/PolyEngine/Core/Src/pe/core/storage/IndexedString.cpp +++ b/PolyEngine/Core/Src/pe/core/storage/IndexedString.cpp @@ -6,12 +6,23 @@ namespace pe::core::storage { -IndexedString::IndexedString(const char* str) +IndexedString::IndexedString(std::string_view str) : m_entry(impl::IndexedStringManager::get().registerString(str)) { ASSERTE(m_entry, "Entry is null after string creation!"); } +IndexedString::IndexedString(const impl::IndexedStringEntry* entry) + : m_entry(entry) +{ + ASSERTE(m_entry, "Entry is null after string creation!"); +} + +IndexedString IndexedString::FromRString(core::storage::String&& str) +{ + return IndexedString(impl::IndexedStringManager::get().registerString(std::move(str))); +} + IndexedString::~IndexedString() { impl::IndexedStringManager::get().unregisterString(m_entry); diff --git a/PolyEngine/Core/Src/pe/core/storage/IndexedString.hpp b/PolyEngine/Core/Src/pe/core/storage/IndexedString.hpp index c66b156b..4c2043c9 100644 --- a/PolyEngine/Core/Src/pe/core/storage/IndexedString.hpp +++ b/PolyEngine/Core/Src/pe/core/storage/IndexedString.hpp @@ -22,7 +22,12 @@ class CORE_DLLEXPORT IndexedString final : public core::BaseObjectLiteralType<> public: /// @brief IndexedString constructor. Registers the string in the IndexedStringManager. /// @param[in] str String to be represented by the IndexedString instance. - explicit IndexedString(const char* str); + explicit IndexedString(std::string_view str); + + /// @brief IndexedString factory function. Registers the string in the IndexedStringManager. + /// @note If the string is not registered yet, the memory is reused. + /// @param[in] str String to be represented by the IndexedString instance. + static IndexedString FromRString(core::storage::String&& str); /// @brief IndexedString destructor. Unregisters the string from the IndexedStringManager. ~IndexedString(); @@ -59,6 +64,8 @@ class CORE_DLLEXPORT IndexedString final : public core::BaseObjectLiteralType<> friend std::ostream& operator<< (std::ostream& stream, const IndexedString& rhs) { return stream << rhs.get(); } private: + explicit IndexedString(const impl::IndexedStringEntry* entry); + const impl::IndexedStringEntry* m_entry = nullptr; friend struct std::hash<::pe::core::storage::IndexedString>; diff --git a/PolyEngine/Core/Src/pe/core/storage/String.cpp b/PolyEngine/Core/Src/pe/core/storage/String.cpp index 4085aee8..c6dddc9f 100644 --- a/PolyEngine/Core/Src/pe/core/storage/String.cpp +++ b/PolyEngine/Core/Src/pe/core/storage/String.cpp @@ -9,22 +9,10 @@ const String String::EMPTY = String(); static const std::vector WHITESPACES { ' ', '\t', '\r', '\n', '\0' }; -namespace pe::core::storage -{ - -size_t StrLen(const char* str) { - size_t len = 0; - while (str[len] != 0) - ++len; - return len; -} - -} - -String::String(const char* data) { - size_t length = StrLen(data); +String::String(std::string_view str) { + size_t length = str.length(); Data.resize(length + 1); - std::memcpy(Data.data(), data, sizeof(char) * length); + std::memcpy(Data.data(), str.data(), sizeof(char) * length); Data[length] = 0; } @@ -42,8 +30,7 @@ String String::From(float var, size_t precision) { return StringBuilder().Append String String::From(double var) { return StringBuilder().Append(var).StealString(); } String String::From(double var, size_t precision) { return StringBuilder().Append(var, precision).StealString(); } String String::From(char var) { return StringBuilder().Append(var).StealString(); } -String String::From(const char* var) { return StringBuilder().Append(var).StealString(); } -String String::From(const std::string& var) { return StringBuilder().Append(var).StealString(); } +String String::From(std::string_view var) { return StringBuilder().Append(var).StealString(); } bool String::Contains(const String& var) const { @@ -202,8 +189,8 @@ String& String::operator=(String&& rhs) { return *this; } -bool String::operator==(const char* str) const { - if (GetLength() != StrLen(str)) +bool String::operator==(std::string_view str) const { + if (GetLength() != str.length()) return false; for (size_t k = 0; k < GetLength(); ++k) if (Data[k] != str[k]) @@ -211,21 +198,17 @@ bool String::operator==(const char* str) const { return true; } -bool String::operator==(const String& str) const { - return Data == str.Data; -} - -bool String::operator<(const String& rhs) const { - if (GetLength() < rhs.GetLength()) +bool String::operator<(std::string_view rhs) const { + if (GetLength() < rhs.length()) return true; - else if (GetLength() > rhs.GetLength()) + else if (GetLength() > rhs.length()) return false; for (size_t i = 0; i < GetLength(); ++i) { - if (Data[i] < rhs.Data[i]) + if (Data[i] < rhs[i]) return true; - else if (Data[i] > rhs.Data[i]) + else if (Data[i] > rhs[i]) return false; } return false; diff --git a/PolyEngine/Core/Src/pe/core/storage/String.hpp b/PolyEngine/Core/Src/pe/core/storage/String.hpp index 4f83bee4..b3273ca6 100644 --- a/PolyEngine/Core/Src/pe/core/storage/String.hpp +++ b/PolyEngine/Core/Src/pe/core/storage/String.hpp @@ -4,9 +4,6 @@ namespace pe::core::storage { - - CORE_DLLEXPORT size_t StrLen(const char* str); - class CORE_DLLEXPORT String final : public BaseObjectLiteralType<> { public: @@ -17,17 +14,20 @@ namespace pe::core::storage /// String constructor that creates String based on provided Cstring /// - String(const char* data); + String(const char* str) : String(std::string_view(str)) {} + + /// String constructor that creates String based on provided string_view + /// + explicit String(std::string_view str); /// String copy constructor /// Reference to String instance which state should be copied - String(const String& rhs); + explicit String(const String& rhs); /// String move constructor /// Reference to String instance which state should be moved String(String&& rhs); - /// Casts int to String /// Integer value which should be used to make String instance /// String containing integer value @@ -62,15 +62,10 @@ namespace pe::core::storage /// String conaining only one char static String From(char var); - /// Casts Cstring to String - /// Cstring value which should be used to make String instance - /// String containing given Cstring - static String From(const char* var); - - /// Casts std::string to String - /// std::string reference which should be used to make String instance - /// String containing given std::string - static String From(const std::string& var); + /// Casts string_view to String + /// string_view value which should be used to make String instance + /// String containing given content + static String From(std::string_view str); /// Checks if String instance contains another String instance @@ -164,18 +159,12 @@ namespace pe::core::storage /// Moved String reference String& operator=(String&& rhs); - /// Compares String with Cstring - /// Cstring to be compared with - bool operator==(const char* str) const; - - /// Compares two String references - /// String to be compared with - bool operator==(const String& str) const; - - bool operator!=(const char* str) const { return !(*this == str); } - bool operator!=(const String& str) const { return !(*this == str); } + /// Compares String with string_view + /// string_view to be compared with + bool operator==(std::string_view str) const; + bool operator!=(std::string_view str) const { return !(*this == str); } - bool operator<(const String& rhs) const; + bool operator<(std::string_view rhs) const; /// Appends one String to another /// String instance to be appended to source String @@ -197,6 +186,7 @@ namespace pe::core::storage friend std::ostream& operator<< (std::ostream& stream, const String& rhs) { return stream << rhs.GetCStr(); } + operator std::string_view() const { return std::string_view(GetCStr()); } private: String(std::vector rawData) : Data(std::move(rawData)) { Data.push_back('\0'); } diff --git a/PolyEngine/Core/Src/pe/core/storage/StringBuilder.cpp b/PolyEngine/Core/Src/pe/core/storage/StringBuilder.cpp index a26712f3..d09114f8 100644 --- a/PolyEngine/Core/Src/pe/core/storage/StringBuilder.cpp +++ b/PolyEngine/Core/Src/pe/core/storage/StringBuilder.cpp @@ -5,7 +5,7 @@ using namespace pe::core::storage; //---------------------------------------------------------------------------- -StringBuilder& StringBuilder::Append(const char* str, const size_t length) +StringBuilder& StringBuilder::Append(const char* str, size_t length) { Buffer.reserve(Buffer.size() + length); for (size_t i = 0; i < length; ++i) diff --git a/PolyEngine/Core/Src/pe/core/storage/StringBuilder.hpp b/PolyEngine/Core/Src/pe/core/storage/StringBuilder.hpp index 2e4d42cd..206bd218 100644 --- a/PolyEngine/Core/Src/pe/core/storage/StringBuilder.hpp +++ b/PolyEngine/Core/Src/pe/core/storage/StringBuilder.hpp @@ -16,17 +16,15 @@ namespace pe::core::storage /// @param val Value to append /// @return Instance reference for chainlinking inline StringBuilder& Append(char val) { Buffer.push_back(val); return *this; } - inline StringBuilder& Append(const char* val) { return Append(val, strlen(val)); } - inline StringBuilder& Append(const std::string& val) { return Append(val.c_str(), val.length()); } - inline StringBuilder& Append(const String& val) { return Append(val.GetCStr(), val.GetLength()); } inline StringBuilder& Append(int val) { FillBufferWithFormat(val, "%d"); return *this; } inline StringBuilder& Append(long long val) { FillBufferWithFormat(val, "%lld"); return *this; } inline StringBuilder& Append(unsigned val) { FillBufferWithFormat(val, "%u"); return *this; } inline StringBuilder& Append(unsigned long long val) { FillBufferWithFormat(val, "%llu"); return *this; } inline StringBuilder& Append(long val) { return Append((long long)val); } inline StringBuilder& Append(unsigned long val) { return Append((unsigned long long)val); } + inline StringBuilder& Append(std::string_view str) { return Append(str.data(), str.length()); } - StringBuilder& Append(const char* str, const size_t length); + StringBuilder& Append(const char* str, size_t length); StringBuilder& Append(f32 val, size_t precission = DEFAULT_FLT_PRECISION); StringBuilder& Append(f64 val, size_t precission = DEFAULT_FLT_PRECISION); diff --git a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringEntry.hpp b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringEntry.hpp index 17225c4c..cc584fa4 100644 --- a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringEntry.hpp +++ b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringEntry.hpp @@ -12,6 +12,7 @@ class IndexedStringEntry final : public core::BaseObjectLiteralType<> { public: IndexedStringEntry(const char* str) : m_str(str) {} + IndexedStringEntry(core::storage::String&& str) : m_str(std::move(str)) {} void incrementRefCount() const { ++m_refCount; } void decrementRefCount() const { --m_refCount; } diff --git a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.cpp b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.cpp index b49763bb..24da44cc 100644 --- a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.cpp +++ b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.cpp @@ -11,32 +11,52 @@ IndexedStringManager& IndexedStringManager::get() return instance; } -const IndexedStringEntry* IndexedStringManager::registerString(const char* str) +const IndexedStringEntry* IndexedStringManager::registerString(std::string_view str) { - IndexedStringEntry* ret = nullptr; + auto it = m_entries.find(str); + if (it == m_entries.end()) + { + return shareEntry(createEntry(String(str))); + } + else + { + return shareEntry(it->second.get()); + } +} +const IndexedStringEntry* IndexedStringManager::registerString(core::storage::String&& str) +{ auto it = m_entries.find(str); if (it == m_entries.end()) { - // @todo(muniu) There are two allocations happening here. - // Consider fixing it if the performace is affected by this. - auto entry = std::make_unique(str); - ret = entry.get(); - // We need to create a new string_view, which points to the string with the same lifetime as entry. - // Otherwise we could have some memory issues. - std::string_view strView(entry.get()->get().GetCStr()); - m_entries.emplace(strView, std::move(entry)); + return shareEntry(createEntry(std::move(str))); } else { - ret = it->second.get(); + return shareEntry(it->second.get()); } - - ret->incrementRefCount(); - ret->resetRemovalTimePoint(); +} + +const IndexedStringEntry* IndexedStringManager::createEntry(core::storage::String&& str) +{ + IndexedStringEntry* ret = nullptr; + auto entry = std::make_unique(std::move(str)); + ret = entry.get(); + // We need to create a new string_view, which points to the string with the same lifetime as entry. + // Otherwise we could have some memory issues. + std::string_view strView(entry.get()->get().GetCStr()); + m_entries.emplace(strView, std::move(entry)); + return ret; } +const IndexedStringEntry* IndexedStringManager::shareEntry(const IndexedStringEntry* entry) +{ + entry->incrementRefCount(); + entry->resetRemovalTimePoint(); + return entry; +} + void IndexedStringManager::unregisterString(const IndexedStringEntry* entry) { entry->decrementRefCount(); @@ -75,7 +95,7 @@ void IndexedStringManager::setTTLMode(bool enabled) m_ttlEnabled = enabled; } -bool IndexedStringManager::isRegistered(const char* str) const +bool IndexedStringManager::isRegistered(std::string_view str) const { auto it = m_entries.find(str); return it != m_entries.end(); diff --git a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.hpp b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.hpp index 7aa02149..5b1db943 100644 --- a/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.hpp +++ b/PolyEngine/Core/Src/pe/core/storage/impl/IndexedStringManager.hpp @@ -21,13 +21,14 @@ class CORE_DLLEXPORT IndexedStringManager final : public core::BaseObjectLiteral public: static IndexedStringManager& get(); - const IndexedStringEntry* registerString(const char* str); + const IndexedStringEntry* registerString(std::string_view str); + const IndexedStringEntry* registerString(core::storage::String&& str); void unregisterString(const IndexedStringEntry* entry); void setTTLMode(bool enabled); void tickTTL(size_t ttlTickCount = 1); - bool isRegistered(const char* str) const; + bool isRegistered(std::string_view str) const; private: IndexedStringManager() = default; @@ -40,6 +41,9 @@ class CORE_DLLEXPORT IndexedStringManager final : public core::BaseObjectLiteral void erase(const IndexedStringEntry* entry); void scheduleErase(const IndexedStringEntry* entry); + const IndexedStringEntry* createEntry(core::storage::String&& str); + const IndexedStringEntry* shareEntry(const IndexedStringEntry* entry); + std::unordered_map> m_entries; PriorityQueue m_ttlEntries; bool m_ttlEnabled = false;