| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-04 21:02:58 +01:00
										 |  |  | #include <AK/DeprecatedFlyString.h>
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | #include <AK/FlyString.h>
 | 
					
						
							|  |  |  | #include <AK/HashMap.h>
 | 
					
						
							|  |  |  | #include <AK/Singleton.h>
 | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  | #include <AK/String.h>
 | 
					
						
							|  |  |  | #include <AK/StringData.h>
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | #include <AK/StringView.h>
 | 
					
						
							|  |  |  | #include <AK/Utf8View.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace AK { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  | struct FlyStringTableHashTraits : public Traits<Detail::StringData const*> { | 
					
						
							|  |  |  |     static u32 hash(Detail::StringData const* string) { return string->hash(); } | 
					
						
							|  |  |  |     static bool equals(Detail::StringData const* a, Detail::StringData const* b) { return *a == *b; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | static auto& all_fly_strings() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |     static Singleton<HashTable<Detail::StringData const*, FlyStringTableHashTraits>> table; | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  |     return *table; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ErrorOr<FlyString> FlyString::from_utf8(StringView string) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-23 20:03:38 +01:00
										 |  |  |     if (string.is_empty()) | 
					
						
							|  |  |  |         return FlyString {}; | 
					
						
							|  |  |  |     if (string.length() <= Detail::MAX_SHORT_STRING_BYTE_COUNT) | 
					
						
							|  |  |  |         return FlyString { TRY(String::from_utf8(string)) }; | 
					
						
							|  |  |  |     if (auto it = all_fly_strings().find(string.hash(), [&](auto& entry) { return entry->bytes_as_string_view() == string; }); it != all_fly_strings().end()) | 
					
						
							|  |  |  |         return FlyString { Detail::StringBase(**it) }; | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  |     return FlyString { TRY(String::from_utf8(string)) }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 11:33:26 +01:00
										 |  |  | FlyString FlyString::from_utf8_without_validation(ReadonlyBytes string) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-23 20:03:38 +01:00
										 |  |  |     if (string.is_empty()) | 
					
						
							|  |  |  |         return FlyString {}; | 
					
						
							|  |  |  |     if (string.size() <= Detail::MAX_SHORT_STRING_BYTE_COUNT) | 
					
						
							|  |  |  |         return FlyString { String::from_utf8_without_validation(string) }; | 
					
						
							|  |  |  |     if (auto it = all_fly_strings().find(StringView(string).hash(), [&](auto& entry) { return entry->bytes_as_string_view() == string; }); it != all_fly_strings().end()) | 
					
						
							|  |  |  |         return FlyString { Detail::StringBase(**it) }; | 
					
						
							| 
									
										
										
										
											2024-03-23 11:33:26 +01:00
										 |  |  |     return FlyString { String::from_utf8_without_validation(string) }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | FlyString::FlyString(String const& string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (string.is_short_string()) { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |         m_data = string; | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |     if (string.m_data->is_fly_string()) { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |         m_data = string; | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |     auto it = all_fly_strings().find(string.m_data); | 
					
						
							|  |  |  |     if (it == all_fly_strings().end()) { | 
					
						
							|  |  |  |         m_data = string; | 
					
						
							|  |  |  |         all_fly_strings().set(string.m_data); | 
					
						
							|  |  |  |         string.m_data->set_fly_string(true); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |         m_data.m_data = *it; | 
					
						
							|  |  |  |         m_data.m_data->ref(); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-14 14:21:55 +00:00
										 |  |  | FlyString& FlyString::operator=(String const& string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     *this = FlyString { string }; | 
					
						
							|  |  |  |     return *this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | bool FlyString::is_empty() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view().is_empty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned FlyString::hash() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |     return m_data.hash(); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 19:55:21 +02:00
										 |  |  | u32 FlyString::ascii_case_insensitive_hash() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return case_insensitive_string_hash(reinterpret_cast<char const*>(bytes().data()), bytes().size()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | FlyString::operator String() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return to_string(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String FlyString::to_string() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |     Detail::StringBase copy = m_data; | 
					
						
							|  |  |  |     return String(move(copy)); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Utf8View FlyString::code_points() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return Utf8View { bytes_as_string_view() }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ReadonlyBytes FlyString::bytes() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view().bytes(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StringView FlyString::bytes_as_string_view() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |     return m_data.bytes(); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FlyString::operator==(String const& other) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  |     return m_data == other; | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FlyString::operator==(StringView string) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view() == string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FlyString::operator==(char const* string) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view() == string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  | void FlyString::did_destroy_fly_string_data(Badge<Detail::StringData>, Detail::StringData const& string_data) | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-23 14:54:23 +01:00
										 |  |  |     all_fly_strings().remove(&string_data); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-28 18:58:29 -04:00
										 |  |  | Detail::StringBase FlyString::data(Badge<String>) const | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | size_t FlyString::number_of_fly_strings() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return all_fly_strings().size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-04 21:02:58 +01:00
										 |  |  | DeprecatedFlyString FlyString::to_deprecated_fly_string() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return DeprecatedFlyString(bytes_as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-09 17:45:33 +01:00
										 |  |  | ErrorOr<FlyString> FlyString::from_deprecated_fly_string(DeprecatedFlyString const& deprecated_fly_string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return FlyString::from_utf8(deprecated_fly_string.view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | unsigned Traits<FlyString>::hash(FlyString const& fly_string) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-03-08 23:11:59 +01:00
										 |  |  |     return fly_string.hash(); | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 20:05:54 +02:00
										 |  |  | int FlyString::operator<=>(FlyString const& other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view().compare(other.bytes_as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | ErrorOr<void> Formatter<FlyString>::format(FormatBuilder& builder, FlyString const& fly_string) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return Formatter<StringView>::format(builder, fly_string.bytes_as_string_view()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-07 19:53:21 +01:00
										 |  |  | bool FlyString::equals_ignoring_ascii_case(FlyString const& other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (*this == other) | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2023-03-10 08:48:54 +01:00
										 |  |  |     return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other.bytes_as_string_view()); | 
					
						
							| 
									
										
										
										
											2023-03-07 19:53:21 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-04 10:49:29 +01:00
										 |  |  | bool FlyString::equals_ignoring_ascii_case(StringView other) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-06 23:59:15 +13:00
										 |  |  | bool FlyString::starts_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view().starts_with(bytes, case_sensitivity); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FlyString::ends_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bytes_as_string_view().ends_with(bytes, case_sensitivity); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-11 08:26:49 -05:00
										 |  |  | } |