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