[WTF] Remove StaticLock
[WebKit.git] / Source / WTF / wtf / text / StringView.cpp
1 /*
2
3 Copyright (C) 2014-2017 Apple Inc. 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
7 are met:
8 1.  Redistributions of source code must retain the above copyright
9     notice, this list of conditions and the following disclaimer.
10 2.  Redistributions in binary form must reproduce the above copyright
11     notice, this list of conditions and the following disclaimer in the
12     documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25 */
26
27 #include "config.h"
28 #include "StringView.h"
29
30 #include <mutex>
31 #include <unicode/ubrk.h>
32 #include <wtf/HashMap.h>
33 #include <wtf/Lock.h>
34 #include <wtf/NeverDestroyed.h>
35 #include <wtf/Optional.h>
36 #include <wtf/text/TextBreakIterator.h>
37 #include <wtf/unicode/UTF8.h>
38
39 namespace WTF {
40
41 using namespace Unicode;
42
43 bool StringView::containsIgnoringASCIICase(const StringView& matchString) const
44 {
45     return findIgnoringASCIICase(matchString) != notFound;
46 }
47
48 bool StringView::containsIgnoringASCIICase(const StringView& matchString, unsigned startOffset) const
49 {
50     return findIgnoringASCIICase(matchString, startOffset) != notFound;
51 }
52
53 size_t StringView::findIgnoringASCIICase(const StringView& matchString) const
54 {
55     return ::WTF::findIgnoringASCIICase(*this, matchString, 0);
56 }
57
58 size_t StringView::findIgnoringASCIICase(const StringView& matchString, unsigned startOffset) const
59 {
60     return ::WTF::findIgnoringASCIICase(*this, matchString, startOffset);
61 }
62
63 bool StringView::startsWith(const StringView& prefix) const
64 {
65     return ::WTF::startsWith(*this, prefix);
66 }
67
68 bool StringView::startsWithIgnoringASCIICase(const StringView& prefix) const
69 {
70     return ::WTF::startsWithIgnoringASCIICase(*this, prefix);
71 }
72
73 bool StringView::endsWith(const StringView& suffix) const
74 {
75     return ::WTF::endsWith(*this, suffix);
76 }
77
78 bool StringView::endsWithIgnoringASCIICase(const StringView& suffix) const
79 {
80     return ::WTF::endsWithIgnoringASCIICase(*this, suffix);
81 }
82
83 CString StringView::utf8(ConversionMode mode) const
84 {
85     if (isNull())
86         return CString("", 0);
87     if (is8Bit())
88         return StringImpl::utf8ForCharacters(characters8(), length());
89     return StringImpl::utf8ForCharacters(characters16(), length(), mode);
90 }
91
92 size_t StringView::find(StringView matchString, unsigned start) const
93 {
94     return findCommon(*this, matchString, start);
95 }
96
97 void StringView::SplitResult::Iterator::findNextSubstring()
98 {
99     for (size_t separatorPosition; (separatorPosition = m_result.m_string.find(m_result.m_separator, m_position)) != notFound; ++m_position) {
100         if (separatorPosition > m_position) {
101             m_length = separatorPosition - m_position;
102             return;
103         }
104     }
105     m_length = m_result.m_string.length() - m_position;
106 }
107
108 auto StringView::SplitResult::Iterator::operator++() -> Iterator&
109 {
110     ASSERT(m_position < m_result.m_string.length());
111     m_position += m_length;
112     if (m_position < m_result.m_string.length()) {
113         ++m_position;
114         findNextSubstring();
115     }
116     return *this;
117 }
118
119 class StringView::GraphemeClusters::Iterator::Impl {
120 public:
121     Impl(const StringView& stringView, std::optional<NonSharedCharacterBreakIterator>&& iterator, unsigned index)
122         : m_stringView(stringView)
123         , m_iterator(WTFMove(iterator))
124         , m_index(index)
125         , m_indexEnd(computeIndexEnd())
126     {
127     }
128
129     void operator++()
130     {
131         ASSERT(m_indexEnd > m_index);
132         m_index = m_indexEnd;
133         m_indexEnd = computeIndexEnd();
134     }
135
136     StringView operator*() const
137     {
138         if (m_stringView.is8Bit())
139             return StringView(m_stringView.characters8() + m_index, m_indexEnd - m_index);
140         return StringView(m_stringView.characters16() + m_index, m_indexEnd - m_index);
141     }
142
143     bool operator==(const Impl& other) const
144     {
145         ASSERT(&m_stringView == &other.m_stringView);
146         auto result = m_index == other.m_index;
147         ASSERT(!result || m_indexEnd == other.m_indexEnd);
148         return result;
149     }
150
151     unsigned computeIndexEnd()
152     {
153         if (!m_iterator)
154             return 0;
155         if (m_index == m_stringView.length())
156             return m_index;
157         return ubrk_following(m_iterator.value(), m_index);
158     }
159
160 private:
161     const StringView& m_stringView;
162     std::optional<NonSharedCharacterBreakIterator> m_iterator;
163     unsigned m_index;
164     unsigned m_indexEnd;
165 };
166
167 StringView::GraphemeClusters::Iterator::Iterator(const StringView& stringView, unsigned index)
168     : m_impl(std::make_unique<Impl>(stringView, stringView.isNull() ? std::nullopt : std::optional<NonSharedCharacterBreakIterator>(NonSharedCharacterBreakIterator(stringView)), index))
169 {
170 }
171
172 StringView::GraphemeClusters::Iterator::~Iterator()
173 {
174 }
175
176 StringView::GraphemeClusters::Iterator::Iterator(Iterator&& other)
177     : m_impl(WTFMove(other.m_impl))
178 {
179 }
180
181 auto StringView::GraphemeClusters::Iterator::operator++() -> Iterator&
182 {
183     ++(*m_impl);
184     return *this;
185 }
186
187 StringView StringView::GraphemeClusters::Iterator::operator*() const
188 {
189     return **m_impl;
190 }
191
192 bool StringView::GraphemeClusters::Iterator::operator==(const Iterator& other) const
193 {
194     return *m_impl == *(other.m_impl);
195 }
196
197 bool StringView::GraphemeClusters::Iterator::operator!=(const Iterator& other) const
198 {
199     return !(*this == other);
200 }
201
202 #if CHECK_STRINGVIEW_LIFETIME
203
204 // Manage reference count manually so UnderlyingString does not need to be defined in the header.
205
206 struct StringView::UnderlyingString {
207     std::atomic_uint refCount { 1u };
208     bool isValid { true };
209     const StringImpl& string;
210     explicit UnderlyingString(const StringImpl&);
211 };
212
213 StringView::UnderlyingString::UnderlyingString(const StringImpl& string)
214     : string(string)
215 {
216 }
217
218 static Lock underlyingStringsMutex;
219
220 static HashMap<const StringImpl*, StringView::UnderlyingString*>& underlyingStrings()
221 {
222     static NeverDestroyed<HashMap<const StringImpl*, StringView::UnderlyingString*>> map;
223     return map;
224 }
225
226 void StringView::invalidate(const StringImpl& stringToBeDestroyed)
227 {
228     UnderlyingString* underlyingString;
229     {
230         std::lock_guard<Lock> lock(underlyingStringsMutex);
231         underlyingString = underlyingStrings().take(&stringToBeDestroyed);
232         if (!underlyingString)
233             return;
234     }
235     ASSERT(underlyingString->isValid);
236     underlyingString->isValid = false;
237 }
238
239 bool StringView::underlyingStringIsValid() const
240 {
241     return !m_underlyingString || m_underlyingString->isValid;
242 }
243
244 void StringView::adoptUnderlyingString(UnderlyingString* underlyingString)
245 {
246     if (m_underlyingString) {
247         std::lock_guard<Lock> lock(underlyingStringsMutex);
248         if (!--m_underlyingString->refCount) {
249             if (m_underlyingString->isValid) {
250                 underlyingStrings().remove(&m_underlyingString->string);
251             }
252             delete m_underlyingString;
253         }
254     }
255     m_underlyingString = underlyingString;
256 }
257
258 void StringView::setUnderlyingString(const StringImpl* string)
259 {
260     UnderlyingString* underlyingString;
261     if (!string)
262         underlyingString = nullptr;
263     else {
264         std::lock_guard<Lock> lock(underlyingStringsMutex);
265         auto result = underlyingStrings().add(string, nullptr);
266         if (result.isNewEntry)
267             result.iterator->value = new UnderlyingString(*string);
268         else
269             ++result.iterator->value->refCount;
270         underlyingString = result.iterator->value;
271     }
272     adoptUnderlyingString(underlyingString);
273 }
274
275 void StringView::setUnderlyingString(const StringView& otherString)
276 {
277     UnderlyingString* underlyingString = otherString.m_underlyingString;
278     if (underlyingString)
279         ++underlyingString->refCount;
280     adoptUnderlyingString(underlyingString);
281 }
282
283 #endif // CHECK_STRINGVIEW_LIFETIME
284
285 } // namespace WTF