FlyString.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/DeprecatedFlyString.h>
  7. #include <AK/FlyString.h>
  8. #include <AK/HashMap.h>
  9. #include <AK/Singleton.h>
  10. #include <AK/String.h>
  11. #include <AK/StringData.h>
  12. #include <AK/StringView.h>
  13. #include <AK/Utf8View.h>
  14. namespace AK {
  15. struct FlyStringTableHashTraits : public Traits<Detail::StringData const*> {
  16. static u32 hash(Detail::StringData const* string) { return string->hash(); }
  17. static bool equals(Detail::StringData const* a, Detail::StringData const* b) { return *a == *b; }
  18. };
  19. static auto& all_fly_strings()
  20. {
  21. static Singleton<HashTable<Detail::StringData const*, FlyStringTableHashTraits>> table;
  22. return *table;
  23. }
  24. ErrorOr<FlyString> FlyString::from_utf8(StringView string)
  25. {
  26. if (string.is_empty())
  27. return FlyString {};
  28. if (string.length() <= Detail::MAX_SHORT_STRING_BYTE_COUNT)
  29. return FlyString { TRY(String::from_utf8(string)) };
  30. if (auto it = all_fly_strings().find(string.hash(), [&](auto& entry) { return entry->bytes_as_string_view() == string; }); it != all_fly_strings().end())
  31. return FlyString { Detail::StringBase(**it) };
  32. return FlyString { TRY(String::from_utf8(string)) };
  33. }
  34. FlyString FlyString::from_utf8_without_validation(ReadonlyBytes string)
  35. {
  36. if (string.is_empty())
  37. return FlyString {};
  38. if (string.size() <= Detail::MAX_SHORT_STRING_BYTE_COUNT)
  39. return FlyString { String::from_utf8_without_validation(string) };
  40. if (auto it = all_fly_strings().find(StringView(string).hash(), [&](auto& entry) { return entry->bytes_as_string_view() == string; }); it != all_fly_strings().end())
  41. return FlyString { Detail::StringBase(**it) };
  42. return FlyString { String::from_utf8_without_validation(string) };
  43. }
  44. FlyString::FlyString(String const& string)
  45. {
  46. if (string.is_short_string()) {
  47. m_data = string;
  48. return;
  49. }
  50. if (string.m_data->is_fly_string()) {
  51. m_data = string;
  52. return;
  53. }
  54. auto it = all_fly_strings().find(string.m_data);
  55. if (it == all_fly_strings().end()) {
  56. m_data = string;
  57. all_fly_strings().set(string.m_data);
  58. string.m_data->set_fly_string(true);
  59. } else {
  60. m_data.m_data = *it;
  61. m_data.m_data->ref();
  62. }
  63. }
  64. FlyString& FlyString::operator=(String const& string)
  65. {
  66. *this = FlyString { string };
  67. return *this;
  68. }
  69. bool FlyString::is_empty() const
  70. {
  71. return bytes_as_string_view().is_empty();
  72. }
  73. unsigned FlyString::hash() const
  74. {
  75. return m_data.hash();
  76. }
  77. u32 FlyString::ascii_case_insensitive_hash() const
  78. {
  79. return case_insensitive_string_hash(reinterpret_cast<char const*>(bytes().data()), bytes().size());
  80. }
  81. FlyString::operator String() const
  82. {
  83. return to_string();
  84. }
  85. String FlyString::to_string() const
  86. {
  87. Detail::StringBase copy = m_data;
  88. return String(move(copy));
  89. }
  90. Utf8View FlyString::code_points() const
  91. {
  92. return Utf8View { bytes_as_string_view() };
  93. }
  94. ReadonlyBytes FlyString::bytes() const
  95. {
  96. return bytes_as_string_view().bytes();
  97. }
  98. StringView FlyString::bytes_as_string_view() const
  99. {
  100. return m_data.bytes();
  101. }
  102. bool FlyString::operator==(String const& other) const
  103. {
  104. return m_data == other;
  105. }
  106. bool FlyString::operator==(StringView string) const
  107. {
  108. return bytes_as_string_view() == string;
  109. }
  110. bool FlyString::operator==(char const* string) const
  111. {
  112. return bytes_as_string_view() == string;
  113. }
  114. void FlyString::did_destroy_fly_string_data(Badge<Detail::StringData>, Detail::StringData const& string_data)
  115. {
  116. all_fly_strings().remove(&string_data);
  117. }
  118. Detail::StringBase FlyString::data(Badge<String>) const
  119. {
  120. return m_data;
  121. }
  122. size_t FlyString::number_of_fly_strings()
  123. {
  124. return all_fly_strings().size();
  125. }
  126. DeprecatedFlyString FlyString::to_deprecated_fly_string() const
  127. {
  128. return DeprecatedFlyString(bytes_as_string_view());
  129. }
  130. ErrorOr<FlyString> FlyString::from_deprecated_fly_string(DeprecatedFlyString const& deprecated_fly_string)
  131. {
  132. return FlyString::from_utf8(deprecated_fly_string.view());
  133. }
  134. unsigned Traits<FlyString>::hash(FlyString const& fly_string)
  135. {
  136. return fly_string.hash();
  137. }
  138. int FlyString::operator<=>(FlyString const& other) const
  139. {
  140. return bytes_as_string_view().compare(other.bytes_as_string_view());
  141. }
  142. ErrorOr<void> Formatter<FlyString>::format(FormatBuilder& builder, FlyString const& fly_string)
  143. {
  144. return Formatter<StringView>::format(builder, fly_string.bytes_as_string_view());
  145. }
  146. FlyString FlyString::to_ascii_lowercase() const
  147. {
  148. bool const has_ascii_uppercase = [&] {
  149. for (u8 const byte : bytes()) {
  150. if (AK::is_ascii_upper_alpha(byte))
  151. return true;
  152. }
  153. return false;
  154. }();
  155. if (!has_ascii_uppercase)
  156. return *this;
  157. Vector<u8> lowercase_bytes;
  158. lowercase_bytes.ensure_capacity(bytes().size());
  159. for (u8 const byte : bytes()) {
  160. if (AK::is_ascii_upper_alpha(byte))
  161. lowercase_bytes.unchecked_append(AK::to_ascii_lowercase(byte));
  162. else
  163. lowercase_bytes.unchecked_append(byte);
  164. }
  165. return String::from_utf8_without_validation(lowercase_bytes);
  166. }
  167. FlyString FlyString::to_ascii_uppercase() const
  168. {
  169. bool const has_ascii_lowercase = [&] {
  170. for (u8 const byte : bytes()) {
  171. if (AK::is_ascii_lower_alpha(byte))
  172. return true;
  173. }
  174. return false;
  175. }();
  176. if (!has_ascii_lowercase)
  177. return *this;
  178. Vector<u8> uppercase_bytes;
  179. uppercase_bytes.ensure_capacity(bytes().size());
  180. for (u8 const byte : bytes()) {
  181. if (AK::is_ascii_lower_alpha(byte))
  182. uppercase_bytes.unchecked_append(AK::to_ascii_uppercase(byte));
  183. else
  184. uppercase_bytes.unchecked_append(byte);
  185. }
  186. return String::from_utf8_without_validation(uppercase_bytes);
  187. }
  188. bool FlyString::equals_ignoring_ascii_case(FlyString const& other) const
  189. {
  190. if (*this == other)
  191. return true;
  192. return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other.bytes_as_string_view());
  193. }
  194. bool FlyString::equals_ignoring_ascii_case(StringView other) const
  195. {
  196. return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other);
  197. }
  198. bool FlyString::starts_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const
  199. {
  200. return bytes_as_string_view().starts_with(bytes, case_sensitivity);
  201. }
  202. bool FlyString::ends_with_bytes(StringView bytes, CaseSensitivity case_sensitivity) const
  203. {
  204. return bytes_as_string_view().ends_with(bytes, case_sensitivity);
  205. }
  206. }