1 /*
2  * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20 
21 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_ATOMIC_STRING_H_
22 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_ATOMIC_STRING_H_
23 
24 #include <cstring>
25 #include <iosfwd>
26 
27 #include "build/build_config.h"
28 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
29 #include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h"
30 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
31 #include "third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h"
32 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
33 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
34 #include "third_party/blink/renderer/platform/wtf/wtf_export.h"
35 
36 namespace WTF {
37 
38 struct AtomicStringHash;
39 
40 // An AtomicString instance represents a string, and multiple AtomicString
41 // instances can share their string storage if the strings are
42 // identical. Comparing two AtomicString instances is much faster than comparing
43 // two String instances because we just check string storage identity.
44 //
45 // AtomicString instances are not thread-safe. An AtomicString instance created
46 // in a thread must be used only in the creator thread.  If multiple threads
47 // access a single AtomicString instance, we have race condition of a reference
48 // count in StringImpl, and would hit a runtime CHECK in
49 // AtomicStringTable::remove().
50 //
51 // Exception: g_null_atom and g_empty_atom, are shared in multiple threads, and
52 // are never stored in AtomicStringTable.
53 class WTF_EXPORT AtomicString {
54   USING_FAST_MALLOC(AtomicString);
55 
56  public:
57   // The function is defined in StringStatics.cpp.
58   static void Init();
59 
60   AtomicString() = default;
AtomicString(const LChar * chars)61   AtomicString(const LChar* chars)
62       : AtomicString(chars,
63                      chars ? strlen(reinterpret_cast<const char*>(chars)) : 0) {
64   }
65 
66 #if defined(ARCH_CPU_64_BITS)
67   // Only define a size_t constructor if size_t is 64 bit otherwise
68   // we'd have a duplicate define.
69   AtomicString(const LChar* chars, size_t length);
70 #endif  // defined(ARCH_CPU_64_BITS)
71 
AtomicString(const char * chars)72   AtomicString(const char* chars)
73       : AtomicString(reinterpret_cast<const LChar*>(chars)) {}
74   AtomicString(const LChar* chars, unsigned length);
75   AtomicString(const UChar* chars, unsigned length);
76   AtomicString(const UChar* chars);
AtomicString(const char16_t * chars)77   AtomicString(const char16_t* chars)
78       : AtomicString(reinterpret_cast<const UChar*>(chars)) {}
79 
80   template <wtf_size_t inlineCapacity>
AtomicString(const Vector<UChar,inlineCapacity> & vector)81   explicit AtomicString(const Vector<UChar, inlineCapacity>& vector)
82       : AtomicString(vector.data(), vector.size()) {}
83 
84   // Constructing an AtomicString from a String / StringImpl can be expensive if
85   // the StringImpl is not already atomic.
AtomicString(StringImpl * impl)86   explicit AtomicString(StringImpl* impl) : string_(Add(impl)) {}
AtomicString(const String & s)87   explicit AtomicString(const String& s) : string_(Add(s.Impl())) {}
88 
89   explicit operator bool() const { return !IsNull(); }
90   operator const String&() const { return string_; }
GetString()91   const String& GetString() const { return string_; }
92 
Impl()93   StringImpl* Impl() const { return string_.Impl(); }
94 
Is8Bit()95   bool Is8Bit() const { return string_.Is8Bit(); }
Characters8()96   const LChar* Characters8() const { return string_.Characters8(); }
Characters16()97   const UChar* Characters16() const { return string_.Characters16(); }
length()98   wtf_size_t length() const { return string_.length(); }
99 
100   UChar operator[](wtf_size_t i) const { return string_[i]; }
101 
102   // Find characters.
103   wtf_size_t find(UChar c, wtf_size_t start = 0) const {
104     return string_.find(c, start);
105   }
106   wtf_size_t find(LChar c, wtf_size_t start = 0) const {
107     return string_.find(c, start);
108   }
109   wtf_size_t find(char c, wtf_size_t start = 0) const {
110     return find(static_cast<LChar>(c), start);
111   }
112   wtf_size_t Find(CharacterMatchFunctionPtr match_function,
113                   wtf_size_t start = 0) const {
114     return string_.Find(match_function, start);
115   }
116 
117   // Find substrings.
118   wtf_size_t Find(
119       const StringView& value,
120       wtf_size_t start = 0,
121       TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const {
122     return string_.Find(value, start, case_sensitivity);
123   }
124 
125   // Unicode aware case insensitive string matching. Non-ASCII characters might
126   // match to ASCII characters. This function is rarely used to implement web
127   // platform features.
128   wtf_size_t FindIgnoringCase(const StringView& value,
129                               wtf_size_t start = 0) const {
130     return string_.FindIgnoringCase(value, start);
131   }
132 
133   // ASCII case insensitive string matching.
134   wtf_size_t FindIgnoringASCIICase(const StringView& value,
135                                    wtf_size_t start = 0) const {
136     return string_.FindIgnoringASCIICase(value, start);
137   }
138 
Contains(char c)139   bool Contains(char c) const { return find(c) != kNotFound; }
140   bool Contains(
141       const StringView& value,
142       TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const {
143     return Find(value, 0, case_sensitivity) != kNotFound;
144   }
145 
146   // Find the last instance of a single character or string.
147   wtf_size_t ReverseFind(UChar c, wtf_size_t start = UINT_MAX) const {
148     return string_.ReverseFind(c, start);
149   }
150   wtf_size_t ReverseFind(const StringView& value,
151                          wtf_size_t start = UINT_MAX) const {
152     return string_.ReverseFind(value, start);
153   }
154 
155   bool StartsWith(
156       const StringView& prefix,
157       TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const {
158     return string_.StartsWith(prefix, case_sensitivity);
159   }
StartsWithIgnoringCase(const StringView & prefix)160   bool StartsWithIgnoringCase(const StringView& prefix) const {
161     return string_.StartsWithIgnoringCase(prefix);
162   }
StartsWithIgnoringASCIICase(const StringView & prefix)163   bool StartsWithIgnoringASCIICase(const StringView& prefix) const {
164     return string_.StartsWithIgnoringASCIICase(prefix);
165   }
StartsWith(UChar character)166   bool StartsWith(UChar character) const {
167     return string_.StartsWith(character);
168   }
169 
170   bool EndsWith(
171       const StringView& suffix,
172       TextCaseSensitivity case_sensitivity = kTextCaseSensitive) const {
173     return string_.EndsWith(suffix, case_sensitivity);
174   }
EndsWith(UChar character)175   bool EndsWith(UChar character) const { return string_.EndsWith(character); }
176 
177   // Returns a lowercase/uppercase version of the string.
178   // These functions convert ASCII characters only.
179   AtomicString LowerASCII() const;
180   AtomicString UpperASCII() const;
181 
182   // See comments in WTFString.h.
183   int ToInt(bool* ok = nullptr) const { return string_.ToInt(ok); }
184   double ToDouble(bool* ok = nullptr) const { return string_.ToDouble(ok); }
185   float ToFloat(bool* ok = nullptr) const { return string_.ToFloat(ok); }
186 
187   template <typename IntegerType>
Number(IntegerType number)188   static AtomicString Number(IntegerType number) {
189     IntegerToStringConverter<IntegerType> converter(number);
190     return AtomicString(converter.Characters8(), converter.length());
191   }
192 
193   static AtomicString Number(double, unsigned precision = 6);
194 
IsNull()195   bool IsNull() const { return string_.IsNull(); }
IsEmpty()196   bool IsEmpty() const { return string_.IsEmpty(); }
197 
198 #ifdef __OBJC__
AtomicString(NSString * s)199   AtomicString(NSString* s) : string_(Add((CFStringRef)s)) {}
200   operator NSString*() const { return string_; }
201 #endif
202   // AtomicString::fromUTF8 will return a null string if
203   // the input data contains invalid UTF-8 sequences.
204   // NOTE: Passing a zero size means use the whole string.
205   static AtomicString FromUTF8(const char*, size_t length);
206   static AtomicString FromUTF8(const char*);
207 
Ascii()208   std::string Ascii() const { return string_.Ascii(); }
Latin1()209   std::string Latin1() const { return string_.Latin1(); }
210   std::string Utf8(UTF8ConversionMode mode = kLenientUTF8Conversion) const {
211     return string_.Utf8(mode);
212   }
213 
CharactersSizeInBytes()214   size_t CharactersSizeInBytes() const {
215     return string_.CharactersSizeInBytes();
216   }
217 
IsSafeToSendToAnotherThread()218   bool IsSafeToSendToAnotherThread() const {
219     return string_.IsSafeToSendToAnotherThread();
220   }
221 
222 #ifndef NDEBUG
223   void Show() const;
224 #endif
225 
226  private:
227   friend struct HashTraits<AtomicString>;
228 
229   String string_;
230 
231   ALWAYS_INLINE static scoped_refptr<StringImpl> Add(StringImpl* r) {
232     if (!r || r->IsAtomic())
233       return r;
234     return AddSlowCase(r);
235   }
236   static scoped_refptr<StringImpl> AddSlowCase(StringImpl*);
237 #if defined(OS_MAC)
238   static scoped_refptr<StringImpl> Add(CFStringRef);
239 #endif
240 };
241 
242 inline bool operator==(const AtomicString& a, const AtomicString& b) {
243   return a.Impl() == b.Impl();
244 }
245 inline bool operator==(const AtomicString& a, const String& b) {
246   // We don't use equalStringView so we get the isAtomic() optimization inside
247   // WTF::equal.
248   return Equal(a.Impl(), b.Impl());
249 }
250 inline bool operator==(const String& a, const AtomicString& b) {
251   return b == a;
252 }
253 inline bool operator==(const AtomicString& a, const char* b) {
254   return EqualStringView(a, b);
255 }
256 inline bool operator==(const char* a, const AtomicString& b) {
257   return b == a;
258 }
259 
260 inline bool operator!=(const AtomicString& a, const AtomicString& b) {
261   return a.Impl() != b.Impl();
262 }
263 inline bool operator!=(const AtomicString& a, const String& b) {
264   return !(a == b);
265 }
266 inline bool operator!=(const String& a, const AtomicString& b) {
267   return !(a == b);
268 }
269 inline bool operator!=(const AtomicString& a, const char* b) {
270   return !(a == b);
271 }
272 inline bool operator!=(const char* a, const AtomicString& b) {
273   return !(a == b);
274 }
275 
276 // Define external global variables for the commonly used atomic strings.
277 // These are only usable from the main thread.
278 WTF_EXPORT extern const AtomicString& g_null_atom;
279 WTF_EXPORT extern const AtomicString& g_empty_atom;
280 WTF_EXPORT extern const AtomicString& g_star_atom;
281 WTF_EXPORT extern const AtomicString& g_xml_atom;
282 WTF_EXPORT extern const AtomicString& g_xmlns_atom;
283 WTF_EXPORT extern const AtomicString& g_xlink_atom;
284 WTF_EXPORT extern const AtomicString& g_http_atom;
285 WTF_EXPORT extern const AtomicString& g_https_atom;
286 
287 // AtomicStringHash is the default hash for AtomicString
288 template <typename T>
289 struct DefaultHash;
290 template <>
291 struct DefaultHash<AtomicString> {
292   typedef AtomicStringHash Hash;
293 };
294 
295 // Pretty printer for gtest and base/logging.*.  It prepends and appends
296 // double-quotes, and escapes characters other than ASCII printables.
297 WTF_EXPORT std::ostream& operator<<(std::ostream&, const AtomicString&);
298 
299 inline StringView::StringView(const AtomicString& string,
300                               unsigned offset,
301                               unsigned length)
302     : StringView(string.Impl(), offset, length) {}
303 inline StringView::StringView(const AtomicString& string, unsigned offset)
304     : StringView(string.Impl(), offset) {}
305 inline StringView::StringView(const AtomicString& string)
306     : StringView(string.Impl()) {}
307 
308 }  // namespace WTF
309 
310 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(AtomicString)
311 
312 using WTF::AtomicString;
313 using WTF::g_null_atom;
314 using WTF::g_empty_atom;
315 using WTF::g_star_atom;
316 using WTF::g_xml_atom;
317 using WTF::g_xmlns_atom;
318 using WTF::g_xlink_atom;
319 
320 #include "third_party/blink/renderer/platform/wtf/text/string_concatenate.h"
321 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TEXT_ATOMIC_STRING_H_
322