Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/FlyString.h>
28#include <AK/HashTable.h>
29#include <AK/String.h>
30#include <AK/StringUtils.h>
31#include <AK/StringView.h>
32
33namespace AK {
34
35struct FlyStringImplTraits : public AK::Traits<StringImpl*> {
36 static unsigned hash(const StringImpl* s) { return s ? s->hash() : 0; }
37 static bool equals(const StringImpl* a, const StringImpl* b)
38 {
39 ASSERT(a);
40 ASSERT(b);
41 if (a == b)
42 return true;
43 if (a->length() != b->length())
44 return false;
45 return !__builtin_memcmp(a->characters(), b->characters(), a->length());
46 }
47};
48
49static HashTable<StringImpl*, FlyStringImplTraits>& fly_impls()
50{
51 static HashTable<StringImpl*, FlyStringImplTraits>* table;
52 if (!table)
53 table = new HashTable<StringImpl*, FlyStringImplTraits>;
54 return *table;
55}
56
57void FlyString::did_destroy_impl(Badge<StringImpl>, StringImpl& impl)
58{
59 fly_impls().remove(&impl);
60}
61
62FlyString::FlyString(const String& string)
63{
64 if (string.is_null())
65 return;
66 auto it = fly_impls().find(const_cast<StringImpl*>(string.impl()));
67 if (it == fly_impls().end()) {
68 fly_impls().set(const_cast<StringImpl*>(string.impl()));
69 string.impl()->set_fly({}, true);
70 m_impl = string.impl();
71 } else {
72 ASSERT((*it)->is_fly());
73 m_impl = *it;
74 }
75}
76
77FlyString::FlyString(const StringView& string)
78 : FlyString(static_cast<String>(string))
79{
80}
81
82FlyString::FlyString(const char* string)
83 : FlyString(static_cast<String>(string))
84{
85}
86
87int FlyString::to_int(bool& ok) const
88{
89 return StringUtils::convert_to_int(view(), ok);
90}
91
92bool FlyString::equals_ignoring_case(const StringView& other) const
93{
94 return StringUtils::equals_ignoring_case(view(), other);
95}
96
97FlyString FlyString::to_lowercase() const
98{
99 return String(*m_impl).to_lowercase();
100}
101
102StringView FlyString::view() const
103{
104 return { characters(), length() };
105}
106
107bool FlyString::operator==(const String& string) const
108{
109 if (m_impl == string.impl())
110 return true;
111 return String(m_impl.ptr()) == string;
112}
113
114bool FlyString::operator==(const StringView& string) const
115{
116 return String(string) == String(m_impl.ptr());
117}
118
119bool FlyString::operator==(const char* string) const
120{
121 if (is_null())
122 return !string;
123 if (!string)
124 return false;
125 return !__builtin_strcmp(m_impl->characters(), string);
126}
127
128}