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 24 matching lines...) Expand all Loading... |
35 | 35 |
36 static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength) | 36 static unsigned expandedCapacity(unsigned capacity, unsigned requiredLength) |
37 { | 37 { |
38 static const unsigned minimumCapacity = 16; | 38 static const unsigned minimumCapacity = 16; |
39 return std::max(requiredLength, std::max(minimumCapacity, capacity * 2)); | 39 return std::max(requiredLength, std::max(minimumCapacity, capacity * 2)); |
40 } | 40 } |
41 | 41 |
42 void StringBuilder::reifyString() | 42 void StringBuilder::reifyString() |
43 { | 43 { |
44 if (!m_string.isNull()) { | 44 if (!m_string.isNull()) { |
45 ASSERT(m_string.length() == m_length); | 45 DCHECK_EQ(m_string.length(), m_length); |
46 return; | 46 return; |
47 } | 47 } |
48 | 48 |
49 if (!m_length) { | 49 if (!m_length) { |
50 m_string = StringImpl::empty(); | 50 m_string = StringImpl::empty(); |
51 return; | 51 return; |
52 } | 52 } |
53 | 53 |
54 ASSERT(m_buffer && m_length <= m_buffer->length()); | 54 DCHECK(m_buffer); |
| 55 DCHECK_LE(m_length, m_buffer->length()); |
55 if (m_length == m_buffer->length()) { | 56 if (m_length == m_buffer->length()) { |
56 m_string = m_buffer.release(); | 57 m_string = m_buffer.release(); |
57 return; | 58 return; |
58 } | 59 } |
59 | 60 |
60 m_string = m_buffer->substring(0, m_length); | 61 m_string = m_buffer->substring(0, m_length); |
61 } | 62 } |
62 | 63 |
63 String StringBuilder::reifySubstring(unsigned position, unsigned length) const | 64 String StringBuilder::reifySubstring(unsigned position, unsigned length) const |
64 { | 65 { |
65 ASSERT(m_string.isNull()); | 66 DCHECK(m_string.isNull()); |
66 ASSERT(m_buffer); | 67 DCHECK(m_buffer); |
67 unsigned substringLength = std::min(length, m_length - position); | 68 unsigned substringLength = std::min(length, m_length - position); |
68 return m_buffer->substring(position, substringLength); | 69 return m_buffer->substring(position, substringLength); |
69 } | 70 } |
70 | 71 |
71 void StringBuilder::resize(unsigned newSize) | 72 void StringBuilder::resize(unsigned newSize) |
72 { | 73 { |
73 // Check newSize < m_length, hence m_length > 0. | 74 // Check newSize < m_length, hence m_length > 0. |
74 ASSERT(newSize <= m_length); | 75 DCHECK_LE(newSize, m_length); |
75 if (newSize == m_length) | 76 if (newSize == m_length) |
76 return; | 77 return; |
77 ASSERT(m_length); | 78 DCHECK(m_length); |
78 | 79 |
79 // If there is a buffer, we only need to duplicate it if it has more than on
e ref. | 80 // If there is a buffer, we only need to duplicate it if it has more than on
e ref. |
80 if (m_buffer) { | 81 if (m_buffer) { |
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. | 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. |
82 if (!m_buffer->hasOneRef()) { | 83 if (!m_buffer->hasOneRef()) { |
83 if (m_buffer->is8Bit()) | 84 if (m_buffer->is8Bit()) |
84 allocateBuffer(m_buffer->characters8(), m_buffer->length()); | 85 allocateBuffer(m_buffer->characters8(), m_buffer->length()); |
85 else | 86 else |
86 allocateBuffer(m_buffer->characters16(), m_buffer->length()); | 87 allocateBuffer(m_buffer->characters16(), m_buffer->length()); |
87 } | 88 } |
88 m_length = newSize; | 89 m_length = newSize; |
89 return; | 90 return; |
90 } | 91 } |
91 | 92 |
92 // Since m_length && !m_buffer, the string must be valid in m_string, and m_
string.length() > 0. | 93 // Since m_length && !m_buffer, the string must be valid in m_string, and m_
string.length() > 0. |
93 ASSERT(!m_string.isEmpty()); | 94 DCHECK(!m_string.isEmpty()); |
94 ASSERT(m_length == m_string.length()); | 95 DCHECK_EQ(m_length, m_string.length()); |
95 ASSERT(newSize < m_string.length()); | 96 DCHECK_LT(newSize, m_string.length()); |
96 m_length = newSize; | 97 m_length = newSize; |
97 RefPtr<StringImpl> string = m_string.releaseImpl(); | 98 RefPtr<StringImpl> string = m_string.releaseImpl(); |
98 if (string->hasOneRef()) { | 99 if (string->hasOneRef()) { |
99 // If we're the only ones with a reference to the string, we can | 100 // If we're the only ones with a reference to the string, we can |
100 // re-purpose the string as m_buffer and continue mutating it. | 101 // re-purpose the string as m_buffer and continue mutating it. |
101 m_buffer = string; | 102 m_buffer = string; |
102 } else { | 103 } else { |
103 // Otherwise, we need to make a copy of the string so that we don't | 104 // Otherwise, we need to make a copy of the string so that we don't |
104 // mutate a String that's held elsewhere. | 105 // mutate a String that's held elsewhere. |
105 m_buffer = string->substring(0, m_length); | 106 m_buffer = string->substring(0, m_length); |
106 } | 107 } |
107 } | 108 } |
108 | 109 |
109 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come fro
m either m_string | 110 // 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). | 111 // or m_buffer, neither will be reassigned until the copy has completed). |
111 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ
iredLength) | 112 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ
iredLength) |
112 { | 113 { |
113 ASSERT(m_is8Bit); | 114 DCHECK(m_is8Bit); |
114 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 115 // 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); | 116 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters8); |
116 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length)
* sizeof(LChar)); // This can't overflow. | 117 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length)
* sizeof(LChar)); // This can't overflow. |
117 | 118 |
118 // Update the builder state. | 119 // Update the builder state. |
119 m_buffer = buffer.release(); | 120 m_buffer = buffer.release(); |
120 m_string = String(); | 121 m_string = String(); |
121 } | 122 } |
122 | 123 |
123 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come fr
om either m_string | 124 // 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). | 125 // or m_buffer, neither will be reassigned until the copy has completed). |
125 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ
iredLength) | 126 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ
iredLength) |
126 { | 127 { |
127 ASSERT(!m_is8Bit); | 128 DCHECK(!m_is8Bit); |
128 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 129 // 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); | 130 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); |
130 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length
) * sizeof(UChar)); // This can't overflow. | 131 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length
) * sizeof(UChar)); // This can't overflow. |
131 | 132 |
132 // Update the builder state. | 133 // Update the builder state. |
133 m_buffer = buffer.release(); | 134 m_buffer = buffer.release(); |
134 m_string = String(); | 135 m_string = String(); |
135 } | 136 } |
136 | 137 |
137 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit an
d may come | 138 // 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). | 139 // 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) | 140 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsi
gned requiredLength) |
140 { | 141 { |
141 ASSERT(m_is8Bit); | 142 DCHECK(m_is8Bit); |
142 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | 143 // 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); | 144 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); |
144 for (unsigned i = 0; i < m_length; ++i) | 145 for (unsigned i = 0; i < m_length; ++i) |
145 m_bufferCharacters16[i] = currentCharacters[i]; | 146 m_bufferCharacters16[i] = currentCharacters[i]; |
146 | 147 |
147 m_is8Bit = false; | 148 m_is8Bit = false; |
148 | 149 |
149 // Update the builder state. | 150 // Update the builder state. |
150 m_buffer = buffer.release(); | 151 m_buffer = buffer.release(); |
151 m_string = String(); | 152 m_string = String(); |
152 } | 153 } |
153 | 154 |
154 template <> | 155 template <> |
155 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) | 156 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) |
156 { | 157 { |
157 // If the buffer has only one ref (by this StringBuilder), reallocate it, | 158 // If the buffer has only one ref (by this StringBuilder), reallocate it, |
158 // otherwise fall back to "allocate and copy" method. | 159 // otherwise fall back to "allocate and copy" method. |
159 m_string = String(); | 160 m_string = String(); |
160 | 161 |
161 ASSERT(m_is8Bit); | 162 DCHECK(m_is8Bit); |
162 ASSERT(m_buffer->is8Bit()); | 163 DCHECK(m_buffer->is8Bit()); |
163 | 164 |
164 allocateBuffer(m_buffer->characters8(), requiredLength); | 165 allocateBuffer(m_buffer->characters8(), requiredLength); |
165 } | 166 } |
166 | 167 |
167 template <> | 168 template <> |
168 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) | 169 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) |
169 { | 170 { |
170 // If the buffer has only one ref (by this StringBuilder), reallocate it, | 171 // If the buffer has only one ref (by this StringBuilder), reallocate it, |
171 // otherwise fall back to "allocate and copy" method. | 172 // otherwise fall back to "allocate and copy" method. |
172 m_string = String(); | 173 m_string = String(); |
(...skipping 27 matching lines...) Expand all Loading... |
200 } | 201 } |
201 } | 202 } |
202 } | 203 } |
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 { |
210 ASSERT(length); | 211 DCHECK(length); |
211 | 212 |
212 // Calculate the new size of the builder after appending. | 213 // Calculate the new size of the builder after appending. |
213 unsigned requiredLength = length + m_length; | 214 unsigned requiredLength = length + m_length; |
214 RELEASE_ASSERT(requiredLength >= length); | 215 CHECK_GE(requiredLength, length); |
215 | 216 |
216 if ((m_buffer) && (requiredLength <= m_buffer->length())) { | 217 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 // 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 DCHECK_GE(m_buffer->length(), m_length); |
219 unsigned currentLength = m_length; | 220 unsigned currentLength = m_length; |
220 m_string = String(); | 221 m_string = String(); |
221 m_length = requiredLength; | 222 m_length = requiredLength; |
222 return getBufferCharacters<CharType>() + currentLength; | 223 return getBufferCharacters<CharType>() + currentLength; |
223 } | 224 } |
224 | 225 |
225 return appendUninitializedSlow<CharType>(requiredLength); | 226 return appendUninitializedSlow<CharType>(requiredLength); |
226 } | 227 } |
227 | 228 |
228 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, | 229 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, |
229 // return a pointer to the newly allocated storage. | 230 // return a pointer to the newly allocated storage. |
230 template <typename CharType> | 231 template <typename CharType> |
231 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) | 232 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) |
232 { | 233 { |
233 ASSERT(requiredLength); | 234 DCHECK(requiredLength); |
234 | 235 |
235 if (m_buffer) { | 236 if (m_buffer) { |
236 // If the buffer is valid it must be at least as long as the current bui
lder contents! | 237 // If the buffer is valid it must be at least as long as the current bui
lder contents! |
237 ASSERT(m_buffer->length() >= m_length); | 238 DCHECK_GE(m_buffer->length(), m_length); |
238 | 239 |
239 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength))
; | 240 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength))
; |
240 } else { | 241 } else { |
241 ASSERT(m_string.length() == m_length); | 242 DCHECK_EQ(m_string.length(), m_length); |
242 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expand
edCapacity(capacity(), requiredLength)); | 243 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expand
edCapacity(capacity(), requiredLength)); |
243 } | 244 } |
244 | 245 |
245 CharType* result = getBufferCharacters<CharType>() + m_length; | 246 CharType* result = getBufferCharacters<CharType>() + m_length; |
246 m_length = requiredLength; | 247 m_length = requiredLength; |
247 return result; | 248 return result; |
248 } | 249 } |
249 | 250 |
250 void StringBuilder::append(const UChar* characters, unsigned length) | 251 void StringBuilder::append(const UChar* characters, unsigned length) |
251 { | 252 { |
252 if (!length) | 253 if (!length) |
253 return; | 254 return; |
254 | 255 |
255 ASSERT(characters); | 256 DCHECK(characters); |
256 | 257 |
257 if (m_is8Bit) { | 258 if (m_is8Bit) { |
258 if (length == 1 && !(*characters & ~0xff)) { | 259 if (length == 1 && !(*characters & ~0xff)) { |
259 // Append as 8 bit character | 260 // Append as 8 bit character |
260 LChar lChar = static_cast<LChar>(*characters); | 261 LChar lChar = static_cast<LChar>(*characters); |
261 append(&lChar, 1); | 262 append(&lChar, 1); |
262 return; | 263 return; |
263 } | 264 } |
264 | 265 |
265 // Calculate the new size of the builder after appending. | 266 // Calculate the new size of the builder after appending. |
266 unsigned requiredLength = length + m_length; | 267 unsigned requiredLength = length + m_length; |
267 RELEASE_ASSERT(requiredLength >= length); | 268 CHECK_GE(requiredLength, length); |
268 | 269 |
269 if (m_buffer) { | 270 if (m_buffer) { |
270 // If the buffer is valid it must be at least as long as the current
builder contents! | 271 // 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 DCHECK_GE(m_buffer->length(), m_length); |
272 | 273 |
273 allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(ca
pacity(), requiredLength)); | 274 allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(ca
pacity(), requiredLength)); |
274 } else { | 275 } else { |
275 ASSERT(m_string.length() == m_length); | 276 DCHECK_EQ(m_string.length(), m_length); |
276 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8
(), expandedCapacity(capacity(), requiredLength)); | 277 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8
(), expandedCapacity(capacity(), requiredLength)); |
277 } | 278 } |
278 | 279 |
279 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(
length) * sizeof(UChar)); | 280 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(
length) * sizeof(UChar)); |
280 m_length = requiredLength; | 281 m_length = requiredLength; |
281 } else { | 282 } else { |
282 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_
t>(length) * sizeof(UChar)); | 283 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_
t>(length) * sizeof(UChar)); |
283 } | 284 } |
284 } | 285 } |
285 | 286 |
286 void StringBuilder::append(const LChar* characters, unsigned length) | 287 void StringBuilder::append(const LChar* characters, unsigned length) |
287 { | 288 { |
288 if (!length) | 289 if (!length) |
289 return; | 290 return; |
290 ASSERT(characters); | 291 DCHECK(characters); |
291 | 292 |
292 if (m_is8Bit) { | 293 if (m_is8Bit) { |
293 LChar* dest = appendUninitialized<LChar>(length); | 294 LChar* dest = appendUninitialized<LChar>(length); |
294 if (length > 8) { | 295 if (length > 8) { |
295 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar)
); | 296 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar)
); |
296 } else { | 297 } else { |
297 const LChar* end = characters + length; | 298 const LChar* end = characters + length; |
298 while (characters < end) | 299 while (characters < end) |
299 *(dest++) = *(characters++); | 300 *(dest++) = *(characters++); |
300 } | 301 } |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 if (m_is8Bit) { | 359 if (m_is8Bit) { |
359 LChar* dest = appendUninitialized<LChar>(NumberToStringBufferLength); | 360 LChar* dest = appendUninitialized<LChar>(NumberToStringBufferLength); |
360 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); | 361 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); |
361 numberLength = strlen(result); | 362 numberLength = strlen(result); |
362 } else { | 363 } else { |
363 UChar* dest = appendUninitialized<UChar>(NumberToStringBufferLength); | 364 UChar* dest = appendUninitialized<UChar>(NumberToStringBufferLength); |
364 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); | 365 const char* result = numberToFixedPrecisionString(number, precision, rei
nterpret_cast<char*>(dest), truncateTrailingZeros); |
365 numberLength = strlen(result); | 366 numberLength = strlen(result); |
366 expandLCharToUCharInplace(dest, numberLength); | 367 expandLCharToUCharInplace(dest, numberLength); |
367 } | 368 } |
368 ASSERT(m_length >= NumberToStringBufferLength); | 369 DCHECK_GE(m_length, NumberToStringBufferLength); |
369 // Remove what appendUninitialized added. | 370 // Remove what appendUninitialized added. |
370 m_length -= NumberToStringBufferLength; | 371 m_length -= NumberToStringBufferLength; |
371 ASSERT(numberLength <= NumberToStringBufferLength); | 372 DCHECK_LE(numberLength, NumberToStringBufferLength); |
372 m_length += numberLength; | 373 m_length += numberLength; |
373 } | 374 } |
374 | 375 |
375 bool StringBuilder::canShrink() const | 376 bool StringBuilder::canShrink() const |
376 { | 377 { |
377 // Only shrink the buffer if it's less than 80% full. Need to tune this heur
istic! | 378 // Only shrink the buffer if it's less than 80% full. Need to tune this heur
istic! |
378 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); | 379 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); |
379 } | 380 } |
380 | 381 |
381 void StringBuilder::shrinkToFit() | 382 void StringBuilder::shrinkToFit() |
382 { | 383 { |
383 if (!canShrink()) | 384 if (!canShrink()) |
384 return; | 385 return; |
385 if (m_is8Bit) | 386 if (m_is8Bit) |
386 reallocateBuffer<LChar>(m_length); | 387 reallocateBuffer<LChar>(m_length); |
387 else | 388 else |
388 reallocateBuffer<UChar>(m_length); | 389 reallocateBuffer<UChar>(m_length); |
389 m_string = m_buffer.release(); | 390 m_string = m_buffer.release(); |
390 } | 391 } |
391 | 392 |
392 } // namespace WTF | 393 } // namespace WTF |
OLD | NEW |