Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(677)

Side by Side Diff: third_party/WebKit/Source/wtf/text/StringBuilder.cpp

Issue 2046353002: Use a Vector for the buffer in StringBuilder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698