diff --git a/AK/String.cpp b/AK/String.cpp index 34608280232..8286084063f 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,69 +19,6 @@ namespace AK { namespace Detail { -class StringData final : public RefCounted { -public: - static ErrorOr> create_uninitialized(size_t, u8*& buffer); - static ErrorOr> create_substring(StringData const& superstring, size_t start, size_t byte_count); - static ErrorOr> from_utf8(char const* utf8_bytes, size_t); - static ErrorOr> from_stream(Stream&, size_t byte_count); - - struct SubstringData { - StringData const* superstring { nullptr }; - u32 start_offset { 0 }; - }; - - void operator delete(void* ptr); - - ~StringData(); - - SubstringData const& substring_data() const - { - return *reinterpret_cast(m_bytes_or_substring_data); - } - - // NOTE: There is no guarantee about null-termination. - ReadonlyBytes bytes() const - { - if (m_substring) { - auto const& data = substring_data(); - return data.superstring->bytes().slice(data.start_offset, m_byte_count); - } - return { &m_bytes_or_substring_data[0], m_byte_count }; - } - - StringView bytes_as_string_view() const { return { bytes() }; } - - bool operator==(StringData const& other) const - { - return bytes_as_string_view() == other.bytes_as_string_view(); - } - - unsigned hash() const - { - if (!m_has_hash) - compute_hash(); - return m_hash; - } - - bool is_fly_string() const { return m_is_fly_string; } - void set_fly_string(bool is_fly_string) const { m_is_fly_string = is_fly_string; } - -private: - explicit StringData(size_t byte_count); - StringData(StringData const& superstring, size_t start, size_t byte_count); - - void compute_hash() const; - - u32 m_byte_count { 0 }; - mutable unsigned m_hash { 0 }; - mutable bool m_has_hash { false }; - bool m_substring { false }; - mutable bool m_is_fly_string { false }; - - alignas(SubstringData) u8 m_bytes_or_substring_data[0]; -}; - void StringData::operator delete(void* ptr) { free(ptr); diff --git a/AK/StringInternals.h b/AK/StringInternals.h new file mode 100644 index 00000000000..64a06f18864 --- /dev/null +++ b/AK/StringInternals.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace AK::Detail { + +class StringData final : public RefCounted { +public: + static ErrorOr> create_uninitialized(size_t, u8*& buffer); + static ErrorOr> create_substring(StringData const& superstring, size_t start, size_t byte_count); + static ErrorOr> from_utf8(char const* utf8_bytes, size_t); + static ErrorOr> from_stream(Stream&, size_t byte_count); + + struct SubstringData { + StringData const* superstring { nullptr }; + u32 start_offset { 0 }; + }; + + void operator delete(void* ptr); + + ~StringData(); + + SubstringData const& substring_data() const + { + return *reinterpret_cast(m_bytes_or_substring_data); + } + + // NOTE: There is no guarantee about null-termination. + ReadonlyBytes bytes() const + { + if (m_substring) { + auto const& data = substring_data(); + return data.superstring->bytes().slice(data.start_offset, m_byte_count); + } + return { &m_bytes_or_substring_data[0], m_byte_count }; + } + + StringView bytes_as_string_view() const { return { bytes() }; } + + bool operator==(StringData const& other) const + { + return bytes_as_string_view() == other.bytes_as_string_view(); + } + + unsigned hash() const + { + if (!m_has_hash) + compute_hash(); + return m_hash; + } + + bool is_fly_string() const { return m_is_fly_string; } + void set_fly_string(bool is_fly_string) const { m_is_fly_string = is_fly_string; } + +private: + explicit StringData(size_t byte_count); + StringData(StringData const& superstring, size_t start, size_t byte_count); + + void compute_hash() const; + + u32 m_byte_count { 0 }; + mutable unsigned m_hash { 0 }; + mutable bool m_has_hash { false }; + bool m_substring { false }; + mutable bool m_is_fly_string { false }; + + alignas(SubstringData) u8 m_bytes_or_substring_data[0]; +}; + +}