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 void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros); 176 177 String toString() 178 { 179 shrinkToFit(); 180 if (m_string.isNull()) 181 reifyString(); 182 return m_string; 183 } 184 185 String substring(unsigned position, unsigned length) const 186 { 187 if (!m_length) 188 return emptyString(); 189 if (!m_string.isNull()) 190 return m_string.substring(position, length); 191 return reifySubstring(position, length); 192 } 193 194 AtomicString toAtomicString() const 195 { 196 if (!m_length) 197 return emptyAtom; 198 199 // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large. 200 if (canShrink()) { 201 if (is8Bit()) 202 return AtomicString(characters8(), length()); 203 return AtomicString(characters16(), length()); 204 } 205 206 if (!m_string.isNull()) 207 return AtomicString(m_string); 208 209 ASSERT(m_buffer); 210 return AtomicString(m_buffer.get(), 0, m_length); 211 } 212 213 unsigned length() const 214 { 215 return m_length; 216 } 217 218 bool isEmpty() const { return !m_length; } 219 220 void reserveCapacity(unsigned newCapacity); 221 222 unsigned capacity() const 223 { 224 return m_buffer ? m_buffer->length() : m_length; 225 } 226 227 void resize(unsigned newSize); 228 229 bool canShrink() const; 230 231 void shrinkToFit(); 232 233 UChar operator[](unsigned i) const 234 { 235 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); 236 if (m_is8Bit) 237 return characters8()[i]; 238 return characters16()[i]; 239 } 240 241 const LChar* characters8() const 242 { 243 ASSERT(m_is8Bit); 244 if (!m_length) 245 return 0; 246 if (!m_string.isNull()) 247 return m_string.characters8(); 248 ASSERT(m_buffer); 249 return m_buffer->characters8(); 250 } 251 252 const UChar* characters16() const 253 { 254 ASSERT(!m_is8Bit); 255 if (!m_length) 256 return 0; 257 if (!m_string.isNull()) 258 return m_string.characters16(); 259 ASSERT(m_buffer); 260 return m_buffer->characters16(); 261 } 262 263 bool is8Bit() const { return m_is8Bit; } 264 265 void clear() 266 { 267 m_length = 0; 268 m_string = String(); 269 m_buffer = nullptr; 270 m_bufferCharacters8 = 0; 271 m_is8Bit = true; 272 } 273 274 void swap(StringBuilder& stringBuilder) 275 { 276 std::swap(m_length, stringBuilder.m_length); 277 m_string.swap(stringBuilder.m_string); 278 m_buffer.swap(stringBuilder.m_buffer); 279 std::swap(m_is8Bit, stringBuilder.m_is8Bit); 280 std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8); 281 } 282 283 private: 284 void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength); 285 void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength); 286 void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength); 287 template <typename CharType> 288 void reallocateBuffer(unsigned requiredLength); 289 template <typename CharType> 290 ALWAYS_INLINE CharType* appendUninitialized(unsigned length); 291 template <typename CharType> 292 CharType* appendUninitializedSlow(unsigned length); 293 template <typename CharType> 294 ALWAYS_INLINE CharType * getBufferCharacters(); 295 void reifyString(); 296 String reifySubstring(unsigned position, unsigned length) const; 297 298 String m_string; // Pointers first: crbug.com/232031 299 RefPtr<StringImpl> m_buffer; 300 union { 301 LChar* m_bufferCharacters8; 302 UChar* m_bufferCharacters16; 303 }; 304 unsigned m_length; 305 bool m_is8Bit; 306 }; 307 308 template <> 309 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>() 310 { 311 ASSERT(m_is8Bit); 312 return m_bufferCharacters8; 313 } 314 315 template <> 316 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>() 317 { 318 ASSERT(!m_is8Bit); 319 return m_bufferCharacters16; 320 } 321 322 template <typename CharType> 323 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length) 324 { 325 if (s.length() != length) 326 return false; 327 328 if (s.is8Bit()) 329 return equal(s.characters8(), buffer, length); 330 331 return equal(s.characters16(), buffer, length); 332 } 333 334 template<typename CharType> 335 bool equalIgnoringCase(const StringBuilder& s, const CharType* buffer, unsigned length) 336 { 337 if (s.length() != length) 338 return false; 339 340 if (s.is8Bit()) 341 return equalIgnoringCase(s.characters8(), buffer, length); 342 343 return equalIgnoringCase(s.characters16(), buffer, length); 344 } 345 346 inline bool equalIgnoringCase(const StringBuilder& s, const char* string) 347 { 348 return equalIgnoringCase(s, reinterpret_cast<const LChar*>(string), strlen(string)); 349 } 350 351 template <typename StringType> 352 bool equal(const StringBuilder& a, const StringType& b) 353 { 354 if (a.length() != b.length()) 355 return false; 356 357 if (!a.length()) 358 return true; 359 360 if (a.is8Bit()) { 361 if (b.is8Bit()) 362 return equal(a.characters8(), b.characters8(), a.length()); 363 return equal(a.characters8(), b.characters16(), a.length()); 364 } 365 366 if (b.is8Bit()) 367 return equal(a.characters16(), b.characters8(), a.length()); 368 return equal(a.characters16(), b.characters16(), a.length()); 369 } 370 371 template <typename StringType> 372 bool equalIgnoringCase(const StringBuilder& a, const StringType& b) 373 { 374 if (a.length() != b.length()) 375 return false; 376 377 if (!a.length()) 378 return true; 379 380 if (a.is8Bit()) { 381 if (b.is8Bit()) 382 return equalIgnoringCase(a.characters8(), b.characters8(), a.length()); 383 return equalIgnoringCase(a.characters8(), b.characters16(), a.length()); 384 } 385 386 if (b.is8Bit()) 387 return equalIgnoringCase(a.characters16(), b.characters8(), a.length()); 388 return equalIgnoringCase(a.characters16(), b.characters16(), a.length()); 389 } 390 391 inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); } 392 inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); } 393 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); } 394 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); } 395 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); } 396 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); } 397 398 } // namespace WTF 399 400 using WTF::StringBuilder; 401 402 #endif // StringBuilder_h 403