1 /* 2 * Copyright (C) 1999-2000 Harri Porten (porten (at) kde.org) 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 4 * Copyright (C) 2009 Google Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef UString_h 24 #define UString_h 25 26 #include <wtf/text/StringImpl.h> 27 28 namespace JSC { 29 30 class UString { 31 public: 32 // Construct a null string, distinguishable from an empty string. 33 UString() { } 34 35 // Construct a string with UTF-16 data. 36 UString(const UChar* characters, unsigned length); 37 38 // Construct a string with UTF-16 data, from a null-terminated source. 39 UString(const UChar*); 40 41 // Construct a string with latin1 data. 42 UString(const char* characters, unsigned length); 43 44 // Construct a string with latin1 data, from a null-terminated source. 45 UString(const char* characters); 46 47 // Construct a string referencing an existing StringImpl. 48 UString(StringImpl* impl) : m_impl(impl) { } 49 UString(PassRefPtr<StringImpl> impl) : m_impl(impl) { } 50 UString(RefPtr<StringImpl> impl) : m_impl(impl) { } 51 52 // Inline the destructor. 53 ALWAYS_INLINE ~UString() { } 54 55 void swap(UString& o) { m_impl.swap(o.m_impl); } 56 57 template<size_t inlineCapacity> 58 static UString adopt(Vector<UChar, inlineCapacity>& vector) { return StringImpl::adopt(vector); } 59 60 bool isNull() const { return !m_impl; } 61 bool isEmpty() const { return !m_impl || !m_impl->length(); } 62 63 StringImpl* impl() const { return m_impl.get(); } 64 65 unsigned length() const 66 { 67 if (!m_impl) 68 return 0; 69 return m_impl->length(); 70 } 71 72 const UChar* characters() const 73 { 74 if (!m_impl) 75 return 0; 76 return m_impl->characters(); 77 } 78 79 CString ascii() const; 80 CString latin1() const; 81 CString utf8(bool strict = false) const; 82 83 UChar operator[](unsigned index) const 84 { 85 if (!m_impl || index >= m_impl->length()) 86 return 0; 87 return m_impl->characters()[index]; 88 } 89 90 static UString number(int); 91 static UString number(unsigned); 92 static UString number(long); 93 static UString number(long long); 94 static UString number(double); 95 96 // Find a single character or string, also with match function & latin1 forms. 97 size_t find(UChar c, unsigned start = 0) const 98 { return m_impl ? m_impl->find(c, start) : notFound; } 99 size_t find(const UString& str, unsigned start = 0) const 100 { return m_impl ? m_impl->find(str.impl(), start) : notFound; } 101 size_t find(const char* str, unsigned start = 0) const 102 { return m_impl ? m_impl->find(str, start) : notFound; } 103 104 // Find the last instance of a single character or string. 105 size_t reverseFind(UChar c, unsigned start = UINT_MAX) const 106 { return m_impl ? m_impl->reverseFind(c, start) : notFound; } 107 size_t reverseFind(const UString& str, unsigned start = UINT_MAX) const 108 { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; } 109 110 UString substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const; 111 112 private: 113 RefPtr<StringImpl> m_impl; 114 }; 115 116 ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2) 117 { 118 StringImpl* rep1 = s1.impl(); 119 StringImpl* rep2 = s2.impl(); 120 unsigned size1 = 0; 121 unsigned size2 = 0; 122 123 if (rep1 == rep2) // If they're the same rep, they're equal. 124 return true; 125 126 if (rep1) 127 size1 = rep1->length(); 128 129 if (rep2) 130 size2 = rep2->length(); 131 132 if (size1 != size2) // If the lengths are not the same, we're done. 133 return false; 134 135 if (!size1) 136 return true; 137 138 // At this point we know 139 // (a) that the strings are the same length and 140 // (b) that they are greater than zero length. 141 const UChar* d1 = rep1->characters(); 142 const UChar* d2 = rep2->characters(); 143 144 if (d1 == d2) // Check to see if the data pointers are the same. 145 return true; 146 147 // Do quick checks for sizes 1 and 2. 148 switch (size1) { 149 case 1: 150 return d1[0] == d2[0]; 151 case 2: 152 return (d1[0] == d2[0]) & (d1[1] == d2[1]); 153 default: 154 return memcmp(d1, d2, size1 * sizeof(UChar)) == 0; 155 } 156 } 157 158 159 inline bool operator!=(const UString& s1, const UString& s2) 160 { 161 return !JSC::operator==(s1, s2); 162 } 163 164 bool operator<(const UString& s1, const UString& s2); 165 bool operator>(const UString& s1, const UString& s2); 166 167 bool operator==(const UString& s1, const char* s2); 168 169 inline bool operator!=(const UString& s1, const char* s2) 170 { 171 return !JSC::operator==(s1, s2); 172 } 173 174 inline bool operator==(const char *s1, const UString& s2) 175 { 176 return operator==(s2, s1); 177 } 178 179 inline bool operator!=(const char *s1, const UString& s2) 180 { 181 return !JSC::operator==(s1, s2); 182 } 183 184 inline int codePointCompare(const UString& s1, const UString& s2) 185 { 186 return codePointCompare(s1.impl(), s2.impl()); 187 } 188 189 struct UStringHash { 190 static unsigned hash(StringImpl* key) { return key->hash(); } 191 static bool equal(const StringImpl* a, const StringImpl* b) 192 { 193 if (a == b) 194 return true; 195 if (!a || !b) 196 return false; 197 198 unsigned aLength = a->length(); 199 unsigned bLength = b->length(); 200 if (aLength != bLength) 201 return false; 202 203 // FIXME: perhaps we should have a more abstract macro that indicates when 204 // going 4 bytes at a time is unsafe 205 #if CPU(ARM) || CPU(SH4) || CPU(MIPS) 206 const UChar* aChars = a->characters(); 207 const UChar* bChars = b->characters(); 208 for (unsigned i = 0; i != aLength; ++i) { 209 if (*aChars++ != *bChars++) 210 return false; 211 } 212 return true; 213 #else 214 /* Do it 4-bytes-at-a-time on architectures where it's safe */ 215 const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters()); 216 const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters()); 217 218 unsigned halfLength = aLength >> 1; 219 for (unsigned i = 0; i != halfLength; ++i) 220 if (*aChars++ != *bChars++) 221 return false; 222 223 if (aLength & 1 && *reinterpret_cast<const uint16_t*>(aChars) != *reinterpret_cast<const uint16_t*>(bChars)) 224 return false; 225 226 return true; 227 #endif 228 } 229 230 static unsigned hash(const RefPtr<StringImpl>& key) { return key->hash(); } 231 static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b) 232 { 233 return equal(a.get(), b.get()); 234 } 235 236 static unsigned hash(const UString& key) { return key.impl()->hash(); } 237 static bool equal(const UString& a, const UString& b) 238 { 239 return equal(a.impl(), b.impl()); 240 } 241 242 static const bool safeToCompareToEmptyOrDeleted = false; 243 }; 244 245 } // namespace JSC 246 247 namespace WTF { 248 249 // UStringHash is the default hash for UString 250 template<typename T> struct DefaultHash; 251 template<> struct DefaultHash<JSC::UString> { 252 typedef JSC::UStringHash Hash; 253 }; 254 255 template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits { }; 256 257 } // namespace WTF 258 259 #endif 260 261