/* * Copyright (c) 2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include namespace AK { class FlyString { AK_MAKE_DEFAULT_MOVABLE(FlyString); AK_MAKE_DEFAULT_COPYABLE(FlyString); public: FlyString() = default; static ErrorOr from_utf8(StringView); template requires(IsOneOf, ByteString, DeprecatedFlyString, FlyString, String>) static ErrorOr from_utf8(T&&) = delete; FlyString(String const&); FlyString& operator=(String const&); [[nodiscard]] bool is_empty() const; [[nodiscard]] unsigned hash() const; [[nodiscard]] u32 ascii_case_insensitive_hash() const; explicit operator String() const; String to_string() const; [[nodiscard]] Utf8View code_points() const; [[nodiscard]] ReadonlyBytes bytes() const; [[nodiscard]] StringView bytes_as_string_view() const; [[nodiscard]] ALWAYS_INLINE bool operator==(FlyString const& other) const { return m_data.raw({}) == other.m_data.raw({}); } [[nodiscard]] bool operator==(String const&) const; [[nodiscard]] bool operator==(StringView) const; [[nodiscard]] bool operator==(char const*) const; [[nodiscard]] int operator<=>(FlyString const& other) const; static void did_destroy_fly_string_data(Badge, StringView); [[nodiscard]] Detail::StringBase data(Badge) const; // This is primarily interesting to unit tests. [[nodiscard]] static size_t number_of_fly_strings(); // FIXME: Remove these once all code has been ported to FlyString [[nodiscard]] DeprecatedFlyString to_deprecated_fly_string() const; static ErrorOr from_deprecated_fly_string(DeprecatedFlyString const&); template requires(IsSame, StringView>) static ErrorOr from_deprecated_fly_string(T&&) = delete; // Compare this FlyString against another string with ASCII caseless matching. [[nodiscard]] bool equals_ignoring_ascii_case(FlyString const&) const; [[nodiscard]] bool equals_ignoring_ascii_case(StringView) const; [[nodiscard]] bool starts_with_bytes(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; [[nodiscard]] bool ends_with_bytes(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; template [[nodiscard]] ALWAYS_INLINE constexpr bool is_one_of(Ts... strings) const { return (... || this->operator==(forward(strings))); } private: Detail::StringBase m_data; }; template<> struct Traits : public DefaultTraits { static unsigned hash(FlyString const&); }; template<> struct Formatter : Formatter { ErrorOr format(FormatBuilder&, FlyString const&); }; struct ASCIICaseInsensitiveFlyStringTraits : public Traits { static unsigned hash(FlyString const& s) { return s.ascii_case_insensitive_hash(); } static bool equals(FlyString const& a, FlyString const& b) { return a.bytes().data() == b.bytes().data() || a.bytes_as_string_view().equals_ignoring_ascii_case(b.bytes_as_string_view()); } }; } [[nodiscard]] ALWAYS_INLINE AK::FlyString operator""_fly_string(char const* cstring, size_t length) { return AK::FlyString::from_utf8(AK::StringView(cstring, length)).release_value(); } #if USING_AK_GLOBALLY using AK::FlyString; #endif