From 870a947040ed45ebb3eb2cdb12ae097edbac021e Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Sat, 28 Oct 2023 19:07:10 -0400 Subject: [PATCH] AK: Remove StringInternals.h Since we do not expose memory layout anymore in StringBase, there is no need to keep StringData public. --- AK/String.cpp | 79 --------------------------- AK/StringBase.cpp | 127 ++++++++++++++++++++++++++++++++++++++++++- AK/StringInternals.h | 81 --------------------------- 3 files changed, 126 insertions(+), 161 deletions(-) delete mode 100644 AK/StringInternals.h diff --git a/AK/String.cpp b/AK/String.cpp index 6c5e41fa7b..17eb6313d1 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -11,90 +11,11 @@ #include #include #include -#include #include #include namespace AK { -namespace Detail { - -void StringData::operator delete(void* ptr) -{ - free(ptr); -} - -StringData::StringData(size_t byte_count) - : m_byte_count(byte_count) -{ -} - -StringData::StringData(StringData const& superstring, size_t start, size_t byte_count) - : m_byte_count(byte_count) - , m_substring(true) -{ - auto& data = const_cast(substring_data()); - data.start_offset = start; - data.superstring = &superstring; - superstring.ref(); -} - -StringData::~StringData() -{ - if (m_substring) - substring_data().superstring->unref(); -} - -void StringData::unref() const -{ - if (m_is_fly_string && m_ref_count == 2) { - m_is_fly_string = false; // Otherwise unref from did_destory_fly_string_data will cause infinite recursion. - FlyString::did_destroy_fly_string_data({}, bytes_as_string_view()); - } - RefCounted::unref(); -} - -constexpr size_t allocation_size_for_string_data(size_t length) -{ - return sizeof(StringData) + (sizeof(char) * length); -} - -ErrorOr> StringData::create_uninitialized(size_t byte_count, u8*& buffer) -{ - VERIFY(byte_count); - void* slot = malloc(allocation_size_for_string_data(byte_count)); - if (!slot) { - return Error::from_errno(ENOMEM); - } - auto new_string_data = adopt_ref(*new (slot) StringData(byte_count)); - buffer = const_cast(new_string_data->bytes().data()); - return new_string_data; -} - -ErrorOr> StringData::create_substring(StringData const& superstring, size_t start, size_t byte_count) -{ - // Strings of MAX_SHORT_STRING_BYTE_COUNT bytes or less should be handled by the String short string optimization. - VERIFY(byte_count > String::MAX_SHORT_STRING_BYTE_COUNT); - - void* slot = malloc(sizeof(StringData) + sizeof(StringData::SubstringData)); - if (!slot) { - return Error::from_errno(ENOMEM); - } - return adopt_ref(*new (slot) StringData(superstring, start, byte_count)); -} - -void StringData::compute_hash() const -{ - auto bytes = this->bytes(); - if (bytes.size() == 0) - m_hash = 0; - else - m_hash = string_hash(reinterpret_cast(bytes.data()), bytes.size()); - m_has_hash = true; -} - -} - String String::from_utf8_without_validation(ReadonlyBytes bytes) { String result; diff --git a/AK/StringBase.cpp b/AK/StringBase.cpp index 7c0b041f3a..52afdc4759 100644 --- a/AK/StringBase.cpp +++ b/AK/StringBase.cpp @@ -5,11 +5,136 @@ */ #include +#include #include -#include namespace AK::Detail { +class StringData final : public RefCounted { +public: + static ErrorOr> create_uninitialized(size_t byte_count, u8*& buffer) + { + VERIFY(byte_count); + void* slot = malloc(allocation_size_for_string_data(byte_count)); + if (!slot) { + return Error::from_errno(ENOMEM); + } + auto new_string_data = adopt_ref(*new (slot) StringData(byte_count)); + buffer = const_cast(new_string_data->bytes().data()); + return new_string_data; + } + + static ErrorOr> create_substring(StringData const& superstring, size_t start, size_t byte_count) + { + // Strings of MAX_SHORT_STRING_BYTE_COUNT bytes or less should be handled by the String short string optimization. + VERIFY(byte_count > MAX_SHORT_STRING_BYTE_COUNT); + + void* slot = malloc(sizeof(StringData) + sizeof(StringData::SubstringData)); + if (!slot) { + return Error::from_errno(ENOMEM); + } + return adopt_ref(*new (slot) StringData(superstring, start, byte_count)); + } + + struct SubstringData { + StringData const* superstring { nullptr }; + u32 start_offset { 0 }; + }; + + 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_destory_fly_string_data will cause infinite recursion. + FlyString::did_destroy_fly_string_data({}, bytes_as_string_view()); + } + RefCounted::unref(); + } + + ~StringData() + { + if (m_substring) + substring_data().superstring->unref(); + } + + 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; } + + size_t byte_count() const { return m_byte_count; } + +private: + static constexpr size_t allocation_size_for_string_data(size_t length) + { + return sizeof(StringData) + (sizeof(char) * length); + } + + explicit StringData(size_t byte_count) + : m_byte_count(byte_count) + { + } + + StringData(StringData const& superstring, size_t start, size_t byte_count) + : m_byte_count(byte_count) + , m_substring(true) + { + auto& data = const_cast(substring_data()); + data.start_offset = start; + data.superstring = &superstring; + superstring.ref(); + } + + void compute_hash() const + { + auto bytes = this->bytes(); + if (bytes.size() == 0) + m_hash = 0; + else + m_hash = string_hash(reinterpret_cast(bytes.data()), bytes.size()); + m_has_hash = true; + } + + 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]; +}; + ReadonlyBytes ShortString::bytes() const { return { storage, byte_count() }; diff --git a/AK/StringInternals.h b/AK/StringInternals.h deleted file mode 100644 index 99961eb779..0000000000 --- a/AK/StringInternals.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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); - - struct SubstringData { - StringData const* superstring { nullptr }; - u32 start_offset { 0 }; - }; - - void operator delete(void* ptr); - - void unref() const; - - ~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; } - - size_t byte_count() const { return m_byte_count; } - -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]; -}; - -}