Serenity Operating System
1/*
2 * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/DeprecatedFlyString.h>
8#include <AK/FlyString.h>
9#include <AK/HashMap.h>
10#include <AK/Singleton.h>
11#include <AK/StringView.h>
12#include <AK/Utf8View.h>
13
14namespace AK {
15
16static auto& all_fly_strings()
17{
18 static Singleton<HashMap<StringView, uintptr_t>> table;
19 return *table;
20}
21
22FlyString::FlyString()
23 : m_data(String {}.to_fly_string_data({}))
24{
25}
26
27FlyString::~FlyString()
28{
29 String::unref_fly_string_data({}, m_data);
30}
31
32ErrorOr<FlyString> FlyString::from_utf8(StringView string)
33{
34 return FlyString { TRY(String::from_utf8(string)) };
35}
36
37FlyString::FlyString(String const& string)
38{
39 if (string.is_short_string()) {
40 m_data = string.to_fly_string_data({});
41 return;
42 }
43
44 auto it = all_fly_strings().find(string.bytes_as_string_view());
45 if (it == all_fly_strings().end()) {
46 m_data = string.to_fly_string_data({});
47
48 all_fly_strings().set(string.bytes_as_string_view(), m_data);
49 string.did_create_fly_string({});
50 } else {
51 m_data = it->value;
52 }
53
54 String::ref_fly_string_data({}, m_data);
55}
56
57FlyString& FlyString::operator=(String const& string)
58{
59 *this = FlyString { string };
60 return *this;
61}
62
63FlyString::FlyString(FlyString const& other)
64 : m_data(other.m_data)
65{
66 String::ref_fly_string_data({}, m_data);
67}
68
69FlyString& FlyString::operator=(FlyString const& other)
70{
71 if (this != &other) {
72 m_data = other.m_data;
73 String::ref_fly_string_data({}, m_data);
74 }
75
76 return *this;
77}
78
79FlyString::FlyString(FlyString&& other)
80 : m_data(other.m_data)
81{
82 other.m_data = String {}.to_fly_string_data({});
83}
84
85FlyString& FlyString::operator=(FlyString&& other)
86{
87 m_data = other.m_data;
88 other.m_data = String {}.to_fly_string_data({});
89
90 return *this;
91}
92
93bool FlyString::is_empty() const
94{
95 return bytes_as_string_view().is_empty();
96}
97
98unsigned FlyString::hash() const
99{
100 return String::fly_string_data_to_hash({}, m_data);
101}
102
103FlyString::operator String() const
104{
105 return to_string();
106}
107
108String FlyString::to_string() const
109{
110 return String::fly_string_data_to_string({}, m_data);
111}
112
113Utf8View FlyString::code_points() const
114{
115 return Utf8View { bytes_as_string_view() };
116}
117
118ReadonlyBytes FlyString::bytes() const
119{
120 return bytes_as_string_view().bytes();
121}
122
123StringView FlyString::bytes_as_string_view() const
124{
125 return String::fly_string_data_to_string_view({}, m_data);
126}
127
128bool FlyString::operator==(FlyString const& other) const
129{
130 return m_data == other.m_data;
131}
132
133bool FlyString::operator==(String const& other) const
134{
135 if (m_data == other.to_fly_string_data({}))
136 return true;
137
138 return bytes_as_string_view() == other.bytes_as_string_view();
139}
140
141bool FlyString::operator==(StringView string) const
142{
143 return bytes_as_string_view() == string;
144}
145
146bool FlyString::operator==(char const* string) const
147{
148 return bytes_as_string_view() == string;
149}
150
151void FlyString::did_destroy_fly_string_data(Badge<Detail::StringData>, StringView string_data)
152{
153 all_fly_strings().remove(string_data);
154}
155
156uintptr_t FlyString::data(Badge<String>) const
157{
158 return m_data;
159}
160
161size_t FlyString::number_of_fly_strings()
162{
163 return all_fly_strings().size();
164}
165
166DeprecatedFlyString FlyString::to_deprecated_fly_string() const
167{
168 return DeprecatedFlyString(bytes_as_string_view());
169}
170
171ErrorOr<FlyString> FlyString::from_deprecated_fly_string(DeprecatedFlyString const& deprecated_fly_string)
172{
173 return FlyString::from_utf8(deprecated_fly_string.view());
174}
175
176unsigned Traits<FlyString>::hash(FlyString const& fly_string)
177{
178 return fly_string.hash();
179}
180
181ErrorOr<void> Formatter<FlyString>::format(FormatBuilder& builder, FlyString const& fly_string)
182{
183 return Formatter<StringView>::format(builder, fly_string.bytes_as_string_view());
184}
185
186bool FlyString::equals_ignoring_ascii_case(FlyString const& other) const
187{
188 if (*this == other)
189 return true;
190 return StringUtils::equals_ignoring_ascii_case(bytes_as_string_view(), other.bytes_as_string_view());
191}
192
193}