Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2010 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 | 26 |
| 27 #include "wtf/text/StringBuilder.h" | 27 #include "wtf/text/StringBuilder.h" |
| 28 | 28 |
| 29 #include "wtf/dtoa.h" | 29 #include "wtf/dtoa.h" |
| 30 #include "wtf/text/IntegerToStringConversion.h" | 30 #include "wtf/text/IntegerToStringConversion.h" |
| 31 #include "wtf/text/WTFString.h" | 31 #include "wtf/text/WTFString.h" |
| 32 #include <algorithm> | 32 #include <algorithm> |
| 33 | 33 |
| 34 namespace WTF { | 34 namespace WTF { |
| 35 | 35 |
| 36 static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength) | 36 String StringBuilder::toString() |
| 37 { | 37 { |
| 38 static const unsigned minimumCapacity = 16; | 38 if (!m_length) |
| 39 return std::max(requiredLength, std::max(minimumCapacity, capacity * 2)); | 39 return emptyString(); |
| 40 if (m_string.isNull()) { | |
| 41 if (m_is8Bit) | |
| 42 m_string = String(characters8(), m_length); | |
| 43 else | |
| 44 m_string = String(characters16(), m_length); | |
| 45 } | |
| 46 return m_string; | |
| 40 } | 47 } |
| 41 | 48 |
| 42 void StringBuilder::reifyString() | 49 AtomicString StringBuilder::toAtomicString() |
| 43 { | 50 { |
| 44 if (!m_string.isNull()) { | 51 if (!m_length) |
| 45 DCHECK_EQ(m_string.length(), m_length); | 52 return emptyAtom; |
| 46 return; | 53 if (m_string.isNull()) { |
| 54 if (m_is8Bit) | |
| 55 m_string = AtomicString(characters8(), m_length); | |
| 56 else | |
| 57 m_string = AtomicString(characters16(), m_length); | |
| 47 } | 58 } |
| 48 | 59 return AtomicString(m_string); |
| 49 if (!m_length) { | |
| 50 m_string = StringImpl::empty(); | |
| 51 return; | |
| 52 } | |
| 53 | |
| 54 DCHECK(m_buffer); | |
| 55 DCHECK_LE(m_length, m_buffer->length()); | |
| 56 if (m_length == m_buffer->length()) { | |
| 57 m_string = m_buffer.release(); | |
| 58 return; | |
| 59 } | |
| 60 | |
| 61 m_string = m_buffer->substring(0, m_length); | |
| 62 } | 60 } |
| 63 | 61 |
| 64 String StringBuilder::reifySubstring(unsigned position, unsigned length) const | 62 String StringBuilder::substring(unsigned start, unsigned length) const |
| 65 { | 63 { |
| 66 DCHECK(m_string.isNull()); | 64 if (start >= m_length) |
| 67 DCHECK(m_buffer); | 65 return emptyString(); |
| 68 unsigned substringLength = std::min(length, m_length - position); | 66 if (!m_string.isNull()) |
| 69 return m_buffer->substring(position, substringLength); | 67 return m_string.substring(start, length); |
| 68 length = std::min(length, m_length - start); | |
| 69 if (m_is8Bit) | |
| 70 return String(characters8() + start, length); | |
| 71 return String(characters16() + start, length); | |
| 72 } | |
| 73 | |
| 74 void StringBuilder::swap(StringBuilder& builder) | |
| 75 { | |
| 76 std::swap(m_string, builder.m_string); | |
| 77 std::swap(m_buffer, builder.m_buffer); | |
| 78 std::swap(m_length, builder.m_length); | |
| 79 std::swap(m_is8Bit, builder.m_is8Bit); | |
| 80 } | |
| 81 | |
| 82 void StringBuilder::clear() | |
| 83 { | |
| 84 m_string = String(); | |
| 85 if (m_is8Bit) | |
| 86 delete m_buffer8; | |
|
haraken
2016/06/27 06:36:01
Can we use OwnPtr and avoid using manual delete?
hajimehoshi
2016/06/27 06:38:02
unique_ptr I think :-)
esprehn
2016/06/27 23:36:40
No, you can't store a unique_ptr in a union. So we
hajimehoshi
2016/06/28 05:01:35
Out of curiosity, isn't it possible to use two uni
| |
| 87 else | |
| 88 delete m_buffer16; | |
| 89 m_buffer = nullptr; | |
| 90 m_length = 0; | |
| 91 m_is8Bit = true; | |
| 92 } | |
| 93 | |
| 94 unsigned StringBuilder::capacity() const | |
| 95 { | |
| 96 if (!hasBuffer()) | |
| 97 return 0; | |
| 98 if (m_is8Bit) | |
| 99 return m_buffer8->capacity(); | |
| 100 return m_buffer16->capacity(); | |
| 101 } | |
| 102 | |
| 103 void StringBuilder::reserveCapacity(unsigned newCapacity) | |
| 104 { | |
| 105 if (m_is8Bit) { | |
| 106 ensureBuffer8(); | |
| 107 m_buffer8->reserveCapacity(newCapacity); | |
| 108 } else { | |
| 109 ensureBuffer16(); | |
| 110 m_buffer16->reserveCapacity(newCapacity); | |
| 111 } | |
| 70 } | 112 } |
| 71 | 113 |
| 72 void StringBuilder::resize(unsigned newSize) | 114 void StringBuilder::resize(unsigned newSize) |
| 73 { | 115 { |
| 74 // Check newSize < m_length, hence m_length > 0. | |
| 75 DCHECK_LE(newSize, m_length); | 116 DCHECK_LE(newSize, m_length); |
| 76 if (newSize == m_length) | 117 m_length = newSize; |
| 118 m_string = String(); | |
| 119 if (!hasBuffer()) | |
| 77 return; | 120 return; |
| 78 DCHECK(m_length); | 121 if (m_is8Bit) |
| 122 m_buffer8->resize(newSize); | |
| 123 else | |
| 124 m_buffer16->resize(newSize); | |
| 125 } | |
| 79 | 126 |
| 80 // If there is a buffer, we only need to duplicate it if it has more than on e ref. | 127 void StringBuilder::createBuffer8() |
| 81 if (m_buffer) { | 128 { |
| 82 m_string = String(); // Clear the string to remove the reference to m_bu ffer if any before checking the reference count of m_buffer. | 129 DCHECK(!hasBuffer()); |
| 83 if (!m_buffer->hasOneRef()) { | 130 DCHECK(m_is8Bit); |
| 84 if (m_buffer->is8Bit()) | 131 m_buffer8 = new Buffer8; |
| 85 allocateBuffer(m_buffer->characters8(), m_buffer->length()); | 132 m_length = 0; |
| 86 else | 133 // Must keep a ref to the string since append will clear it. |
| 87 allocateBuffer(m_buffer->characters16(), m_buffer->length()); | 134 String string(m_string); |
| 88 } | 135 append(string); |
| 89 m_length = newSize; | 136 } |
| 137 | |
| 138 void StringBuilder::createBuffer16() | |
| 139 { | |
| 140 DCHECK(m_is8Bit || !hasBuffer()); | |
|
haraken
2016/06/27 06:36:01
Slightly better:
DCHECK((m_is8Bit && m_buffer8)
esprehn
2016/06/27 23:36:40
I'm not sure what that does, if m_buffer8 is null
| |
| 141 Buffer8 buffer8; | |
| 142 unsigned length = m_length; | |
| 143 if (m_buffer8) { | |
| 144 m_buffer8->swap(buffer8); | |
| 145 delete m_buffer8; | |
| 146 } | |
| 147 m_buffer16 = new Buffer16; | |
| 148 m_is8Bit = false; | |
| 149 m_length = 0; | |
| 150 if (!buffer8.isEmpty()) { | |
| 151 append(buffer8.data(), length); | |
| 90 return; | 152 return; |
| 91 } | 153 } |
| 92 | 154 // Must keep a ref to the string since append will clear it. |
| 93 // Since m_length && !m_buffer, the string must be valid in m_string, and m_ string.length() > 0. | 155 String string(m_string); |
| 94 DCHECK(!m_string.isEmpty()); | 156 append(string); |
| 95 DCHECK_EQ(m_length, m_string.length()); | |
| 96 DCHECK_LT(newSize, m_string.length()); | |
| 97 m_length = newSize; | |
| 98 RefPtr<StringImpl> string = m_string.releaseImpl(); | |
| 99 if (string->hasOneRef()) { | |
| 100 // If we're the only ones with a reference to the string, we can | |
| 101 // re-purpose the string as m_buffer and continue mutating it. | |
| 102 m_buffer = string; | |
| 103 } else { | |
| 104 // Otherwise, we need to make a copy of the string so that we don't | |
| 105 // mutate a String that's held elsewhere. | |
| 106 m_buffer = string->substring(0, m_length); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come fro m either m_string | |
| 111 // or m_buffer, neither will be reassigned until the copy has completed). | |
| 112 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ iredLength) | |
| 113 { | |
| 114 DCHECK(m_is8Bit); | |
| 115 // Copy the existing data into a new buffer, set result to point to the end of the existing data. | |
| 116 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8); | |
| 117 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow. | |
| 118 | |
| 119 // Update the builder state. | |
| 120 m_buffer = buffer.release(); | |
| 121 m_string = String(); | |
| 122 } | |
| 123 | |
| 124 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come fr om either m_string | |
| 125 // or m_buffer, neither will be reassigned until the copy has completed). | |
| 126 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ iredLength) | |
| 127 { | |
| 128 DCHECK(!m_is8Bit); | |
| 129 // Copy the existing data into a new buffer, set result to point to the end of the existing data. | |
| 130 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); | |
| 131 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length ) * sizeof(UChar)); // This can't overflow. | |
| 132 | |
| 133 // Update the builder state. | |
| 134 m_buffer = buffer.release(); | |
| 135 m_string = String(); | |
| 136 } | |
| 137 | |
| 138 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit an d may come | |
| 139 // from either m_string or m_buffer, neither will be reassigned until the copy h as completed). | |
| 140 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsi gned requiredLength) | |
| 141 { | |
| 142 DCHECK(m_is8Bit); | |
| 143 // Copy the existing data into a new buffer, set result to point to the end of the existing data. | |
| 144 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); | |
| 145 for (unsigned i = 0; i < m_length; ++i) | |
| 146 m_bufferCharacters16[i] = currentCharacters[i]; | |
| 147 | |
| 148 m_is8Bit = false; | |
| 149 | |
| 150 // Update the builder state. | |
| 151 m_buffer = buffer.release(); | |
| 152 m_string = String(); | |
| 153 } | |
| 154 | |
| 155 template <> | |
| 156 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) | |
| 157 { | |
| 158 // If the buffer has only one ref (by this StringBuilder), reallocate it, | |
| 159 // otherwise fall back to "allocate and copy" method. | |
| 160 m_string = String(); | |
| 161 | |
| 162 DCHECK(m_is8Bit); | |
| 163 DCHECK(m_buffer->is8Bit()); | |
| 164 | |
| 165 allocateBuffer(m_buffer->characters8(), requiredLength); | |
| 166 } | |
| 167 | |
| 168 template <> | |
| 169 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) | |
| 170 { | |
| 171 // If the buffer has only one ref (by this StringBuilder), reallocate it, | |
| 172 // otherwise fall back to "allocate and copy" method. | |
| 173 m_string = String(); | |
| 174 | |
| 175 if (m_buffer->is8Bit()) | |
| 176 allocateBufferUpConvert(m_buffer->characters8(), requiredLength); | |
| 177 else | |
| 178 allocateBuffer(m_buffer->characters16(), requiredLength); | |
| 179 } | |
| 180 | |
| 181 void StringBuilder::reserveCapacity(unsigned newCapacity) | |
| 182 { | |
| 183 if (m_buffer) { | |
| 184 // If there is already a buffer, then grow if necessary. | |
| 185 if (newCapacity > m_buffer->length()) { | |
| 186 if (m_buffer->is8Bit()) | |
| 187 reallocateBuffer<LChar>(newCapacity); | |
| 188 else | |
| 189 reallocateBuffer<UChar>(newCapacity); | |
| 190 } | |
| 191 } else { | |
| 192 // Grow the string, if necessary. | |
| 193 if (newCapacity > m_length) { | |
| 194 if (!m_length) { | |
| 195 LChar* nullPlaceholder = 0; | |
| 196 allocateBuffer(nullPlaceholder, newCapacity); | |
| 197 } else if (m_string.is8Bit()) { | |
| 198 allocateBuffer(m_string.characters8(), newCapacity); | |
| 199 } else { | |
| 200 allocateBuffer(m_string.characters16(), newCapacity); | |
| 201 } | |
| 202 } | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length, | |
| 207 // return a pointer to the newly allocated storage. | |
| 208 template <typename CharType> | |
| 209 ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length) | |
| 210 { | |
| 211 DCHECK(length); | |
| 212 | |
| 213 // Calculate the new size of the builder after appending. | |
| 214 unsigned requiredLength = length + m_length; | |
| 215 CHECK_GE(requiredLength, length); | |
| 216 | |
| 217 if ((m_buffer) && (requiredLength <= m_buffer->length())) { | |
| 218 // If the buffer is valid it must be at least as long as the current bui lder contents! | |
| 219 DCHECK_GE(m_buffer->length(), m_length); | |
| 220 unsigned currentLength = m_length; | |
| 221 m_string = String(); | |
| 222 m_length = requiredLength; | |
| 223 return getBufferCharacters<CharType>() + currentLength; | |
| 224 } | |
| 225 | |
| 226 return appendUninitializedSlow<CharType>(requiredLength); | |
| 227 } | |
| 228 | |
| 229 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length, | |
| 230 // return a pointer to the newly allocated storage. | |
| 231 template <typename CharType> | |
| 232 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) | |
| 233 { | |
| 234 DCHECK(requiredLength); | |
| 235 | |
| 236 if (m_buffer) { | |
| 237 // If the buffer is valid it must be at least as long as the current bui lder contents! | |
| 238 DCHECK_GE(m_buffer->length(), m_length); | |
| 239 | |
| 240 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength)) ; | |
| 241 } else { | |
| 242 DCHECK_EQ(m_string.length(), m_length); | |
| 243 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expand edCapacity(capacity(), requiredLength)); | |
| 244 } | |
| 245 | |
| 246 CharType* result = getBufferCharacters<CharType>() + m_length; | |
| 247 m_length = requiredLength; | |
| 248 return result; | |
| 249 } | 157 } |
| 250 | 158 |
| 251 void StringBuilder::append(const UChar* characters, unsigned length) | 159 void StringBuilder::append(const UChar* characters, unsigned length) |
| 252 { | 160 { |
| 253 if (!length) | 161 if (!length) |
| 254 return; | 162 return; |
| 255 | |
| 256 DCHECK(characters); | 163 DCHECK(characters); |
| 257 | 164 |
| 258 if (m_is8Bit) { | 165 // If there's only one char we use append(UChar) instead since it will |
| 259 if (length == 1 && !(*characters & ~0xff)) { | 166 // check for latin1 and avoid converting to 16bit if possible. |
| 260 // Append as 8 bit character | 167 if (length == 1) { |
| 261 LChar lChar = static_cast<LChar>(*characters); | 168 append(*characters); |
| 262 append(&lChar, 1); | 169 return; |
| 263 return; | 170 } |
| 264 } | |
| 265 | 171 |
| 266 // Calculate the new size of the builder after appending. | 172 ensureBuffer16(); |
| 267 unsigned requiredLength = length + m_length; | 173 m_string = String(); |
| 268 CHECK_GE(requiredLength, length); | 174 m_buffer16->append(characters, length); |
| 269 | 175 m_length += length; |
| 270 if (m_buffer) { | |
| 271 // If the buffer is valid it must be at least as long as the current builder contents! | |
| 272 DCHECK_GE(m_buffer->length(), m_length); | |
| 273 | |
| 274 allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(ca pacity(), requiredLength)); | |
| 275 } else { | |
| 276 DCHECK_EQ(m_string.length(), m_length); | |
| 277 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8 (), expandedCapacity(capacity(), requiredLength)); | |
| 278 } | |
| 279 | |
| 280 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>( length) * sizeof(UChar)); | |
| 281 m_length = requiredLength; | |
| 282 } else { | |
| 283 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_ t>(length) * sizeof(UChar)); | |
| 284 } | |
| 285 } | 176 } |
| 286 | 177 |
| 287 void StringBuilder::append(const LChar* characters, unsigned length) | 178 void StringBuilder::append(const LChar* characters, unsigned length) |
| 288 { | 179 { |
| 289 if (!length) | 180 if (!length) |
| 290 return; | 181 return; |
| 291 DCHECK(characters); | 182 DCHECK(characters); |
| 292 | 183 |
| 293 if (m_is8Bit) { | 184 if (m_is8Bit) { |
| 294 LChar* dest = appendUninitialized<LChar>(length); | 185 ensureBuffer8(); |
| 295 if (length > 8) { | 186 m_string = String(); |
| 296 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar) ); | 187 m_buffer8->append(characters, length); |
| 297 } else { | 188 m_length += length; |
| 298 const LChar* end = characters + length; | 189 return; |
| 299 while (characters < end) | |
| 300 *(dest++) = *(characters++); | |
| 301 } | |
| 302 } else { | |
| 303 UChar* dest = appendUninitialized<UChar>(length); | |
| 304 const LChar* end = characters + length; | |
| 305 while (characters < end) | |
| 306 *(dest++) = *(characters++); | |
| 307 } | 190 } |
| 191 | |
| 192 ensureBuffer16(); | |
| 193 m_string = String(); | |
| 194 m_buffer16->reserveCapacity(m_buffer16->size() + length); | |
| 195 for (size_t i = 0; i < length; ++i) | |
| 196 m_buffer16->uncheckedAppend(characters[i]); | |
| 197 m_length += length; | |
| 308 } | 198 } |
| 309 | 199 |
| 310 template<typename IntegerType> | 200 template<typename IntegerType> |
| 311 static void appendIntegerInternal(StringBuilder& builder, IntegerType input) | 201 static void appendIntegerInternal(StringBuilder& builder, IntegerType input) |
| 312 { | 202 { |
| 313 IntegerToStringConverter<IntegerType> converter(input); | 203 IntegerToStringConverter<IntegerType> converter(input); |
| 314 builder.append(converter.characters8(), converter.length()); | 204 builder.append(converter.characters8(), converter.length()); |
| 315 } | 205 } |
| 316 | 206 |
| 317 void StringBuilder::appendNumber(int number) | 207 void StringBuilder::appendNumber(int number) |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 337 void StringBuilder::appendNumber(long long number) | 227 void StringBuilder::appendNumber(long long number) |
| 338 { | 228 { |
| 339 appendIntegerInternal(*this, number); | 229 appendIntegerInternal(*this, number); |
| 340 } | 230 } |
| 341 | 231 |
| 342 void StringBuilder::appendNumber(unsigned long long number) | 232 void StringBuilder::appendNumber(unsigned long long number) |
| 343 { | 233 { |
| 344 appendIntegerInternal(*this, number); | 234 appendIntegerInternal(*this, number); |
| 345 } | 235 } |
| 346 | 236 |
| 347 static void expandLCharToUCharInplace(UChar* buffer, size_t length) | |
| 348 { | |
| 349 const LChar* sourceEnd = reinterpret_cast<LChar*>(buffer) + length; | |
| 350 UChar* current = buffer + length; | |
| 351 while (current != buffer) | |
| 352 *--current = *--sourceEnd; | |
| 353 } | |
| 354 | |
| 355 void StringBuilder::appendNumber(double number, unsigned precision, TrailingZero sTruncatingPolicy trailingZerosTruncatingPolicy) | 237 void StringBuilder::appendNumber(double number, unsigned precision, TrailingZero sTruncatingPolicy trailingZerosTruncatingPolicy) |
| 356 { | 238 { |
| 357 bool truncateTrailingZeros = trailingZerosTruncatingPolicy == TruncateTraili ngZeros; | 239 NumberToStringBuffer buffer; |
| 358 size_t numberLength; | 240 append(numberToFixedPrecisionString(number, precision, buffer, trailingZeros TruncatingPolicy == TruncateTrailingZeros)); |
| 359 if (m_is8Bit) { | |
| 360 LChar* dest = appendUninitialized<LChar>(NumberToStringBufferLength); | |
| 361 const char* result = numberToFixedPrecisionString(number, precision, rei nterpret_cast<char*>(dest), truncateTrailingZeros); | |
| 362 numberLength = strlen(result); | |
| 363 } else { | |
| 364 UChar* dest = appendUninitialized<UChar>(NumberToStringBufferLength); | |
| 365 const char* result = numberToFixedPrecisionString(number, precision, rei nterpret_cast<char*>(dest), truncateTrailingZeros); | |
| 366 numberLength = strlen(result); | |
| 367 expandLCharToUCharInplace(dest, numberLength); | |
| 368 } | |
| 369 DCHECK_GE(m_length, NumberToStringBufferLength); | |
| 370 // Remove what appendUninitialized added. | |
| 371 m_length -= NumberToStringBufferLength; | |
| 372 DCHECK_LE(numberLength, NumberToStringBufferLength); | |
| 373 m_length += numberLength; | |
| 374 } | |
| 375 | |
| 376 bool StringBuilder::canShrink() const | |
| 377 { | |
| 378 // Only shrink the buffer if it's less than 80% full. Need to tune this heur istic! | |
| 379 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); | |
| 380 } | |
| 381 | |
| 382 void StringBuilder::shrinkToFit() | |
| 383 { | |
| 384 if (!canShrink()) | |
| 385 return; | |
| 386 if (m_is8Bit) | |
| 387 reallocateBuffer<LChar>(m_length); | |
| 388 else | |
| 389 reallocateBuffer<UChar>(m_length); | |
| 390 m_string = m_buffer.release(); | |
| 391 } | 241 } |
| 392 | 242 |
| 393 } // namespace WTF | 243 } // namespace WTF |
| OLD | NEW |