1/* 2 * Copyright (C) 2004, 2005, 2006, 2008, 2014 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 38class AtomicStringTable; 39struct AtomicStringHash; 40 41class AtomicString { 42public: 43 WTF_EXPORT_PRIVATE static void init(); 44 45 AtomicString() { } 46 AtomicString(const LChar* s) : m_string(add(s)) { } 47 AtomicString(const char* s) : m_string(add(s)) { } 48 AtomicString(const LChar* s, unsigned length) : m_string(add(s, length)) { } 49 AtomicString(const UChar* s, unsigned length) : m_string(add(s, length)) { } 50 AtomicString(const UChar* s, unsigned length, unsigned existingHash) : m_string(add(s, length, existingHash)) { } 51 AtomicString(const UChar* s) : m_string(add(s)) { } 52 53 template<size_t inlineCapacity> 54 explicit AtomicString(const Vector<UChar, inlineCapacity>& characters) 55 : m_string(add(characters.data(), characters.size())) 56 { 57 } 58 59 ATOMICSTRING_CONVERSION AtomicString(StringImpl* imp) : m_string(add(imp)) { } 60 AtomicString(AtomicStringImpl* imp) : m_string(imp) { } 61 ATOMICSTRING_CONVERSION AtomicString(const String& s) : m_string(add(s.impl())) { } 62 AtomicString(StringImpl* baseString, unsigned start, unsigned length) : m_string(add(baseString, start, length)) { } 63 64 enum ConstructFromLiteralTag { ConstructFromLiteral }; 65 AtomicString(const char* characters, unsigned length, ConstructFromLiteralTag) 66 : m_string(addFromLiteralData(characters, length)) 67 { 68 } 69 70 template<unsigned charactersCount> 71 ALWAYS_INLINE AtomicString(const char (&characters)[charactersCount], ConstructFromLiteralTag) 72 : m_string(addFromLiteralData(characters, charactersCount - 1)) 73 { 74 COMPILE_ASSERT(charactersCount > 1, AtomicStringFromLiteralNotEmpty); 75 COMPILE_ASSERT((charactersCount - 1 <= ((unsigned(~0) - sizeof(StringImpl)) / sizeof(LChar))), AtomicStringFromLiteralCannotOverflow); 76 } 77 78 // We have to declare the copy constructor and copy assignment operator as well, otherwise 79 // they'll be implicitly deleted by adding the move constructor and move assignment operator. 80 AtomicString(const AtomicString& other) : m_string(other.m_string) { } 81 AtomicString(AtomicString&& other) : m_string(WTF::move(other.m_string)) { } 82 AtomicString& operator=(const AtomicString& other) { m_string = other.m_string; return *this; } 83 AtomicString& operator=(AtomicString&& other) { m_string = WTF::move(other.m_string); return *this; } 84 85 // Hash table deleted values, which are only constructed and never copied or destroyed. 86 AtomicString(WTF::HashTableDeletedValueType) : m_string(WTF::HashTableDeletedValue) { } 87 bool isHashTableDeletedValue() const { return m_string.isHashTableDeletedValue(); } 88 89 WTF_EXPORT_STRING_API static AtomicStringImpl* findStringWithHash(const StringImpl&); 90 WTF_EXPORT_STRING_API static AtomicStringImpl* find(LChar*, unsigned length); 91 WTF_EXPORT_STRING_API static AtomicStringImpl* find(UChar*, unsigned length); 92 static AtomicStringImpl* find(StringImpl* string) 93 { 94 if (!string || string->isAtomic()) 95 return static_cast<AtomicStringImpl*>(string); 96 return findSlowCase(*string); 97 } 98 99 operator const String&() const { return m_string; } 100 const String& string() const { return m_string; }; 101 102 AtomicStringImpl* impl() const { return static_cast<AtomicStringImpl *>(m_string.impl()); } 103 104 bool is8Bit() const { return m_string.is8Bit(); } 105 const LChar* characters8() const { return m_string.characters8(); } 106 const UChar* characters16() const { return m_string.characters16(); } 107 unsigned length() const { return m_string.length(); } 108 109 UChar operator[](unsigned int i) const { return m_string[i]; } 110 111 WTF_EXPORT_STRING_API static AtomicString number(int); 112 WTF_EXPORT_STRING_API static AtomicString number(unsigned); 113 WTF_EXPORT_STRING_API static AtomicString number(double); 114 // 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. 115 116 bool contains(UChar c) const { return m_string.contains(c); } 117 bool contains(const LChar* s, bool caseSensitive = true) const 118 { return m_string.contains(s, caseSensitive); } 119 bool contains(const String& s, bool caseSensitive = true) const 120 { return m_string.contains(s, caseSensitive); } 121 122 size_t find(UChar c, unsigned start = 0) const { return m_string.find(c, start); } 123 size_t find(const LChar* s, unsigned start = 0, bool caseSentitive = true) const 124 { return m_string.find(s, start, caseSentitive); } 125 size_t find(const String& s, unsigned start = 0, bool caseSentitive = true) const 126 { return m_string.find(s, start, caseSentitive); } 127 128 bool startsWith(const String& s, bool caseSensitive = true) const 129 { return m_string.startsWith(s, caseSensitive); } 130 bool startsWith(UChar character) const 131 { return m_string.startsWith(character); } 132 template<unsigned matchLength> 133 bool startsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const 134 { return m_string.startsWith<matchLength>(prefix, caseSensitive); } 135 136 bool endsWith(const String& s, bool caseSensitive = true) const 137 { return m_string.endsWith(s, caseSensitive); } 138 bool endsWith(UChar character) const 139 { return m_string.endsWith(character); } 140 template<unsigned matchLength> 141 bool endsWith(const char (&prefix)[matchLength], bool caseSensitive = true) const 142 { return m_string.endsWith<matchLength>(prefix, caseSensitive); } 143 144 WTF_EXPORT_STRING_API AtomicString convertToASCIILowercase() const; 145 WTF_EXPORT_STRING_API AtomicString lower() const; 146 AtomicString upper() const { return AtomicString(impl()->upper()); } 147 148 int toInt(bool* ok = 0) const { return m_string.toInt(ok); } 149 double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); } 150 float toFloat(bool* ok = 0) const { return m_string.toFloat(ok); } 151 bool percentage(int& p) const { return m_string.percentage(p); } 152 153 bool isNull() const { return m_string.isNull(); } 154 bool isEmpty() const { return m_string.isEmpty(); } 155 156 static void remove(StringImpl*); 157 158#if USE(CF) 159 AtomicString(CFStringRef s) : m_string(add(s)) { } 160#endif 161#ifdef __OBJC__ 162 AtomicString(NSString* s) : m_string(add((CFStringRef)s)) { } 163 operator NSString*() const { return m_string; } 164#endif 165 166 // AtomicString::fromUTF8 will return a null string if 167 // the input data contains invalid UTF-8 sequences. 168 static AtomicString fromUTF8(const char*, size_t); 169 static AtomicString fromUTF8(const char*); 170 171#ifndef NDEBUG 172 void show() const; 173#endif 174 175 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(const LChar*); 176 ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s) { return add(reinterpret_cast<const LChar*>(s)); }; 177 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(const LChar*, unsigned length); 178 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(const UChar*, unsigned length); 179 ALWAYS_INLINE static PassRefPtr<StringImpl> add(const char* s, unsigned length) { return add(reinterpret_cast<const LChar*>(s), length); }; 180 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(const UChar*, unsigned length, unsigned existingHash); 181 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(const UChar*); 182 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(StringImpl*, unsigned offset, unsigned length); 183 ALWAYS_INLINE static PassRefPtr<StringImpl> add(StringImpl* string) 184 { 185 if (!string || string->isAtomic()) { 186 ASSERT_WITH_MESSAGE(!string || !string->length() || isInAtomicStringTable(string), "The atomic string comes from an other thread!"); 187 return string; 188 } 189 return addSlowCase(*string); 190 } 191 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> addFromLiteralData(const char* characters, unsigned length); 192#if USE(CF) 193 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> add(CFStringRef); 194#endif 195 196 template<typename StringTableProvider> 197 ALWAYS_INLINE static PassRefPtr<StringImpl> addWithStringTableProvider(StringTableProvider& stringTableProvider, StringImpl* string) 198 { 199 if (!string || string->isAtomic()) { 200 ASSERT_WITH_MESSAGE(!string || !string->length() || isInAtomicStringTable(string), "The atomic string comes from an other thread!"); 201 return string; 202 } 203 return addSlowCase(*stringTableProvider.atomicStringTable(), *string); 204 } 205 206private: 207 // The explicit constructors with AtomicString::ConstructFromLiteral must be used for literals. 208 AtomicString(ASCIILiteral); 209 210 String m_string; 211 212 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> addSlowCase(StringImpl&); 213 WTF_EXPORT_STRING_API static PassRefPtr<StringImpl> addSlowCase(AtomicStringTable&, StringImpl&); 214 215 WTF_EXPORT_STRING_API static AtomicStringImpl* findSlowCase(StringImpl&); 216 WTF_EXPORT_STRING_API static AtomicString fromUTF8Internal(const char*, const char*); 217 218#if !ASSERT_DISABLED 219 WTF_EXPORT_STRING_API static bool isInAtomicStringTable(StringImpl*); 220#endif 221}; 222 223inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); } 224bool operator==(const AtomicString&, const LChar*); 225inline bool operator==(const AtomicString& a, const char* b) { return WTF::equal(a.impl(), reinterpret_cast<const LChar*>(b)); } 226inline bool operator==(const AtomicString& a, const Vector<UChar>& b) { return a.impl() && equal(a.impl(), b.data(), b.size()); } 227inline bool operator==(const AtomicString& a, const String& b) { return equal(a.impl(), b.impl()); } 228inline bool operator==(const LChar* a, const AtomicString& b) { return b == a; } 229inline bool operator==(const String& a, const AtomicString& b) { return equal(a.impl(), b.impl()); } 230inline bool operator==(const Vector<UChar>& a, const AtomicString& b) { return b == a; } 231 232inline bool operator!=(const AtomicString& a, const AtomicString& b) { return a.impl() != b.impl(); } 233inline bool operator!=(const AtomicString& a, const LChar* b) { return !(a == b); } 234inline bool operator!=(const AtomicString& a, const char* b) { return !(a == b); } 235inline bool operator!=(const AtomicString& a, const String& b) { return !equal(a.impl(), b.impl()); } 236inline bool operator!=(const AtomicString& a, const Vector<UChar>& b) { return !(a == b); } 237inline bool operator!=(const LChar* a, const AtomicString& b) { return !(b == a); } 238inline bool operator!=(const String& a, const AtomicString& b) { return !equal(a.impl(), b.impl()); } 239inline bool operator!=(const Vector<UChar>& a, const AtomicString& b) { return !(a == b); } 240 241inline bool equalIgnoringCase(const AtomicString& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } 242inline bool equalIgnoringCase(const AtomicString& a, const LChar* b) { return equalIgnoringCase(a.impl(), b); } 243inline bool equalIgnoringCase(const AtomicString& a, const char* b) { return equalIgnoringCase(a.impl(), reinterpret_cast<const LChar*>(b)); } 244inline bool equalIgnoringCase(const AtomicString& a, const String& b) { return equalIgnoringCase(a.impl(), b.impl()); } 245inline bool equalIgnoringCase(const LChar* a, const AtomicString& b) { return equalIgnoringCase(a, b.impl()); } 246inline bool equalIgnoringCase(const char* a, const AtomicString& b) { return equalIgnoringCase(reinterpret_cast<const LChar*>(a), b.impl()); } 247inline bool equalIgnoringCase(const String& a, const AtomicString& b) { return equalIgnoringCase(a.impl(), b.impl()); } 248 249// Define external global variables for the commonly used atomic strings. 250// These are only usable from the main thread. 251#ifndef ATOMICSTRING_HIDE_GLOBALS 252extern const WTF_EXPORTDATA AtomicString nullAtom; 253extern const WTF_EXPORTDATA AtomicString emptyAtom; 254extern const WTF_EXPORTDATA AtomicString textAtom; 255extern const WTF_EXPORTDATA AtomicString commentAtom; 256extern const WTF_EXPORTDATA AtomicString starAtom; 257extern const WTF_EXPORTDATA AtomicString xmlAtom; 258extern const WTF_EXPORTDATA AtomicString xmlnsAtom; 259extern const WTF_EXPORTDATA AtomicString xlinkAtom; 260 261inline AtomicString AtomicString::fromUTF8(const char* characters, size_t length) 262{ 263 if (!characters) 264 return nullAtom; 265 if (!length) 266 return emptyAtom; 267 return fromUTF8Internal(characters, characters + length); 268} 269 270inline AtomicString AtomicString::fromUTF8(const char* characters) 271{ 272 if (!characters) 273 return nullAtom; 274 if (!*characters) 275 return emptyAtom; 276 return fromUTF8Internal(characters, 0); 277} 278#endif 279 280// AtomicStringHash is the default hash for AtomicString 281template<typename T> struct DefaultHash; 282template<> struct DefaultHash<AtomicString> { 283 typedef AtomicStringHash Hash; 284}; 285 286} // namespace WTF 287 288#ifndef ATOMICSTRING_HIDE_GLOBALS 289using WTF::AtomicString; 290using WTF::nullAtom; 291using WTF::emptyAtom; 292using WTF::textAtom; 293using WTF::commentAtom; 294using WTF::starAtom; 295using WTF::xmlAtom; 296using WTF::xmlnsAtom; 297using WTF::xlinkAtom; 298#endif 299 300#include <wtf/text/StringConcatenate.h> 301#endif // AtomicString_h 302