/src/serenity/AK/FlyString.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/FlyString.h> |
8 | | #include <AK/HashTable.h> |
9 | | #include <AK/Optional.h> |
10 | | #include <AK/Singleton.h> |
11 | | #include <AK/String.h> |
12 | | #include <AK/StringUtils.h> |
13 | | #include <AK/StringView.h> |
14 | | |
15 | | namespace AK { |
16 | | |
17 | | struct FlyStringImplTraits : public Traits<StringImpl*> { |
18 | 0 | static unsigned hash(StringImpl const* s) { return s ? s->hash() : 0; } |
19 | | static bool equals(StringImpl const* a, StringImpl const* b) |
20 | 0 | { |
21 | 0 | VERIFY(a); |
22 | 0 | VERIFY(b); |
23 | 0 | return *a == *b; |
24 | 0 | } |
25 | | }; |
26 | | |
27 | | static Singleton<HashTable<StringImpl*, FlyStringImplTraits>> s_table; |
28 | | |
29 | | static HashTable<StringImpl*, FlyStringImplTraits>& fly_impls() |
30 | 0 | { |
31 | 0 | return *s_table; |
32 | 0 | } |
33 | | |
34 | | void FlyString::did_destroy_impl(Badge<StringImpl>, StringImpl& impl) |
35 | 0 | { |
36 | 0 | fly_impls().remove(&impl); |
37 | 0 | } |
38 | | |
39 | | FlyString::FlyString(String const& string) |
40 | 0 | { |
41 | 0 | if (string.is_null()) |
42 | 0 | return; |
43 | 0 | if (string.impl()->is_fly()) { |
44 | 0 | m_impl = string.impl(); |
45 | 0 | return; |
46 | 0 | } |
47 | 0 | auto it = fly_impls().find(const_cast<StringImpl*>(string.impl())); |
48 | 0 | if (it == fly_impls().end()) { |
49 | 0 | fly_impls().set(const_cast<StringImpl*>(string.impl())); |
50 | 0 | string.impl()->set_fly({}, true); |
51 | 0 | m_impl = string.impl(); |
52 | 0 | } else { |
53 | 0 | VERIFY((*it)->is_fly()); |
54 | 0 | m_impl = *it; |
55 | 0 | } |
56 | 0 | } |
57 | | |
58 | | FlyString::FlyString(StringView string) |
59 | 0 | { |
60 | 0 | if (string.is_null()) |
61 | 0 | return; |
62 | 0 | auto it = fly_impls().find(string.hash(), [&](auto& candidate) { |
63 | 0 | return string == candidate; |
64 | 0 | }); |
65 | 0 | if (it == fly_impls().end()) { |
66 | 0 | auto new_string = string.to_string(); |
67 | 0 | fly_impls().set(new_string.impl()); |
68 | 0 | new_string.impl()->set_fly({}, true); |
69 | 0 | m_impl = new_string.impl(); |
70 | 0 | } else { |
71 | 0 | VERIFY((*it)->is_fly()); |
72 | 0 | m_impl = *it; |
73 | 0 | } |
74 | 0 | } |
75 | | |
76 | | template<typename T> |
77 | | Optional<T> FlyString::to_int(TrimWhitespace trim_whitespace) const |
78 | 0 | { |
79 | 0 | return StringUtils::convert_to_int<T>(view(), trim_whitespace); |
80 | 0 | } Unexecuted instantiation: AK::Optional<signed char> AK::FlyString::to_int<signed char>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<short> AK::FlyString::to_int<short>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<int> AK::FlyString::to_int<int>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<long> AK::FlyString::to_int<long>(AK::TrimWhitespace) const |
81 | | |
82 | | template Optional<i8> FlyString::to_int(TrimWhitespace) const; |
83 | | template Optional<i16> FlyString::to_int(TrimWhitespace) const; |
84 | | template Optional<i32> FlyString::to_int(TrimWhitespace) const; |
85 | | template Optional<i64> FlyString::to_int(TrimWhitespace) const; |
86 | | |
87 | | template<typename T> |
88 | | Optional<T> FlyString::to_uint(TrimWhitespace trim_whitespace) const |
89 | 0 | { |
90 | 0 | return StringUtils::convert_to_uint<T>(view(), trim_whitespace); |
91 | 0 | } Unexecuted instantiation: AK::Optional<unsigned char> AK::FlyString::to_uint<unsigned char>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<unsigned short> AK::FlyString::to_uint<unsigned short>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<unsigned int> AK::FlyString::to_uint<unsigned int>(AK::TrimWhitespace) const Unexecuted instantiation: AK::Optional<unsigned long> AK::FlyString::to_uint<unsigned long>(AK::TrimWhitespace) const |
92 | | |
93 | | template Optional<u8> FlyString::to_uint(TrimWhitespace) const; |
94 | | template Optional<u16> FlyString::to_uint(TrimWhitespace) const; |
95 | | template Optional<u32> FlyString::to_uint(TrimWhitespace) const; |
96 | | template Optional<u64> FlyString::to_uint(TrimWhitespace) const; |
97 | | |
98 | | bool FlyString::equals_ignoring_case(StringView other) const |
99 | 0 | { |
100 | 0 | return StringUtils::equals_ignoring_case(view(), other); |
101 | 0 | } |
102 | | |
103 | | bool FlyString::starts_with(StringView str, CaseSensitivity case_sensitivity) const |
104 | 0 | { |
105 | 0 | return StringUtils::starts_with(view(), str, case_sensitivity); |
106 | 0 | } |
107 | | |
108 | | bool FlyString::ends_with(StringView str, CaseSensitivity case_sensitivity) const |
109 | 0 | { |
110 | 0 | return StringUtils::ends_with(view(), str, case_sensitivity); |
111 | 0 | } |
112 | | |
113 | | FlyString FlyString::to_lowercase() const |
114 | 0 | { |
115 | 0 | return String(*m_impl).to_lowercase(); |
116 | 0 | } |
117 | | |
118 | | bool FlyString::operator==(String const& other) const |
119 | 0 | { |
120 | 0 | return m_impl == other.impl() || view() == other.view(); |
121 | 0 | } |
122 | | |
123 | | bool FlyString::operator==(StringView string) const |
124 | 0 | { |
125 | 0 | return view() == string; |
126 | 0 | } |
127 | | |
128 | | bool FlyString::operator==(char const* string) const |
129 | 0 | { |
130 | 0 | return view() == string; |
131 | 0 | } |
132 | | |
133 | | } |