| 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 static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength) { |
| 37 { | 37 static const unsigned minimumCapacity = 16; |
| 38 static const unsigned minimumCapacity = 16; | 38 return std::max(requiredLength, std::max(minimumCapacity, capacity * 2)); |
| 39 return std::max(requiredLength, std::max(minimumCapacity, capacity * 2)); | 39 } |
| 40 } | 40 |
| 41 | 41 void StringBuilder::reifyString() { |
| 42 void StringBuilder::reifyString() | 42 if (!m_string.isNull()) { |
| 43 { | 43 ASSERT(m_string.length() == m_length); |
| 44 if (!m_string.isNull()) { | 44 return; |
| 45 ASSERT(m_string.length() == m_length); | 45 } |
| 46 return; | 46 |
| 47 } | 47 if (!m_length) { |
| 48 | 48 m_string = StringImpl::empty(); |
| 49 if (!m_length) { | 49 return; |
| 50 m_string = StringImpl::empty(); | 50 } |
| 51 return; | 51 |
| 52 } | 52 ASSERT(m_buffer && m_length <= m_buffer->length()); |
| 53 | 53 if (m_length == m_buffer->length()) { |
| 54 ASSERT(m_buffer && m_length <= m_buffer->length()); | 54 m_string = m_buffer.release(); |
| 55 if (m_length == m_buffer->length()) { | 55 return; |
| 56 m_string = m_buffer.release(); | 56 } |
| 57 return; | 57 |
| 58 } | 58 m_string = m_buffer->substring(0, m_length); |
| 59 | 59 } |
| 60 m_string = m_buffer->substring(0, m_length); | 60 |
| 61 } | 61 String StringBuilder::reifySubstring(unsigned position, unsigned length) const { |
| 62 | 62 ASSERT(m_string.isNull()); |
| 63 String StringBuilder::reifySubstring(unsigned position, unsigned length) const | 63 ASSERT(m_buffer); |
| 64 { | 64 unsigned substringLength = std::min(length, m_length - position); |
| 65 ASSERT(m_string.isNull()); | 65 return m_buffer->substring(position, substringLength); |
| 66 ASSERT(m_buffer); | 66 } |
| 67 unsigned substringLength = std::min(length, m_length - position); | 67 |
| 68 return m_buffer->substring(position, substringLength); | 68 void StringBuilder::resize(unsigned newSize) { |
| 69 } | 69 // Check newSize < m_length, hence m_length > 0. |
| 70 | 70 ASSERT(newSize <= m_length); |
| 71 void StringBuilder::resize(unsigned newSize) | 71 if (newSize == m_length) |
| 72 { | 72 return; |
| 73 // Check newSize < m_length, hence m_length > 0. | 73 ASSERT(m_length); |
| 74 ASSERT(newSize <= m_length); | 74 |
| 75 if (newSize == m_length) | 75 // If there is a buffer, we only need to duplicate it if it has more than one
ref. |
| 76 return; | 76 if (m_buffer) { |
| 77 ASSERT(m_length); | 77 m_string = |
| 78 | 78 String(); // Clear the string to remove the reference to m_buffer if an
y before checking the reference count of m_buffer. |
| 79 // If there is a buffer, we only need to duplicate it if it has more than on
e ref. | 79 if (!m_buffer->hasOneRef()) { |
| 80 if (m_buffer) { | 80 if (m_buffer->is8Bit()) |
| 81 m_string = String(); // Clear the string to remove the reference to m_bu
ffer if any before checking the reference count of m_buffer. | 81 allocateBuffer(m_buffer->characters8(), m_buffer->length()); |
| 82 if (!m_buffer->hasOneRef()) { | 82 else |
| 83 if (m_buffer->is8Bit()) | 83 allocateBuffer(m_buffer->characters16(), m_buffer->length()); |
| 84 allocateBuffer(m_buffer->characters8(), m_buffer->length()); | 84 } |
| 85 else | |
| 86 allocateBuffer(m_buffer->characters16(), m_buffer->length()); | |
| 87 } | |
| 88 m_length = newSize; | |
| 89 return; | |
| 90 } | |
| 91 | |
| 92 // Since m_length && !m_buffer, the string must be valid in m_string, and m_
string.length() > 0. | |
| 93 ASSERT(!m_string.isEmpty()); | |
| 94 ASSERT(m_length == m_string.length()); | |
| 95 ASSERT(newSize < m_string.length()); | |
| 96 m_length = newSize; | 85 m_length = newSize; |
| 97 RefPtr<StringImpl> string = m_string.releaseImpl(); | 86 return; |
| 98 if (string->hasOneRef()) { | 87 } |
| 99 // If we're the only ones with a reference to the string, we can | 88 |
| 100 // re-purpose the string as m_buffer and continue mutating it. | 89 // Since m_length && !m_buffer, the string must be valid in m_string, and m_st
ring.length() > 0. |
| 101 m_buffer = string; | 90 ASSERT(!m_string.isEmpty()); |
| 102 } else { | 91 ASSERT(m_length == m_string.length()); |
| 103 // Otherwise, we need to make a copy of the string so that we don't | 92 ASSERT(newSize < m_string.length()); |
| 104 // mutate a String that's held elsewhere. | 93 m_length = newSize; |
| 105 m_buffer = string->substring(0, m_length); | 94 RefPtr<StringImpl> string = m_string.releaseImpl(); |
| 106 } | 95 if (string->hasOneRef()) { |
| 96 // If we're the only ones with a reference to the string, we can |
| 97 // re-purpose the string as m_buffer and continue mutating it. |
| 98 m_buffer = string; |
| 99 } else { |
| 100 // Otherwise, we need to make a copy of the string so that we don't |
| 101 // mutate a String that's held elsewhere. |
| 102 m_buffer = string->substring(0, m_length); |
| 103 } |
| 107 } | 104 } |
| 108 | 105 |
| 109 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come fro
m either m_string | 106 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come fro
m either m_string |
| 110 // or m_buffer, neither will be reassigned until the copy has completed). | 107 // or m_buffer, neither will be reassigned until the copy has completed). |
| 111 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ
iredLength) | 108 void StringBuilder::allocateBuffer(const LChar* currentCharacters, |
| 112 { | 109 unsigned requiredLength) { |
| 113 ASSERT(m_is8Bit); | 110 ASSERT(m_is8Bit); |
| 114 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 111 // Copy the existing data into a new buffer, set result to point to the end of
the existing data. |
| 115 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters8); | 112 RefPtr<StringImpl> buffer = |
| 116 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length)
* sizeof(LChar)); // This can't overflow. | 113 StringImpl::createUninitialized(requiredLength, m_bufferCharacters8); |
| 117 | 114 memcpy( |
| 118 // Update the builder state. | 115 m_bufferCharacters8, currentCharacters, |
| 119 m_buffer = buffer.release(); | 116 static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow. |
| 120 m_string = String(); | 117 |
| 118 // Update the builder state. |
| 119 m_buffer = buffer.release(); |
| 120 m_string = String(); |
| 121 } | 121 } |
| 122 | 122 |
| 123 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come fr
om either m_string | 123 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come fr
om either m_string |
| 124 // or m_buffer, neither will be reassigned until the copy has completed). | 124 // or m_buffer, neither will be reassigned until the copy has completed). |
| 125 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ
iredLength) | 125 void StringBuilder::allocateBuffer(const UChar* currentCharacters, |
| 126 { | 126 unsigned requiredLength) { |
| 127 ASSERT(!m_is8Bit); | 127 ASSERT(!m_is8Bit); |
| 128 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 128 // Copy the existing data into a new buffer, set result to point to the end of
the existing data. |
| 129 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); | 129 RefPtr<StringImpl> buffer = |
| 130 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length
) * sizeof(UChar)); // This can't overflow. | 130 StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); |
| 131 | 131 memcpy( |
| 132 // Update the builder state. | 132 m_bufferCharacters16, currentCharacters, |
| 133 m_buffer = buffer.release(); | 133 static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow. |
| 134 m_string = String(); | 134 |
| 135 // Update the builder state. |
| 136 m_buffer = buffer.release(); |
| 137 m_string = String(); |
| 135 } | 138 } |
| 136 | 139 |
| 137 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit an
d may come | 140 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit an
d may come |
| 138 // from either m_string or m_buffer, neither will be reassigned until the copy h
as completed). | 141 // from either m_string or m_buffer, neither will be reassigned until the copy h
as completed). |
| 139 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsi
gned requiredLength) | 142 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, |
| 140 { | 143 unsigned requiredLength) { |
| 141 ASSERT(m_is8Bit); | 144 ASSERT(m_is8Bit); |
| 142 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 145 // Copy the existing data into a new buffer, set result to point to the end of
the existing data. |
| 143 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); | 146 RefPtr<StringImpl> buffer = |
| 144 for (unsigned i = 0; i < m_length; ++i) | 147 StringImpl::createUninitialized(requiredLength, m_bufferCharacters16); |
| 145 m_bufferCharacters16[i] = currentCharacters[i]; | 148 for (unsigned i = 0; i < m_length; ++i) |
| 146 | 149 m_bufferCharacters16[i] = currentCharacters[i]; |
| 147 m_is8Bit = false; | 150 |
| 148 | 151 m_is8Bit = false; |
| 149 // Update the builder state. | 152 |
| 150 m_buffer = buffer.release(); | 153 // Update the builder state. |
| 151 m_string = String(); | 154 m_buffer = buffer.release(); |
| 155 m_string = String(); |
| 152 } | 156 } |
| 153 | 157 |
| 154 template <> | 158 template <> |
| 155 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) | 159 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) { |
| 156 { | 160 // If the buffer has only one ref (by this StringBuilder), reallocate it, |
| 157 // If the buffer has only one ref (by this StringBuilder), reallocate it, | 161 // otherwise fall back to "allocate and copy" method. |
| 158 // otherwise fall back to "allocate and copy" method. | 162 m_string = String(); |
| 159 m_string = String(); | 163 |
| 160 | 164 ASSERT(m_is8Bit); |
| 161 ASSERT(m_is8Bit); | 165 ASSERT(m_buffer->is8Bit()); |
| 162 ASSERT(m_buffer->is8Bit()); | 166 |
| 163 | 167 allocateBuffer(m_buffer->characters8(), requiredLength); |
| 164 allocateBuffer(m_buffer->characters8(), requiredLength); | |
| 165 } | 168 } |
| 166 | 169 |
| 167 template <> | 170 template <> |
| 168 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) | 171 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) { |
| 169 { | 172 // If the buffer has only one ref (by this StringBuilder), reallocate it, |
| 170 // If the buffer has only one ref (by this StringBuilder), reallocate it, | 173 // otherwise fall back to "allocate and copy" method. |
| 171 // otherwise fall back to "allocate and copy" method. | 174 m_string = String(); |
| 172 m_string = String(); | 175 |
| 173 | 176 if (m_buffer->is8Bit()) |
| 174 if (m_buffer->is8Bit()) | 177 allocateBufferUpConvert(m_buffer->characters8(), requiredLength); |
| 175 allocateBufferUpConvert(m_buffer->characters8(), requiredLength); | 178 else |
| 176 else | 179 allocateBuffer(m_buffer->characters16(), requiredLength); |
| 177 allocateBuffer(m_buffer->characters16(), requiredLength); | 180 } |
| 178 } | 181 |
| 179 | 182 void StringBuilder::reserveCapacity(unsigned newCapacity) { |
| 180 void StringBuilder::reserveCapacity(unsigned newCapacity) | 183 if (m_buffer) { |
| 181 { | 184 // If there is already a buffer, then grow if necessary. |
| 182 if (m_buffer) { | 185 if (newCapacity > m_buffer->length()) { |
| 183 // If there is already a buffer, then grow if necessary. | 186 if (m_buffer->is8Bit()) |
| 184 if (newCapacity > m_buffer->length()) { | 187 reallocateBuffer<LChar>(newCapacity); |
| 185 if (m_buffer->is8Bit()) | 188 else |
| 186 reallocateBuffer<LChar>(newCapacity); | 189 reallocateBuffer<UChar>(newCapacity); |
| 187 else | 190 } |
| 188 reallocateBuffer<UChar>(newCapacity); | 191 } else { |
| 189 } | 192 // Grow the string, if necessary. |
| 190 } else { | 193 if (newCapacity > m_length) { |
| 191 // Grow the string, if necessary. | 194 if (!m_length) { |
| 192 if (newCapacity > m_length) { | 195 LChar* nullPlaceholder = 0; |
| 193 if (!m_length) { | 196 allocateBuffer(nullPlaceholder, newCapacity); |
| 194 LChar* nullPlaceholder = 0; | 197 } else if (m_string.is8Bit()) { |
| 195 allocateBuffer(nullPlaceholder, newCapacity); | 198 allocateBuffer(m_string.characters8(), newCapacity); |
| 196 } else if (m_string.is8Bit()) { | 199 } else { |
| 197 allocateBuffer(m_string.characters8(), newCapacity); | 200 allocateBuffer(m_string.characters16(), newCapacity); |
| 198 } else { | 201 } |
| 199 allocateBuffer(m_string.characters16(), newCapacity); | 202 } |
| 200 } | 203 } |
| 201 } | |
| 202 } | |
| 203 } | 204 } |
| 204 | 205 |
| 205 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, | 206 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, |
| 206 // return a pointer to the newly allocated storage. | 207 // return a pointer to the newly allocated storage. |
| 207 template <typename CharType> | 208 template <typename CharType> |
| 208 ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length) | 209 ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length) { |
| 209 { | 210 ASSERT(length); |
| 210 ASSERT(length); | 211 |
| 212 // Calculate the new size of the builder after appending. |
| 213 unsigned requiredLength = length + m_length; |
| 214 RELEASE_ASSERT(requiredLength >= length); |
| 215 |
| 216 if ((m_buffer) && (requiredLength <= m_buffer->length())) { |
| 217 // If the buffer is valid it must be at least as long as the current builder
contents! |
| 218 ASSERT(m_buffer->length() >= m_length); |
| 219 unsigned currentLength = m_length; |
| 220 m_string = String(); |
| 221 m_length = requiredLength; |
| 222 return getBufferCharacters<CharType>() + currentLength; |
| 223 } |
| 224 |
| 225 return appendUninitializedSlow<CharType>(requiredLength); |
| 226 } |
| 227 |
| 228 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, |
| 229 // return a pointer to the newly allocated storage. |
| 230 template <typename CharType> |
| 231 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) { |
| 232 ASSERT(requiredLength); |
| 233 |
| 234 if (m_buffer) { |
| 235 // If the buffer is valid it must be at least as long as the current builder
contents! |
| 236 ASSERT(m_buffer->length() >= m_length); |
| 237 |
| 238 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength)); |
| 239 } else { |
| 240 ASSERT(m_string.length() == m_length); |
| 241 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, |
| 242 expandedCapacity(capacity(), requiredLength)); |
| 243 } |
| 244 |
| 245 CharType* result = getBufferCharacters<CharType>() + m_length; |
| 246 m_length = requiredLength; |
| 247 return result; |
| 248 } |
| 249 |
| 250 void StringBuilder::append(const UChar* characters, unsigned length) { |
| 251 if (!length) |
| 252 return; |
| 253 |
| 254 ASSERT(characters); |
| 255 |
| 256 if (m_is8Bit) { |
| 257 if (length == 1 && !(*characters & ~0xff)) { |
| 258 // Append as 8 bit character |
| 259 LChar lChar = static_cast<LChar>(*characters); |
| 260 append(&lChar, 1); |
| 261 return; |
| 262 } |
| 211 | 263 |
| 212 // Calculate the new size of the builder after appending. | 264 // Calculate the new size of the builder after appending. |
| 213 unsigned requiredLength = length + m_length; | 265 unsigned requiredLength = length + m_length; |
| 214 RELEASE_ASSERT(requiredLength >= length); | 266 RELEASE_ASSERT(requiredLength >= length); |
| 215 | 267 |
| 216 if ((m_buffer) && (requiredLength <= m_buffer->length())) { | |
| 217 // If the buffer is valid it must be at least as long as the current bui
lder contents! | |
| 218 ASSERT(m_buffer->length() >= m_length); | |
| 219 unsigned currentLength = m_length; | |
| 220 m_string = String(); | |
| 221 m_length = requiredLength; | |
| 222 return getBufferCharacters<CharType>() + currentLength; | |
| 223 } | |
| 224 | |
| 225 return appendUninitializedSlow<CharType>(requiredLength); | |
| 226 } | |
| 227 | |
| 228 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, | |
| 229 // return a pointer to the newly allocated storage. | |
| 230 template <typename CharType> | |
| 231 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) | |
| 232 { | |
| 233 ASSERT(requiredLength); | |
| 234 | |
| 235 if (m_buffer) { | 268 if (m_buffer) { |
| 236 // If the buffer is valid it must be at least as long as the current bui
lder contents! | 269 // If the buffer is valid it must be at least as long as the current build
er contents! |
| 237 ASSERT(m_buffer->length() >= m_length); | 270 ASSERT(m_buffer->length() >= m_length); |
| 238 | 271 |
| 239 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength))
; | 272 allocateBufferUpConvert(m_buffer->characters8(), |
| 273 expandedCapacity(capacity(), requiredLength)); |
| 240 } else { | 274 } else { |
| 241 ASSERT(m_string.length() == m_length); | 275 ASSERT(m_string.length() == m_length); |
| 242 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expand
edCapacity(capacity(), requiredLength)); | 276 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), |
| 243 } | 277 expandedCapacity(capacity(), requiredLength)); |
| 244 | 278 } |
| 245 CharType* result = getBufferCharacters<CharType>() + m_length; | 279 |
| 280 memcpy(m_bufferCharacters16 + m_length, characters, |
| 281 static_cast<size_t>(length) * sizeof(UChar)); |
| 246 m_length = requiredLength; | 282 m_length = requiredLength; |
| 247 return result; | 283 } else { |
| 248 } | 284 memcpy(appendUninitialized<UChar>(length), characters, |
| 249 | 285 static_cast<size_t>(length) * sizeof(UChar)); |
| 250 void StringBuilder::append(const UChar* characters, unsigned length) | 286 } |
| 251 { | 287 } |
| 252 if (!length) | 288 |
| 253 return; | 289 void StringBuilder::append(const LChar* characters, unsigned length) { |
| 254 | 290 if (!length) |
| 255 ASSERT(characters); | 291 return; |
| 256 | 292 ASSERT(characters); |
| 257 if (m_is8Bit) { | 293 |
| 258 if (length == 1 && !(*characters & ~0xff)) { | 294 if (m_is8Bit) { |
| 259 // Append as 8 bit character | 295 LChar* dest = appendUninitialized<LChar>(length); |
| 260 LChar lChar = static_cast<LChar>(*characters); | 296 if (length > 8) { |
| 261 append(&lChar, 1); | 297 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar)); |
| 262 return; | |
| 263 } | |
| 264 | |
| 265 // Calculate the new size of the builder after appending. | |
| 266 unsigned requiredLength = length + m_length; | |
| 267 RELEASE_ASSERT(requiredLength >= length); | |
| 268 | |
| 269 if (m_buffer) { | |
| 270 // If the buffer is valid it must be at least as long as the current
builder contents! | |
| 271 ASSERT(m_buffer->length() >= m_length); | |
| 272 | |
| 273 allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(ca
pacity(), requiredLength)); | |
| 274 } else { | |
| 275 ASSERT(m_string.length() == m_length); | |
| 276 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8
(), expandedCapacity(capacity(), requiredLength)); | |
| 277 } | |
| 278 | |
| 279 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(
length) * sizeof(UChar)); | |
| 280 m_length = requiredLength; | |
| 281 } else { | 298 } else { |
| 282 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_
t>(length) * sizeof(UChar)); | 299 const LChar* end = characters + length; |
| 283 } | 300 while (characters < end) |
| 284 } | 301 *(dest++) = *(characters++); |
| 285 | 302 } |
| 286 void StringBuilder::append(const LChar* characters, unsigned length) | 303 } else { |
| 287 { | 304 UChar* dest = appendUninitialized<UChar>(length); |
| 288 if (!length) | 305 const LChar* end = characters + length; |
| 289 return; | 306 while (characters < end) |
| 290 ASSERT(characters); | 307 *(dest++) = *(characters++); |
| 291 | 308 } |
| 292 if (m_is8Bit) { | 309 } |
| 293 LChar* dest = appendUninitialized<LChar>(length); | 310 |
| 294 if (length > 8) { | 311 void StringBuilder::appendNumber(int number) { |
| 295 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar)
); | 312 numberToStringSigned<StringBuilder>(number, this); |
| 296 } else { | 313 } |
| 297 const LChar* end = characters + length; | 314 |
| 298 while (characters < end) | 315 void StringBuilder::appendNumber(unsigned number) { |
| 299 *(dest++) = *(characters++); | 316 numberToStringUnsigned<StringBuilder>(number, this); |
| 300 } | 317 } |
| 301 } else { | 318 |
| 302 UChar* dest = appendUninitialized<UChar>(length); | 319 void StringBuilder::appendNumber(long number) { |
| 303 const LChar* end = characters + length; | 320 numberToStringSigned<StringBuilder>(number, this); |
| 304 while (characters < end) | 321 } |
| 305 *(dest++) = *(characters++); | 322 |
| 306 } | 323 void StringBuilder::appendNumber(unsigned long number) { |
| 307 } | 324 numberToStringUnsigned<StringBuilder>(number, this); |
| 308 | 325 } |
| 309 void StringBuilder::appendNumber(int number) | 326 |
| 310 { | 327 void StringBuilder::appendNumber(long long number) { |
| 311 numberToStringSigned<StringBuilder>(number, this); | 328 numberToStringSigned<StringBuilder>(number, this); |
| 312 } | 329 } |
| 313 | 330 |
| 314 void StringBuilder::appendNumber(unsigned number) | 331 void StringBuilder::appendNumber(unsigned long long number) { |
| 315 { | 332 numberToStringUnsigned<StringBuilder>(number, this); |
| 316 numberToStringUnsigned<StringBuilder>(number, this); | 333 } |
| 317 } | 334 |
| 318 | 335 static void expandLCharToUCharInplace(UChar* buffer, size_t length) { |
| 319 void StringBuilder::appendNumber(long number) | 336 const LChar* sourceEnd = reinterpret_cast<LChar*>(buffer) + length; |
| 320 { | 337 UChar* current = buffer + length; |
| 321 numberToStringSigned<StringBuilder>(number, this); | 338 while (current != buffer) |
| 322 } | 339 *--current = *--sourceEnd; |
| 323 | 340 } |
| 324 void StringBuilder::appendNumber(unsigned long number) | 341 |
| 325 { | 342 void StringBuilder::appendNumber( |
| 326 numberToStringUnsigned<StringBuilder>(number, this); | 343 double number, |
| 327 } | 344 unsigned precision, |
| 328 | 345 TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy) { |
| 329 void StringBuilder::appendNumber(long long number) | 346 bool truncateTrailingZeros = |
| 330 { | 347 trailingZerosTruncatingPolicy == TruncateTrailingZeros; |
| 331 numberToStringSigned<StringBuilder>(number, this); | 348 size_t numberLength; |
| 332 } | 349 if (m_is8Bit) { |
| 333 | 350 LChar* dest = appendUninitialized<LChar>(NumberToStringBufferLength); |
| 334 void StringBuilder::appendNumber(unsigned long long number) | 351 const char* result = numberToFixedPrecisionString( |
| 335 { | 352 number, precision, reinterpret_cast<char*>(dest), |
| 336 numberToStringUnsigned<StringBuilder>(number, this); | 353 truncateTrailingZeros); |
| 337 } | 354 numberLength = strlen(result); |
| 338 | 355 } else { |
| 339 static void expandLCharToUCharInplace(UChar* buffer, size_t length) | 356 UChar* dest = appendUninitialized<UChar>(NumberToStringBufferLength); |
| 340 { | 357 const char* result = numberToFixedPrecisionString( |
| 341 const LChar* sourceEnd = reinterpret_cast<LChar*>(buffer) + length; | 358 number, precision, reinterpret_cast<char*>(dest), |
| 342 UChar* current = buffer + length; | 359 truncateTrailingZeros); |
| 343 while (current != buffer) | 360 numberLength = strlen(result); |
| 344 *--current = *--sourceEnd; | 361 expandLCharToUCharInplace(dest, numberLength); |
| 345 } | 362 } |
| 346 | 363 ASSERT(m_length >= NumberToStringBufferLength); |
| 347 void StringBuilder::appendNumber(double number, unsigned precision, TrailingZero
sTruncatingPolicy trailingZerosTruncatingPolicy) | 364 // Remove what appendUninitialized added. |
| 348 { | 365 m_length -= NumberToStringBufferLength; |
| 349 bool truncateTrailingZeros = trailingZerosTruncatingPolicy == TruncateTraili
ngZeros; | 366 ASSERT(numberLength <= NumberToStringBufferLength); |
| 350 size_t numberLength; | 367 m_length += numberLength; |
| 351 if (m_is8Bit) { | 368 } |
| 352 LChar* dest = appendUninitialized<LChar>(NumberToStringBufferLength); | 369 |
| 353 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); | 370 bool StringBuilder::canShrink() const { |
| 354 numberLength = strlen(result); | 371 // Only shrink the buffer if it's less than 80% full. Need to tune this heuris
tic! |
| 355 } else { | 372 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); |
| 356 UChar* dest = appendUninitialized<UChar>(NumberToStringBufferLength); | 373 } |
| 357 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); | 374 |
| 358 numberLength = strlen(result); | 375 void StringBuilder::shrinkToFit() { |
| 359 expandLCharToUCharInplace(dest, numberLength); | 376 if (!canShrink()) |
| 360 } | 377 return; |
| 361 ASSERT(m_length >= NumberToStringBufferLength); | 378 if (m_is8Bit) |
| 362 // Remove what appendUninitialized added. | 379 reallocateBuffer<LChar>(m_length); |
| 363 m_length -= NumberToStringBufferLength; | 380 else |
| 364 ASSERT(numberLength <= NumberToStringBufferLength); | 381 reallocateBuffer<UChar>(m_length); |
| 365 m_length += numberLength; | 382 m_string = m_buffer.release(); |
| 366 } | 383 } |
| 367 | 384 |
| 368 bool StringBuilder::canShrink() const | 385 } // namespace WTF |
| 369 { | |
| 370 // Only shrink the buffer if it's less than 80% full. Need to tune this heur
istic! | |
| 371 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); | |
| 372 } | |
| 373 | |
| 374 void StringBuilder::shrinkToFit() | |
| 375 { | |
| 376 if (!canShrink()) | |
| 377 return; | |
| 378 if (m_is8Bit) | |
| 379 reallocateBuffer<LChar>(m_length); | |
| 380 else | |
| 381 reallocateBuffer<UChar>(m_length); | |
| 382 m_string = m_buffer.release(); | |
| 383 } | |
| 384 | |
| 385 } // namespace WTF | |
| OLD | NEW |