diff --git a/AK/FlyString.cpp b/AK/FlyString.cpp index f4e3416508..ad947190c4 100644 --- a/AK/FlyString.cpp +++ b/AK/FlyString.cpp @@ -8,14 +8,21 @@ #include #include #include +#include +#include #include #include namespace AK { +struct FlyStringTableHashTraits : public Traits { + static u32 hash(Detail::StringData const* string) { return string->hash(); } + static bool equals(Detail::StringData const* a, Detail::StringData const* b) { return *a == *b; } +}; + static auto& all_fly_strings() { - static Singleton> table; + static Singleton> table; return *table; } @@ -31,14 +38,19 @@ FlyString::FlyString(String const& string) return; } - auto it = all_fly_strings().find(string.bytes_as_string_view()); + if (string.m_data->is_fly_string()) { + m_data = string; + return; + } + + auto it = all_fly_strings().find(string.m_data); if (it == all_fly_strings().end()) { m_data = string; - - all_fly_strings().set(string.bytes_as_string_view(), m_data); - string.did_create_fly_string({}); + all_fly_strings().set(string.m_data); + string.m_data->set_fly_string(true); } else { - m_data = it->value; + m_data.m_data = *it; + m_data.m_data->ref(); } } @@ -104,9 +116,9 @@ bool FlyString::operator==(char const* string) const return bytes_as_string_view() == string; } -void FlyString::did_destroy_fly_string_data(Badge, StringView string_data) +void FlyString::did_destroy_fly_string_data(Badge, Detail::StringData const& string_data) { - all_fly_strings().remove(string_data); + all_fly_strings().remove(&string_data); } Detail::StringBase FlyString::data(Badge) const diff --git a/AK/FlyString.h b/AK/FlyString.h index 6c8815a67f..f91fe1d2cc 100644 --- a/AK/FlyString.h +++ b/AK/FlyString.h @@ -48,7 +48,7 @@ public: [[nodiscard]] int operator<=>(FlyString const& other) const; - static void did_destroy_fly_string_data(Badge, StringView); + static void did_destroy_fly_string_data(Badge, Detail::StringData const&); [[nodiscard]] Detail::StringBase data(Badge) const; // This is primarily interesting to unit tests. diff --git a/AK/String.h b/AK/String.h index 20a31b71ac..99417acb4b 100644 --- a/AK/String.h +++ b/AK/String.h @@ -186,7 +186,7 @@ public: static ErrorOr from_byte_string(T&&) = delete; private: - friend FlyString; + friend class ::AK::FlyString; using ShortString = Detail::ShortString; diff --git a/AK/StringBase.cpp b/AK/StringBase.cpp index ff83bd0ff0..62746b91a5 100644 --- a/AK/StringBase.cpp +++ b/AK/StringBase.cpp @@ -90,12 +90,6 @@ bool StringBase::operator==(StringBase const& other) const return bytes() == other.bytes(); } -void StringBase::did_create_fly_string(Badge) const -{ - VERIFY(!is_short_string()); - m_data->set_fly_string(true); -} - ErrorOr StringBase::replace_with_uninitialized_buffer(size_t byte_count) { if (byte_count <= MAX_SHORT_STRING_BYTE_COUNT) diff --git a/AK/StringBase.h b/AK/StringBase.h index cdad290360..541f7b8bdd 100644 --- a/AK/StringBase.h +++ b/AK/StringBase.h @@ -69,8 +69,6 @@ public: [[nodiscard]] bool operator==(StringBase const&) const; - void did_create_fly_string(Badge) const; - [[nodiscard]] ALWAYS_INLINE FlatPtr raw(Badge) const { return bit_cast(m_data); } protected: @@ -96,6 +94,9 @@ protected: ErrorOr substring_from_byte_offset_with_shared_superstring(size_t start, size_t byte_count) const; private: + friend class ::AK::String; + friend class ::AK::FlyString; + // NOTE: If the least significant bit of the pointer is set, this is a short string. static constexpr uintptr_t SHORT_STRING_FLAG = 1; diff --git a/AK/StringData.h b/AK/StringData.h index 8341d0b334..a871c2871a 100644 --- a/AK/StringData.h +++ b/AK/StringData.h @@ -44,22 +44,15 @@ public: void operator delete(void* ptr) { - free(ptr); - } - - void unref() const - { - if (m_is_fly_string && m_ref_count == 2) { - m_is_fly_string = false; // Otherwise unref from did_destroy_fly_string_data will cause infinite recursion. - FlyString::did_destroy_fly_string_data({}, *this); - } - RefCounted::unref(); + kfree_sized(ptr, allocation_size_for_string_data(static_cast(ptr)->m_byte_count)); } ~StringData() { if (m_substring) substring_data().superstring->unref(); + if (m_is_fly_string) + FlyString::did_destroy_fly_string_data({}, *this); } SubstringData const& substring_data() const