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