• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 AtomicString_h
22 #define AtomicString_h
23 
24 #include "wtf/HashTableDeletedValueType.h"
25 #include "wtf/WTFExport.h"
26 #include "wtf/text/CString.h"
27 #include "wtf/text/WTFString.h"
28 
29 namespace WTF {
30 
31 struct AtomicStringHash;
32 
33 class WTF_EXPORT AtomicString {
34 public:
35     static void init();
36 
AtomicString()37     AtomicString() { }
AtomicString(const LChar * s)38     AtomicString(const LChar* s) : m_string(add(s)) { }
AtomicString(const char * s)39     AtomicString(const char* s) : m_string(add(s)) { }
AtomicString(const LChar * s,unsigned length)40     AtomicString(const LChar* s, unsigned length) : m_string(add(s, length)) { }
AtomicString(const UChar * s,unsigned length)41     AtomicString(const UChar* s, unsigned length) : m_string(add(s, length)) { }
AtomicString(const UChar * s,unsigned length,unsigned existingHash)42     AtomicString(const UChar* s, unsigned length, unsigned existingHash) : m_string(add(s, length, existingHash)) { }
AtomicString(const UChar * s)43     AtomicString(const UChar* s) : m_string(add(s)) { }
44 
45     template<size_t inlineCapacity>
AtomicString(const Vector<UChar,inlineCapacity> & characters)46     explicit AtomicString(const Vector<UChar, inlineCapacity>& characters)
47         : m_string(add(characters.data(), characters.size()))
48     {
49     }
50 
51     // Constructing an AtomicString from a String / StringImpl can be expensive if
52     // the StringImpl is not already atomic.
AtomicString(StringImpl * impl)53     explicit AtomicString(StringImpl* impl) : m_string(add(impl)) { }
AtomicString(const String & s)54     explicit AtomicString(const String& s) : m_string(add(s.impl())) { }
55 
AtomicString(StringImpl * baseString,unsigned start,unsigned length)56     AtomicString(StringImpl* baseString, unsigned start, unsigned length) : m_string(add(baseString, start, length)) { }
57 
58     enum ConstructFromLiteralTag { ConstructFromLiteral };
AtomicString(const char * characters,unsigned length,ConstructFromLiteralTag)59     AtomicString(const char* characters, unsigned length, ConstructFromLiteralTag)
60         : m_string(addFromLiteralData(characters, length))
61     {
62     }
63 
64     template<unsigned charactersCount>
AtomicString(const char (& characters)[charactersCount],ConstructFromLiteralTag)65     ALWAYS_INLINE AtomicString(const char (&characters)[charactersCount], ConstructFromLiteralTag)
66         : m_string(addFromLiteralData(characters, charactersCount - 1))
67     {
68         COMPILE_ASSERT(charactersCount > 1, AtomicStringFromLiteralNotEmpty);
69         COMPILE_ASSERT((charactersCount - 1 <= ((unsigned(~0) - sizeof(StringImpl)) / sizeof(LChar))), AtomicStringFromLiteralCannotOverflow);
70     }
71 
72 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
73     // We have to declare the copy constructor and copy assignment operator as well, otherwise
74     // they'll be implicitly deleted by adding the move constructor and move assignment operator.
75     // FIXME: Instead of explicitly casting to String&& here, we should use std::move, but that requires us to
76     // have a standard library that supports move semantics.
AtomicString(const AtomicString & other)77     AtomicString(const AtomicString& other) : m_string(other.m_string) { }
AtomicString(AtomicString && other)78     AtomicString(AtomicString&& other) : m_string(static_cast<String&&>(other.m_string)) { }
79     AtomicString& operator=(const AtomicString& other) { m_string = other.m_string; return *this; }
80     AtomicString& operator=(AtomicString&& other) { m_string = static_cast<String&&>(other.m_string); return *this; }
81 #endif
82 
83     // Hash table deleted values, which are only constructed and never copied or destroyed.
AtomicString(WTF::HashTableDeletedValueType)84     AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { }
isHashTableDeletedValue()85     bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); }
86 
87     static StringImpl* find(const StringImpl*);
88 
89     operator const String&() const { return m_string; }
string()90     const String& string() const { return m_string; };
91 
impl()92     StringImpl* impl() const { return m_string.impl(); }
93 
is8Bit()94     bool is8Bit() const { return m_string.is8Bit(); }
characters8()95     const LChar* characters8() const { return m_string.characters8(); }
characters16()96     const UChar* characters16() const { return m_string.characters16(); }
length()97     unsigned length() const { return m_string.length(); }
98 
99     UChar operator[](unsigned i) const { return m_string[i]; }
100 
contains(UChar c)101     bool contains(UChar c) const { return m_string.contains(c); }
102     bool contains(const LChar* s, bool caseSensitive = true) const
103         { return m_string.contains(s, caseSensitive); }
104     bool contains(const String& s, bool caseSensitive = true) const
105         { return m_string.contains(s, caseSensitive); }
106 
107     size_t find(UChar c, size_t start = 0) const { return m_string.find(c, start); }
108     size_t find(const LChar* s, size_t start = 0, bool caseSentitive = true) const
109         { return m_string.find(s, start, caseSentitive); }
110     size_t find(const String& s, size_t start = 0, bool caseSentitive = true) const
111         { return m_string.find(s, start, caseSentitive); }
112 
113     bool startsWith(const String& s, bool caseSensitive = true) const
114         { return m_string.startsWith(s, caseSensitive); }
startsWith(UChar character)115     bool startsWith(UChar character) const
116         { return m_string.startsWith(character); }
117     template<unsigned matchLength>
118     bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
119         { return m_string.startsWith<matchLength>(prefix, caseSensitive); }
120 
121     bool endsWith(const String& s, bool caseSensitive = true) const
122         { return m_string.endsWith(s, caseSensitive); }
endsWith(UChar character)123     bool endsWith(UChar character) const
124         { return m_string.endsWith(character); }
125     template<unsigned matchLength>
126     bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const
127         { return m_string.endsWith<matchLength>(prefix, caseSensitive); }
128 
129     AtomicString lower() const;
upper()130     AtomicString upper() const { return AtomicString(impl()->upper()); }
131 
132     int toInt(bool* ok = 0) const { return m_string.toInt(ok); }
133     double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); }
134     float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); }
percentage(int & p)135     bool percentage(int& p) const { return m_string.percentage(p); }
136 
137     static AtomicString number(int);
138     static AtomicString number(unsigned);
139     static AtomicString number(long);
140     static AtomicString number(unsigned long);
141     static AtomicString number(long long);
142     static AtomicString number(unsigned long long);
143 
144     static AtomicString number(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
145 
isNull()146     bool isNull() const { return m_string.isNull(); }
isEmpty()147     bool isEmpty() const { return m_string.isEmpty(); }
148 
149     static void remove(StringImpl*);
150 
151 #if USE(CF)
AtomicString(CFStringRef s)152     AtomicString(CFStringRef s) :  m_string(add(s)) { }
153 #endif
154 #ifdef __OBJC__
AtomicString(NSString * s)155     AtomicString(NSString* s) : m_string(add((CFStringRef)s)) { }
156     operator NSString*() const { return m_string; }
157 #endif
158     // AtomicString::fromUTF8 will return a null string if
159     // the input data contains invalid UTF-8 sequences.
160     static AtomicString fromUTF8(const char*, size_t);
161     static AtomicString fromUTF8(const char*);
162 
ascii()163     CString ascii() const { return m_string.ascii(); }
latin1()164     CString latin1() const { return m_string.latin1(); }
165     CString utf8(UTF8ConversionMode mode = LenientUTF8Conversion) const { return m_string.utf8(mode); }
166 
167 #ifndef NDEBUG
168     void show() const;
169 #endif
170 
171 private:
172     String m_string;
173 
174     static PassRefPtr<StringImpl> add(const LChar*);
add(const char * s)175     ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s) { return add(reinterpret_cast<const LChar*>(s)); };
176     static PassRefPtr<StringImpl> add(const LChar*, unsigned length);
177     static PassRefPtr<StringImpl> add(const UChar*, unsigned length);
add(const char * s,unsigned length)178     ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const LChar*>(s), length); };
179     static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash);
180     static PassRefPtr<StringImpl> add(const UChar*);
181     static PassRefPtr<StringImpl> add(StringImpl*, unsigned offset, unsigned length);
add(StringImpl * r)182     ALWAYS_INLINE static PassRefPtr<StringImpl> add(StringImpl* r)
183     {
184         if (!r || r->isAtomic())
185             return r;
186         return addSlowCase(r);
187     }
188     static PassRefPtr<StringImpl> addFromLiteralData(const char* characters, unsigned length);
189     static PassRefPtr<StringImpl> addSlowCase(StringImpl*);
190 #if USE(CF)
191     static PassRefPtr<StringImpl> add(CFStringRef);
192 #endif
193 
194     static AtomicString fromUTF8Internal(const char*, const char*);
195 };
196 
197 inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
198 WTF_EXPORT bool operator==(const AtomicString&, const LChar*);
199 inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), reinterpret_cast<const LChar*>(b)); }
200 inline bool operator==(const AtomicString& a, const Vector<UChar>& b) { return a.impl() && equal(a.impl(), b.data(), b.size()); }
201 inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); }
202 inline bool operator==(const LChar* a, const AtomicString& b) { return b == a; }
203 inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); }
204 inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; }
205 
206 inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); }
207 inline bool operator!=(const AtomicString& a, const LChar* b) { return !(a == b); }
208 inline bool operator!=(const AtomicString& a, const char* b) { return !(a == b); }
209 inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); }
210 inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); }
211 inline bool operator!=(const LChar* a, const AtomicString& b) { return !(b == a); }
212 inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); }
213 inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); }
214 
equalIgnoringCase(const AtomicString & a,const AtomicString & b)215 inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); }
equalIgnoringCase(const AtomicString & a,const LChar * b)216 inline bool equalIgnoringCase(const AtomicString& a, const LChar* b) { return equalIgnoringCase(a.impl(), b); }
equalIgnoringCase(const AtomicString & a,const char * b)217 inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); }
equalIgnoringCase(const AtomicString & a,const String & b)218 inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); }
equalIgnoringCase(const LChar * a,const AtomicString & b)219 inline bool equalIgnoringCase(const LChar* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); }
equalIgnoringCase(const char * a,const AtomicString & b)220 inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(a), b.impl()); }
equalIgnoringCase(const String & a,const AtomicString & b)221 inline bool equalIgnoringCase(const String& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); }
222 
223 // Define external global variables for the commonly used atomic strings.
224 // These are only usable from the main thread.
225 #ifndef ATOMICSTRING_HIDE_GLOBALS
226 WTF_EXPORT extern const AtomicString nullAtom;
227 WTF_EXPORT extern const AtomicString emptyAtom;
228 WTF_EXPORT extern const AtomicString starAtom;
229 WTF_EXPORT extern const AtomicString xmlAtom;
230 WTF_EXPORT extern const AtomicString xmlnsAtom;
231 WTF_EXPORT extern const AtomicString xlinkAtom;
232 
fromUTF8(const char * characters,size_t length)233 inline AtomicString AtomicString::fromUTF8(const char* characters, size_t length)
234 {
235     if (!characters)
236         return nullAtom;
237     if (!length)
238         return emptyAtom;
239     return fromUTF8Internal(characters, characters + length);
240 }
241 
fromUTF8(const char * characters)242 inline AtomicString AtomicString::fromUTF8(const char* characters)
243 {
244     if (!characters)
245         return nullAtom;
246     if (!*characters)
247         return emptyAtom;
248     return fromUTF8Internal(characters, 0);
249 }
250 #endif
251 
252 // AtomicStringHash is the default hash for AtomicString
253 template<typename T> struct DefaultHash;
254 template<> struct DefaultHash<AtomicString> {
255     typedef AtomicStringHash Hash;
256 };
257 
258 } // namespace WTF
259 
260 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(AtomicString);
261 
262 #ifndef ATOMICSTRING_HIDE_GLOBALS
263 using WTF::AtomicString;
264 using WTF::nullAtom;
265 using WTF::emptyAtom;
266 using WTF::starAtom;
267 using WTF::xmlAtom;
268 using WTF::xmlnsAtom;
269 using WTF::xlinkAtom;
270 #endif
271 
272 #include "wtf/text/StringConcatenate.h"
273 #endif // AtomicString_h
274