2 * Copyright (C) 2010, 2013 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"
35 static size_t expandedCapacity(size_t capacity, size_t newLength)
37 static const size_t minimumCapacity = 16;
38 return std::max(capacity, std::max(minimumCapacity, newLength * 2));
41 void StringBuilder::reifyString() const
43 // Check if the string already exists.
44 if (!m_string.isNull()) {
45 ASSERT(m_string.length() == m_length);
51 m_string = StringImpl::empty();
55 // Must be valid in the buffer, take a substring (unless string fills the buffer).
56 ASSERT(m_buffer && m_length <= m_buffer->length());
57 m_string = (m_length == m_buffer->length())
59 : StringImpl::create(m_buffer, 0, m_length);
61 if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length)
62 m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length);
64 m_valid16BitShadowLength = m_length;
67 void StringBuilder::resize(unsigned newSize)
69 // Check newSize < m_length, hence m_length > 0.
70 ASSERT(newSize <= m_length);
71 if (newSize == m_length)
75 // If there is a buffer, we only need to duplicate it if it has more than one ref.
77 m_string = String(); // Clear the string to remove the reference to m_buffer if any before checking the reference count of m_buffer.
78 if (!m_buffer->hasOneRef()) {
79 if (m_buffer->is8Bit())
80 allocateBuffer(m_buffer->characters8(), m_buffer->length());
82 allocateBuffer(m_buffer->characters16(), m_buffer->length());
88 // Since m_length && !m_buffer, the string must be valid in m_string, and m_string.length() > 0.
89 ASSERT(!m_string.isEmpty());
90 ASSERT(m_length == m_string.length());
91 ASSERT(newSize < m_string.length());
93 m_string = StringImpl::create(m_string.impl(), 0, newSize);
96 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come from either m_string
97 // or m_buffer, neither will be reassigned until the copy has completed).
98 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requiredLength)
101 // Copy the existing data into a new buffer, set result to point to the end of the existing data.
102 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength, m_bufferCharacters8);
103 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length) * sizeof(LChar)); // This can't overflow.
105 // Update the builder state.
106 m_buffer = buffer.release();
110 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come from either m_string
111 // or m_buffer, neither will be reassigned until the copy has completed).
112 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requiredLength)
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_bufferCharacters16);
117 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length) * sizeof(UChar)); // This can't overflow.
119 // Update the builder state.
120 m_buffer = buffer.release();
124 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit and may come
125 // from either m_string or m_buffer, neither will be reassigned until the copy has completed).
126 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength)
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 for (unsigned i = 0; i < m_length; ++i)
132 m_bufferCharacters16[i] = currentCharacters[i];
136 // Update the builder state.
137 m_buffer = buffer.release();
142 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength)
144 // If the buffer has only one ref (by this StringBuilder), reallocate it,
145 // otherwise fall back to "allocate and copy" method.
149 ASSERT(m_buffer->is8Bit());
151 if (m_buffer->hasOneRef())
152 m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters8);
154 allocateBuffer(m_buffer->characters8(), requiredLength);
158 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength)
160 // If the buffer has only one ref (by this StringBuilder), reallocate it,
161 // otherwise fall back to "allocate and copy" method.
164 if (m_buffer->is8Bit())
165 allocateBufferUpConvert(m_buffer->characters8(), requiredLength);
166 else if (m_buffer->hasOneRef())
167 m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_bufferCharacters16);
169 allocateBuffer(m_buffer->characters16(), requiredLength);
172 void StringBuilder::reserveCapacity(unsigned newCapacity)
175 // If there is already a buffer, then grow if necessary.
176 if (newCapacity > m_buffer->length()) {
177 if (m_buffer->is8Bit())
178 reallocateBuffer<LChar>(newCapacity);
180 reallocateBuffer<UChar>(newCapacity);
183 // Grow the string, if necessary.
184 if (newCapacity > m_length) {
186 LChar* nullPlaceholder = 0;
187 allocateBuffer(nullPlaceholder, newCapacity);
188 } else if (m_string.is8Bit())
189 allocateBuffer(m_string.characters8(), newCapacity);
191 allocateBuffer(m_string.characters16(), newCapacity);
196 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
197 // return a pointer to the newly allocated storage.
198 template <typename CharType>
199 ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length)
203 // Calculate the new size of the builder after appending.
204 unsigned requiredLength = length + m_length;
205 if (requiredLength < length)
208 if ((m_buffer) && (requiredLength <= m_buffer->length())) {
209 // If the buffer is valid it must be at least as long as the current builder contents!
210 ASSERT(m_buffer->length() >= m_length);
211 unsigned currentLength = m_length;
213 m_length = requiredLength;
214 return getBufferCharacters<CharType>() + currentLength;
217 return appendUninitializedSlow<CharType>(requiredLength);
220 // Make 'length' additional capacity be available in m_buffer, update m_string & m_length,
221 // return a pointer to the newly allocated storage.
222 template <typename CharType>
223 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength)
225 ASSERT(requiredLength);
228 // If the buffer is valid it must be at least as long as the current builder contents!
229 ASSERT(m_buffer->length() >= m_length);
231 reallocateBuffer<CharType>(expandedCapacity(capacity(), requiredLength));
233 ASSERT(m_string.length() == m_length);
234 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, expandedCapacity(capacity(), requiredLength));
237 CharType* result = getBufferCharacters<CharType>() + m_length;
238 m_length = requiredLength;
242 void StringBuilder::append(const UChar* characters, unsigned length)
250 if (length == 1 && !(*characters & ~0xff)) {
251 // Append as 8 bit character
252 LChar lChar = static_cast<LChar>(*characters);
257 // Calculate the new size of the builder after appending.
258 unsigned requiredLength = length + m_length;
259 if (requiredLength < length)
263 // If the buffer is valid it must be at least as long as the current builder contents!
264 ASSERT(m_buffer->length() >= m_length);
266 allocateBufferUpConvert(m_buffer->characters8(), expandedCapacity(capacity(), requiredLength));
268 ASSERT(m_string.length() == m_length);
269 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8(), expandedCapacity(capacity(), requiredLength));
272 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(length) * sizeof(UChar));
273 m_length = requiredLength;
275 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_t>(length) * sizeof(UChar));
278 void StringBuilder::append(const LChar* characters, unsigned length)
285 LChar* dest = appendUninitialized<LChar>(length);
287 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar));
289 const LChar* end = characters + length;
290 while (characters < end)
291 *(dest++) = *(characters++);
294 UChar* dest = appendUninitialized<UChar>(length);
295 const LChar* end = characters + length;
296 while (characters < end)
297 *(dest++) = *(characters++);
301 void StringBuilder::appendNumber(int number)
303 numberToStringSigned<StringBuilder>(number, this);
306 void StringBuilder::appendNumber(unsigned int number)
308 numberToStringUnsigned<StringBuilder>(number, this);
311 void StringBuilder::appendNumber(long number)
313 numberToStringSigned<StringBuilder>(number, this);
316 void StringBuilder::appendNumber(unsigned long number)
318 numberToStringUnsigned<StringBuilder>(number, this);
321 void StringBuilder::appendNumber(long long number)
323 numberToStringSigned<StringBuilder>(number, this);
326 void StringBuilder::appendNumber(unsigned long long number)
328 numberToStringUnsigned<StringBuilder>(number, this);
331 bool StringBuilder::canShrink() const
333 // Only shrink the buffer if it's less than 80% full. Need to tune this heuristic!
334 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2));
337 void StringBuilder::shrinkToFit()
341 reallocateBuffer<LChar>(m_length);
343 reallocateBuffer<UChar>(m_length);