1/*
2 * Copyright (C) 2004-2017 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#pragma once
22
23#include <utility>
24#include <wtf/NeverDestroyed.h>
25#include <wtf/text/AtomicStringImpl.h>
26#include <wtf/text/IntegerToStringConversion.h>
27#include <wtf/text/WTFString.h>
28
29#if OS(WINDOWS)
30#include <wtf/text/win/WCharStringExtras.h>
31#endif
32
33// Define 'NO_IMPLICIT_ATOMICSTRING' before including this header,
34// to disallow (expensive) implicit String-->AtomicString conversions.
35#ifdef NO_IMPLICIT_ATOMICSTRING
36#define ATOMICSTRING_CONVERSION explicit
37#else
38#define ATOMICSTRING_CONVERSION
39#endif
40
41namespace WTF {
42
43struct AtomicStringHash;
44
45class AtomicString {
46public:
47 WTF_EXPORT_PRIVATE static void init();
48
49 AtomicString();
50 AtomicString(const LChar*);
51 AtomicString(const char*);
52 AtomicString(const LChar*, unsigned length);
53 AtomicString(const UChar*, unsigned length);
54 AtomicString(const UChar*);
55
56 template<size_t inlineCapacity>
57 explicit AtomicString(const Vector<UChar, inlineCapacity>& characters)
58 : m_string(AtomicStringImpl::add(characters.data(), characters.size()))
59 {
60 }
61
62 AtomicString(AtomicStringImpl*);
63 AtomicString(RefPtr<AtomicStringImpl>&&);
64 AtomicString(const StaticStringImpl*);
65 ATOMICSTRING_CONVERSION AtomicString(StringImpl*);
66 ATOMICSTRING_CONVERSION AtomicString(const String&);
67 AtomicString(StringImpl* baseString, unsigned start, unsigned length);
68
69 // FIXME: AtomicString doesn’t always have AtomicStringImpl, so one of those two names needs to change..
70 AtomicString(UniquedStringImpl* uid);
71
72 enum ConstructFromLiteralTag { ConstructFromLiteral };
73 AtomicString(const char* characters, unsigned length, ConstructFromLiteralTag)
74 : m_string(AtomicStringImpl::addLiteral(characters, length))
75 {
76 }
77
78 template<unsigned characterCount> ALWAYS_INLINE AtomicString(const char (&characters)[characterCount], ConstructFromLiteralTag)
79 : m_string(AtomicStringImpl::addLiteral(characters, characterCount - 1))
80 {
81 COMPILE_ASSERT(characterCount > 1, AtomicStringFromLiteralNotEmpty);
82 COMPILE_ASSERT((characterCount - 1 <= ((unsigned(~0) - sizeof(StringImpl)) / sizeof(LChar))), AtomicStringFromLiteralCannotOverflow);
83 }
84
85 // We have to declare the copy constructor and copy assignment operator as well, otherwise
86 // they'll be implicitly deleted by adding the move constructor and move assignment operator.
87 AtomicString(const AtomicString& other) : m_string(other.m_string) { }
88 AtomicString(AtomicString&& other) : m_string(WTFMove(other.m_string)) { }
89 AtomicString& operator=(const AtomicString& other) { m_string = other.m_string; return *this; }
90 AtomicString& operator=(AtomicString&& other) { m_string = WTFMove(other.m_string); return *this; }
91
92 // Hash table deleted values, which are only constructed and never copied or destroyed.
93 AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { }
94 bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); }
95
96 unsigned existingHash() const { return isNull() ? 0 : impl()->existingHash(); }
97
98 operator const String&() const { return m_string; }
99 const String& string() const { return m_string; };
100
101 AtomicStringImpl* impl() const { return static_cast<AtomicStringImpl *>(m_string.impl()); }
102
103 bool is8Bit() const { return m_string.is8Bit(); }
104 const LChar* characters8() const { return m_string.characters8(); }
105 const UChar* characters16() const { return m_string.characters16(); }
106 unsigned length() const { return m_string.length(); }
107
108 UChar operator[](unsigned int i) const { return m_string[i]; }
109
110 WTF_EXPORT_PRIVATE static AtomicString number(int);
111 WTF_EXPORT_PRIVATE static AtomicString number(unsigned);
112 WTF_EXPORT_PRIVATE static AtomicString number(unsigned long);
113 WTF_EXPORT_PRIVATE static AtomicString number(unsigned long long);
114 WTF_EXPORT_PRIVATE static AtomicString number(float);
115 WTF_EXPORT_PRIVATE static AtomicString number(double);
116 // If we need more overloads of the number function, we can add all the others that String has, but these seem to do for now.
117
118 bool contains(UChar character) const { return m_string.contains(character); }
119 bool contains(const LChar* string) const { return m_string.contains(string); }
120 bool contains(const String& string) const { return m_string.contains(string); }
121 bool containsIgnoringASCIICase(const String& string) const { return m_string.containsIgnoringASCIICase(string); }
122
123 size_t find(UChar character, unsigned start = 0) const { return m_string.find(character, start); }
124 size_t find(const LChar* string, unsigned start = 0) const { return m_string.find(string, start); }
125 size_t find(const String& string, unsigned start = 0) const { return m_string.find(string, start); }
126 size_t findIgnoringASCIICase(const String& string) const { return m_string.findIgnoringASCIICase(string); }
127 size_t findIgnoringASCIICase(const String& string, unsigned startOffset) const { return m_string.findIgnoringASCIICase(string, startOffset); }
128 size_t find(CodeUnitMatchFunction matchFunction, unsigned start = 0) const { return m_string.find(matchFunction, start); }
129
130 bool startsWith(const String& string) const { return m_string.startsWith(string); }
131 bool startsWithIgnoringASCIICase(const String& string) const { return m_string.startsWithIgnoringASCIICase(string); }
132 bool startsWith(UChar character) const { return m_string.startsWith(character); }
133 template<unsigned matchLength> bool startsWith(const char (&prefix)[matchLength]) const { return m_string.startsWith<matchLength>(prefix); }
134
135 bool endsWith(const String& string) const { return m_string.endsWith(string); }
136 bool endsWithIgnoringASCIICase(const String& string) const { return m_string.endsWithIgnoringASCIICase(string); }
137 bool endsWith(UChar character) const { return m_string.endsWith(character); }
138 template<unsigned matchLength> bool endsWith(const char (&prefix)[matchLength]) const { return m_string.endsWith<matchLength>(prefix); }
139
140 WTF_EXPORT_PRIVATE AtomicString convertToASCIILowercase() const;
141 WTF_EXPORT_PRIVATE AtomicString convertToASCIIUppercase() const;
142
143 int toInt(bool* ok = 0) const { return m_string.toInt(ok); }
144 double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); }
145 float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); }
146 bool percentage(int& p) const { return m_string.percentage(p); }
147
148 bool isNull() const { return m_string.isNull(); }
149 bool isEmpty() const { return m_string.isEmpty(); }
150
151#if USE(CF)
152 AtomicString(CFStringRef);
153#endif
154
155#ifdef __OBJC__
156 AtomicString(NSString*);
157 operator NSString*() const { return m_string; }
158#endif
159
160#if OS(WINDOWS) && U_ICU_VERSION_MAJOR_NUM >= 59
161 AtomicString(const wchar_t* characters, unsigned length)
162 : AtomicString(ucharFrom(characters), length) { }
163
164 AtomicString(const wchar_t* characters)
165 : AtomicString(ucharFrom(characters)) { }
166#endif
167
168 // AtomicString::fromUTF8 will return a null string if the input data contains invalid UTF-8 sequences.
169 static AtomicString fromUTF8(const char*, size_t);
170 static AtomicString fromUTF8(const char*);
171
172#ifndef NDEBUG
173 void show() const;
174#endif
175
176private:
177 // The explicit constructors with AtomicString::ConstructFromLiteral must be used for literals.
178 AtomicString(ASCIILiteral);
179
180 enum class CaseConvertType { Upper, Lower };
181 template<CaseConvertType> AtomicString convertASCIICase() const;
182
183 WTF_EXPORT_PRIVATE static AtomicString fromUTF8Internal(const char*, const char*);
184
185 String m_string;
186};
187
188static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must be same size!");
189
190inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
191bool operator==(const AtomicString&, const LChar*);
192inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
193inline bool operator==(const AtomicString& a, const Vector<UChar>& b) { return a.impl() && equal(a.impl(), b.data(), b.size()); }
194inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); }
195inline bool operator==(const LChar* a, const AtomicString& b) { return b == a; }
196inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); }
197inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; }
198
199inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); }
200inline bool operator!=(const AtomicString& a, const LChar* b) { return !(a == b); }
201inline bool operator!=(const AtomicString& a, const char* b) { return !(a == b); }
202inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); }
203inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); }
204inline bool operator!=(const LChar* a, const AtomicString& b) { return !(b == a); }
205inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); }
206inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); }
207
208bool equalIgnoringASCIICase(const AtomicString&, const AtomicString&);
209bool equalIgnoringASCIICase(const AtomicString&, const String&);
210bool equalIgnoringASCIICase(const String&, const AtomicString&);
211bool equalIgnoringASCIICase(const AtomicString&, const char*);
212
213template<unsigned length> bool equalLettersIgnoringASCIICase(const AtomicString&, const char (&lowercaseLetters)[length]);
214
215inline AtomicString::AtomicString()
216{
217}
218
219inline AtomicString::AtomicString(const LChar* string)
220 : m_string(AtomicStringImpl::add(string))
221{
222}
223
224inline AtomicString::AtomicString(const char* string)
225 : m_string(AtomicStringImpl::add(string))
226{
227}
228
229inline AtomicString::AtomicString(const LChar* string, unsigned length)
230 : m_string(AtomicStringImpl::add(string, length))
231{
232}
233
234inline AtomicString::AtomicString(const UChar* string, unsigned length)
235 : m_string(AtomicStringImpl::add(string, length))
236{
237}
238
239inline AtomicString::AtomicString(const UChar* string)
240 : m_string(AtomicStringImpl::add(string))
241{
242}
243
244inline AtomicString::AtomicString(AtomicStringImpl* string)
245 : m_string(string)
246{
247}
248
249inline AtomicString::AtomicString(RefPtr<AtomicStringImpl>&& string)
250 : m_string(WTFMove(string))
251{
252}
253
254inline AtomicString::AtomicString(StringImpl* string)
255 : m_string(AtomicStringImpl::add(string))
256{
257}
258
259inline AtomicString::AtomicString(const StaticStringImpl* string)
260 : m_string(AtomicStringImpl::add(string))
261{
262}
263
264inline AtomicString::AtomicString(const String& string)
265 : m_string(AtomicStringImpl::add(string.impl()))
266{
267}
268
269inline AtomicString::AtomicString(StringImpl* baseString, unsigned start, unsigned length)
270 : m_string(AtomicStringImpl::add(baseString, start, length))
271{
272}
273
274inline AtomicString::AtomicString(UniquedStringImpl* uid)
275 : m_string(uid)
276{
277}
278
279#if USE(CF)
280
281inline AtomicString::AtomicString(CFStringRef string)
282 : m_string(AtomicStringImpl::add(string))
283{
284}
285
286#endif
287
288#ifdef __OBJC__
289
290inline AtomicString::AtomicString(NSString* string)
291 : m_string(AtomicStringImpl::add((__bridge CFStringRef)string))
292{
293}
294
295#endif
296
297// Define external global variables for the commonly used atomic strings.
298// These are only usable from the main thread.
299extern WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> nullAtomData;
300extern WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> emptyAtomData;
301extern WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> starAtomData;
302extern WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> xmlAtomData;
303extern WTF_EXPORT_PRIVATE LazyNeverDestroyed<AtomicString> xmlnsAtomData;
304
305inline const AtomicString& nullAtom() { return nullAtomData.get(); }
306inline const AtomicString& emptyAtom() { return emptyAtomData.get(); }
307inline const AtomicString& starAtom() { return starAtomData.get(); }
308inline const AtomicString& xmlAtom() { return xmlAtomData.get(); }
309inline const AtomicString& xmlnsAtom() { return xmlnsAtomData.get(); }
310
311inline AtomicString AtomicString::fromUTF8(const char* characters, size_t length)
312{
313 if (!characters)
314 return nullAtom();
315 if (!length)
316 return emptyAtom();
317 return fromUTF8Internal(characters, characters + length);
318}
319
320inline AtomicString AtomicString::fromUTF8(const char* characters)
321{
322 if (!characters)
323 return nullAtom();
324 if (!*characters)
325 return emptyAtom();
326 return fromUTF8Internal(characters, nullptr);
327}
328
329// AtomicStringHash is the default hash for AtomicString
330template<typename T> struct DefaultHash;
331template<> struct DefaultHash<AtomicString> {
332 typedef AtomicStringHash Hash;
333};
334
335template<unsigned length> inline bool equalLettersIgnoringASCIICase(const AtomicString& string, const char (&lowercaseLetters)[length])
336{
337 return equalLettersIgnoringASCIICase(string.string(), lowercaseLetters);
338}
339
340inline bool equalIgnoringASCIICase(const AtomicString& a, const AtomicString& b)
341{
342 return equalIgnoringASCIICase(a.string(), b.string());
343}
344
345inline bool equalIgnoringASCIICase(const AtomicString& a, const String& b)
346{
347 return equalIgnoringASCIICase(a.string(), b);
348}
349
350inline bool equalIgnoringASCIICase(const String& a, const AtomicString& b)
351{
352 return equalIgnoringASCIICase(a, b.string());
353}
354
355inline bool equalIgnoringASCIICase(const AtomicString& a, const char* b)
356{
357 return equalIgnoringASCIICase(a.string(), b);
358}
359
360template<> struct IntegerToStringConversionTrait<AtomicString> {
361 using ReturnType = AtomicString;
362 using AdditionalArgumentType = void;
363 static AtomicString flush(LChar* characters, unsigned length, void*) { return { characters, length }; }
364};
365
366} // namespace WTF
367
368#ifndef ATOMICSTRING_HIDE_GLOBALS
369using WTF::AtomicString;
370using WTF::nullAtom;
371using WTF::emptyAtom;
372using WTF::starAtom;
373using WTF::xmlAtom;
374using WTF::xmlnsAtom;
375#endif
376
377#include <wtf/text/StringConcatenate.h>
378