1 /* 2 * Copyright (C) 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #ifndef StringBuilder_h 28 #define StringBuilder_h 29 30 #include "wtf/WTFExport.h" 31 #include "wtf/text/AtomicString.h" 32 #include "wtf/text/WTFString.h" 33 34 namespace WTF { 35 36 class WTF_EXPORT StringBuilder { 37 // Disallow copying since it's expensive and we don't want code to do it by accident. 38 WTF_MAKE_NONCOPYABLE(StringBuilder); 39 40 public: 41 StringBuilder() 42 : m_bufferCharacters8(0) 43 , m_length(0) 44 , m_is8Bit(true) 45 { 46 } 47 48 void append(const UChar*, unsigned); 49 void append(const LChar*, unsigned); 50 51 ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast<const LChar*>(characters), length); } 52 53 void append(const String& string) 54 { 55 if (!string.length()) 56 return; 57 58 // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called) 59 // then just retain the string. 60 if (!m_length && !m_buffer) { 61 m_string = string; 62 m_length = string.length(); 63 m_is8Bit = m_string.is8Bit(); 64 return; 65 } 66 67 if (string.is8Bit()) 68 append(string.characters8(), string.length()); 69 else 70 append(string.characters16(), string.length()); 71 } 72 73 void append(const StringBuilder& other) 74 { 75 if (!other.m_length) 76 return; 77 78 // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called) 79 // then just retain the string. 80 if (!m_length && !m_buffer && !other.m_string.isNull()) { 81 m_string = other.m_string; 82 m_length = other.m_length; 83 return; 84 } 85 86 if (other.is8Bit()) 87 append(other.characters8(), other.m_length); 88 else 89 append(other.characters16(), other.m_length); 90 } 91 92 void append(const String& string, unsigned offset, unsigned length) 93 { 94 if (!string.length()) 95 return; 96 97 unsigned extent = offset + length; 98 if (extent < offset || extent > string.length()) 99 return; 100 101 if (string.is8Bit()) 102 append(string.characters8() + offset, length); 103 else 104 append(string.characters16() + offset, length); 105 } 106 107 void append(const StringView& string) 108 { 109 if (!string.length()) 110 return; 111 112 if (string.is8Bit()) 113 append(string.characters8(), string.length()); 114 else 115 append(string.characters16(), string.length()); 116 } 117 118 void append(const char* characters) 119 { 120 if (characters) 121 append(characters, strlen(characters)); 122 } 123 124 void append(UChar c) 125 { 126 if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { 127 if (!m_is8Bit) { 128 m_bufferCharacters16[m_length++] = c; 129 return; 130 } 131 132 if (!(c & ~0xff)) { 133 m_bufferCharacters8[m_length++] = static_cast<LChar>(c); 134 return; 135 } 136 } 137 append(&c, 1); 138 } 139 140 void append(LChar c) 141 { 142 if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) { 143 if (m_is8Bit) 144 m_bufferCharacters8[m_length++] = c; 145 else 146 m_bufferCharacters16[m_length++] = c; 147 } else 148 append(&c, 1); 149 } 150 151 void append(char c) 152 { 153 append(static_cast<LChar>(c)); 154 } 155 156 void append(UChar32 c) 157 { 158 if (U_IS_BMP(c)) { 159 append(static_cast<UChar>(c)); 160 return; 161 } 162 append(U16_LEAD(c)); 163 append(U16_TRAIL(c)); 164 } 165 166 template<unsigned charactersCount> 167 ALWAYS_INLINE void appendLiteral(const char (&characters)[charactersCount]) { append(characters, charactersCount - 1); } 168 169 void appendNumber(int); 170 void appendNumber(unsigned); 171 void appendNumber(long); 172 void appendNumber(unsigned long); 173 void appendNumber(long long); 174 void appendNumber(unsigned long long); 175 176 String toString() 177 { 178 shrinkToFit(); 179 if (m_string.isNull()) 180 reifyString(); 181 return m_string; 182 } 183 184 String substring(unsigned position, unsigned length) const 185 { 186 if (!m_length) 187 return emptyString(); 188 if (!m_string.isNull()) 189 return m_string.substring(position, length); 190 return reifySubstring(position, length); 191 } 192 193 AtomicString toAtomicString() const 194 { 195 if (!m_length) 196 return emptyAtom; 197 198 // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large. 199 if (canShrink()) { 200 if (is8Bit()) 201 return AtomicString(characters8(), length()); 202 return AtomicString(characters16(), length()); 203 } 204 205 if (!m_string.isNull()) 206 return AtomicString(m_string); 207 208 ASSERT(m_buffer); 209 return AtomicString(m_buffer.get(), 0, m_length); 210 } 211 212 unsigned length() const 213 { 214 return m_length; 215 } 216 217 bool isEmpty() const { return !m_length; } 218 219 void reserveCapacity(unsigned newCapacity); 220 221 unsigned capacity() const 222 { 223 return m_buffer ? m_buffer->length() : m_length; 224 } 225 226 void resize(unsigned newSize); 227 228 bool canShrink() const; 229 230 void shrinkToFit(); 231 232 UChar operator[](unsigned i) const 233 { 234 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); 235 if (m_is8Bit) 236 return characters8()[i]; 237 return characters16()[i]; 238 } 239 240 const LChar* characters8() const 241 { 242 ASSERT(m_is8Bit); 243 if (!m_length) 244 return 0; 245 if (!m_string.isNull()) 246 return m_string.characters8(); 247 ASSERT(m_buffer); 248 return m_buffer->characters8(); 249 } 250 251 const UChar* characters16() const 252 { 253 ASSERT(!m_is8Bit); 254 if (!m_length) 255 return 0; 256 if (!m_string.isNull()) 257 return m_string.characters16(); 258 ASSERT(m_buffer); 259 return m_buffer->characters16(); 260 } 261 262 bool is8Bit() const { return m_is8Bit; } 263 264 void clear() 265 { 266 m_length = 0; 267 m_string = String(); 268 m_buffer = 0; 269 m_bufferCharacters8 = 0; 270 m_is8Bit = true; 271 } 272 273 void swap(StringBuilder& stringBuilder) 274 { 275 std::swap(m_length, stringBuilder.m_length); 276 m_string.swap(stringBuilder.m_string); 277 m_buffer.swap(stringBuilder.m_buffer); 278 std::swap(m_is8Bit, stringBuilder.m_is8Bit); 279 std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8); 280 } 281 282 private: 283 void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength); 284 void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength); 285 void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength); 286 template <typename CharType> 287 void reallocateBuffer(unsigned requiredLength); 288 template <typename CharType> 289 ALWAYS_INLINE CharType* appendUninitialized(unsigned length); 290 template <typename CharType> 291 CharType* appendUninitializedSlow(unsigned length); 292 template <typename CharType> 293 ALWAYS_INLINE CharType * getBufferCharacters(); 294 void reifyString(); 295 String reifySubstring(unsigned position, unsigned length) const; 296 297 String m_string; // Pointers first: crbug.com/232031 298 RefPtr<StringImpl> m_buffer; 299 union { 300 LChar* m_bufferCharacters8; 301 UChar* m_bufferCharacters16; 302 }; 303 unsigned m_length; 304 bool m_is8Bit; 305 }; 306 307 template <> 308 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>() 309 { 310 ASSERT(m_is8Bit); 311 return m_bufferCharacters8; 312 } 313 314 template <> 315 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>() 316 { 317 ASSERT(!m_is8Bit); 318 return m_bufferCharacters16; 319 } 320 321 template <typename CharType> 322 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length) 323 { 324 if (s.length() != length) 325 return false; 326 327 if (s.is8Bit()) 328 return equal(s.characters8(), buffer, length); 329 330 return equal(s.characters16(), buffer, length); 331 } 332 333 template<typename CharType> 334 bool equalIgnoringCase(const StringBuilder& s, const CharType* buffer, unsigned length) 335 { 336 if (s.length() != length) 337 return false; 338 339 if (s.is8Bit()) 340 return equalIgnoringCase(s.characters8(), buffer, length); 341 342 return equalIgnoringCase(s.characters16(), buffer, length); 343 } 344 345 inline bool equalIgnoringCase(const StringBuilder& s, const char* string) 346 { 347 return equalIgnoringCase(s, reinterpret_cast<const LChar*>(string), strlen(string)); 348 } 349 350 template <typename StringType> 351 bool equal(const StringBuilder& a, const StringType& b) 352 { 353 if (a.length() != b.length()) 354 return false; 355 356 if (!a.length()) 357 return true; 358 359 if (a.is8Bit()) { 360 if (b.is8Bit()) 361 return equal(a.characters8(), b.characters8(), a.length()); 362 return equal(a.characters8(), b.characters16(), a.length()); 363 } 364 365 if (b.is8Bit()) 366 return equal(a.characters16(), b.characters8(), a.length()); 367 return equal(a.characters16(), b.characters16(), a.length()); 368 } 369 370 template <typename StringType> 371 bool equalIgnoringCase(const StringBuilder& a, const StringType& b) 372 { 373 if (a.length() != b.length()) 374 return false; 375 376 if (!a.length()) 377 return true; 378 379 if (a.is8Bit()) { 380 if (b.is8Bit()) 381 return equalIgnoringCase(a.characters8(), b.characters8(), a.length()); 382 return equalIgnoringCase(a.characters8(), b.characters16(), a.length()); 383 } 384 385 if (b.is8Bit()) 386 return equalIgnoringCase(a.characters16(), b.characters8(), a.length()); 387 return equalIgnoringCase(a.characters16(), b.characters16(), a.length()); 388 } 389 390 inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); } 391 inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); } 392 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); } 393 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); } 394 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); } 395 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); } 396 397 } // namespace WTF 398 399 using WTF::StringBuilder; 400 401 #endif // StringBuilder_h 402