2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "StringBuilder.h"
30 #include "IntegerToStringConversion.h"
31 #include "WTFString.h"
36 static unsigned expandedCapacity(unsigned capacity
, unsigned requiredLength
)
38 static const unsigned minimumCapacity
= 16;
39 return std::max(requiredLength
, std::max(minimumCapacity
, capacity
* 2));
42 void StringBuilder::reifyString()
44 if (!m_string
.isNull()) {
45 ASSERT(m_string
.length() == m_length
);
50 m_string
= StringImpl::empty();
54 ASSERT(m_buffer
&& m_length
<= m_buffer
->length());
55 if (m_length
== m_buffer
->length()) {
56 m_string
= m_buffer
.release();
60 if (m_buffer
->hasOneRef()) {
61 m_buffer
->truncateAssumingIsolated(m_length
);
62 m_string
= m_buffer
.release();
66 m_string
= m_buffer
->substring(0, m_length
);
69 String
StringBuilder::reifySubstring(unsigned position
, unsigned length
) const
71 ASSERT(m_string
.isNull());
73 unsigned substringLength
= std::min(length
, m_length
- position
);
74 return m_buffer
->substring(position
, substringLength
);
77 void StringBuilder::resize(unsigned newSize
)
79 // Check newSize < m_length, hence m_length > 0.
80 ASSERT(newSize
<= m_length
);
81 if (newSize
== m_length
)
85 // If there is a buffer, we only need to duplicate it if it has more than one ref.
87 m_string
= String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
88 if (!m_buffer
->hasOneRef()) {
89 if (m_buffer
->is8Bit())
90 allocateBuffer(m_buffer
->characters8(), m_buffer
->length());
92 allocateBuffer(m_buffer
->characters16(), m_buffer
->length());
98 // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
99 ASSERT(!m_string
.isEmpty());
100 ASSERT(m_length
== m_string
.length());
101 ASSERT(newSize
< m_string
.length());
103 RefPtr
<StringImpl
> string
= m_string
.releaseImpl();
104 if (string
->hasOneRef()) {
105 // If we're the only ones with a reference to the string, we can
106 // re-purpose the string as m_buffer and continue mutating it.
109 // Otherwise, we need to make a copy of the string so that we don't
110 // mutate a String that's held elsewhere.
111 m_buffer
= string
->substring(0, m_length
);
115 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come from either m_string
116 // or m_buffer, neither will be reassigned until the copy has completed).
117 void StringBuilder::allocateBuffer(const LChar
* currentCharacters
, unsigned requiredLength
)
120 // Copy the existing data into a new buffer, set result to point to the end of the existing data.
121 RefPtr
<StringImpl
> buffer
= StringImpl::createUninitialized(requiredLength
, m_bufferCharacters8
);
122 memcpy(m_bufferCharacters8
, currentCharacters
, static_cast<size_t>(m_length
) * sizeof(LChar
)); // This can't overflow.
124 // Update the builder state.
125 m_buffer
= buffer
.release();
129 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come from either m_string
130 // or m_buffer, neither will be reassigned until the copy has completed).
131 void StringBuilder::allocateBuffer(const UChar
* currentCharacters
, unsigned requiredLength
)
134 // Copy the existing data into a new buffer, set result to point to the end of the existing data.
135 RefPtr
<StringImpl
> buffer
= StringImpl::createUninitialized(requiredLength
, m_bufferCharacters16
);
136 memcpy(m_bufferCharacters16
, currentCharacters
, static_cast<size_t>(m_length
) * sizeof(UChar
)); // This can't overflow.
138 // Update the builder state.
139 m_buffer
= buffer
.release();
143 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come
144 // from either m_string or m_buffer, neither will be reassigned until the copy has completed).
145 void StringBuilder::allocateBufferUpConvert(const LChar
* currentCharacters
, unsigned requiredLength
)
148 // Copy the existing data into a new buffer, set result to point to the end of the existing data.
149 RefPtr
<StringImpl
> buffer
= StringImpl::createUninitialized(requiredLength
, m_bufferCharacters16
);
150 for (unsigned i
= 0; i
< m_length
; ++i
)
151 m_bufferCharacters16
[i
] = currentCharacters
[i
];
155 // Update the builder state.
156 m_buffer
= buffer
.release();
161 void StringBuilder::reallocateBuffer
<LChar
>(unsigned requiredLength
)
163 // If the buffer has only one ref (by this StringBuilder), reallocate it,
164 // otherwise fall back to "allocate and copy" method.
168 ASSERT(m_buffer
->is8Bit());
170 if (m_buffer
->hasOneRef()) {
171 m_buffer
= StringImpl::reallocate(m_buffer
.release(), requiredLength
);
172 m_bufferCharacters8
= const_cast<LChar
*>(m_buffer
->characters8());
174 allocateBuffer(m_buffer
->characters8(), requiredLength
);
178 void StringBuilder::reallocateBuffer
<UChar
>(unsigned requiredLength
)
180 // If the buffer has only one ref (by this StringBuilder), reallocate it,
181 // otherwise fall back to "allocate and copy" method.
184 if (m_buffer
->is8Bit()) {
185 allocateBufferUpConvert(m_buffer
->characters8(), requiredLength
);
186 } else if (m_buffer
->hasOneRef()) {
187 m_buffer
= StringImpl::reallocate(m_buffer
.release(), requiredLength
);
188 m_bufferCharacters16
= const_cast<UChar
*>(m_buffer
->characters16());
190 allocateBuffer(m_buffer
->characters16(), requiredLength
);
193 void StringBuilder::reserveCapacity(unsigned newCapacity
)
196 // If there is already a buffer, then grow if necessary.
197 if (newCapacity
> m_buffer
->length()) {
198 if (m_buffer
->is8Bit())
199 reallocateBuffer
<LChar
>(newCapacity
);
201 reallocateBuffer
<UChar
>(newCapacity
);
204 // Grow the string, if necessary.
205 if (newCapacity
> m_length
) {
207 LChar
* nullPlaceholder
= 0;
208 allocateBuffer(nullPlaceholder
, newCapacity
);
209 } else if (m_string
.is8Bit())
210 allocateBuffer(m_string
.characters8(), newCapacity
);
212 allocateBuffer(m_string
.characters16(), newCapacity
);
217 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
218 // return a pointer to the newly allocated storage.
219 template <typename CharType
>
220 ALWAYS_INLINE CharType
* StringBuilder::appendUninitialized(unsigned length
)
224 // Calculate the new size of the builder after appending.
225 unsigned requiredLength
= length
+ m_length
;
226 RELEASE_ASSERT(requiredLength
>= length
);
228 if ((m_buffer
) && (requiredLength
<= m_buffer
->length())) {
229 // If the buffer is valid it must be at least as long as the current builder contents!
230 ASSERT(m_buffer
->length() >= m_length
);
231 unsigned currentLength
= m_length
;
233 m_length
= requiredLength
;
234 return getBufferCharacters
<CharType
>() + currentLength
;
237 return appendUninitializedSlow
<CharType
>(requiredLength
);
240 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
241 // return a pointer to the newly allocated storage.
242 template <typename CharType
>
243 CharType
* StringBuilder::appendUninitializedSlow(unsigned requiredLength
)
245 ASSERT(requiredLength
);
248 // If the buffer is valid it must be at least as long as the current builder contents!
249 ASSERT(m_buffer
->length() >= m_length
);
251 reallocateBuffer
<CharType
>(expandedCapacity(capacity(), requiredLength
));
253 ASSERT(m_string
.length() == m_length
);
254 allocateBuffer(m_length
? m_string
.getCharacters
<CharType
>() : 0, expandedCapacity(capacity(), requiredLength
));
257 CharType
* result
= getBufferCharacters
<CharType
>() + m_length
;
258 m_length
= requiredLength
;
262 void StringBuilder::append(const UChar
* characters
, unsigned length
)
270 if (length
== 1 && !(*characters
& ~0xff)) {
271 // Append as 8 bit character
272 LChar lChar
= static_cast<LChar
>(*characters
);
277 // Calculate the new size of the builder after appending.
278 unsigned requiredLength
= length
+ m_length
;
279 RELEASE_ASSERT(requiredLength
>= length
);
282 // If the buffer is valid it must be at least as long as the current builder contents!
283 ASSERT(m_buffer
->length() >= m_length
);
285 allocateBufferUpConvert(m_buffer
->characters8(), expandedCapacity(capacity(), requiredLength
));
287 ASSERT(m_string
.length() == m_length
);
288 allocateBufferUpConvert(m_string
.isNull() ? 0 : m_string
.characters8(), expandedCapacity(capacity(), requiredLength
));
291 memcpy(m_bufferCharacters16
+ m_length
, characters
, static_cast<size_t>(length
) * sizeof(UChar
));
292 m_length
= requiredLength
;
294 memcpy(appendUninitialized
<UChar
>(length
), characters
, static_cast<size_t>(length
) * sizeof(UChar
));
297 void StringBuilder::append(const LChar
* characters
, unsigned length
)
304 LChar
* dest
= appendUninitialized
<LChar
>(length
);
306 memcpy(dest
, characters
, static_cast<size_t>(length
) * sizeof(LChar
));
308 const LChar
* end
= characters
+ length
;
309 while (characters
< end
)
310 *(dest
++) = *(characters
++);
313 UChar
* dest
= appendUninitialized
<UChar
>(length
);
314 const LChar
* end
= characters
+ length
;
315 while (characters
< end
)
316 *(dest
++) = *(characters
++);
320 void StringBuilder::appendNumber(int number
)
322 numberToStringSigned
<StringBuilder
>(number
, this);
325 void StringBuilder::appendNumber(unsigned number
)
327 numberToStringUnsigned
<StringBuilder
>(number
, this);
330 void StringBuilder::appendNumber(long number
)
332 numberToStringSigned
<StringBuilder
>(number
, this);
335 void StringBuilder::appendNumber(unsigned long number
)
337 numberToStringUnsigned
<StringBuilder
>(number
, this);
340 void StringBuilder::appendNumber(long long number
)
342 numberToStringSigned
<StringBuilder
>(number
, this);
345 void StringBuilder::appendNumber(unsigned long long number
)
347 numberToStringUnsigned
<StringBuilder
>(number
, this);
350 static void expandLCharToUCharInplace(UChar
* buffer
, size_t length
)
352 const LChar
* sourceEnd
= reinterpret_cast<LChar
*>(buffer
) + length
;
353 UChar
* current
= buffer
+ length
;
354 while (current
!= buffer
)
355 *--current
= *--sourceEnd
;
358 void StringBuilder::appendNumber(double number
, unsigned precision
, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy
)
360 bool truncateTrailingZeros
= trailingZerosTruncatingPolicy
== TruncateTrailingZeros
;
363 LChar
* dest
= appendUninitialized
<LChar
>(NumberToStringBufferLength
);
364 const char* result
= numberToFixedPrecisionString(number
, precision
, reinterpret_cast<char*>(dest
), truncateTrailingZeros
);
365 numberLength
= strlen(result
);
367 UChar
* dest
= appendUninitialized
<UChar
>(NumberToStringBufferLength
);
368 const char* result
= numberToFixedPrecisionString(number
, precision
, reinterpret_cast<char*>(dest
), truncateTrailingZeros
);
369 numberLength
= strlen(result
);
370 expandLCharToUCharInplace(dest
, numberLength
);
372 ASSERT(m_length
>= NumberToStringBufferLength
);
373 // Remove what appendUninitialized added.
374 m_length
-= NumberToStringBufferLength
;
375 ASSERT(numberLength
<= NumberToStringBufferLength
);
376 m_length
+= numberLength
;
379 bool StringBuilder::canShrink() const
381 // Only shrink the buffer if it's less than 80% full. Need to tune this heuristic!
382 return m_buffer
&& m_buffer
->length() > (m_length
+ (m_length
>> 2));
385 void StringBuilder::shrinkToFit()
390 reallocateBuffer
<LChar
>(m_length
);
392 reallocateBuffer
<UChar
>(m_length
);
393 m_string
= m_buffer
.release();