OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2010 Apple Inc. All rights reserved. | |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
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. | |
13 * | |
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. | |
25 */ | |
26 | |
27 #include "config.h" | |
28 #include "StringBuilder.h" | |
29 | |
30 #include "IntegerToStringConversion.h" | |
31 #include "WTFString.h" | |
32 | |
33 namespace WTF { | |
34 | |
35 static const unsigned minimumCapacity = 16; | |
36 | |
37 void StringBuilder::reifyString() const | |
38 { | |
39 // Check if the string already exists. | |
40 if (!m_string.isNull()) { | |
41 ASSERT(m_string.length() == m_length); | |
42 return; | |
43 } | |
44 | |
45 // Check for empty. | |
46 if (!m_length) { | |
47 m_string = StringImpl::empty(); | |
48 return; | |
49 } | |
50 | |
51 // Must be valid in the buffer, take a substring (unless string fills the bu
ffer). | |
52 ASSERT(m_buffer && m_length <= m_buffer->length()); | |
53 m_string = (m_length == m_buffer->length()) | |
54 ? m_buffer.get() | |
55 : StringImpl::create(m_buffer, 0, m_length); | |
56 | |
57 if (m_buffer->has16BitShadow() && m_valid16BitShadowLength < m_length) | |
58 m_buffer->upconvertCharacters(m_valid16BitShadowLength, m_length); | |
59 | |
60 m_valid16BitShadowLength = m_length; | |
61 } | |
62 | |
63 void StringBuilder::resize(unsigned newSize) | |
64 { | |
65 // Check newSize < m_length, hence m_length > 0. | |
66 ASSERT(newSize <= m_length); | |
67 if (newSize == m_length) | |
68 return; | |
69 ASSERT(m_length); | |
70 | |
71 // If there is a buffer, we only need to duplicate it if it has more than on
e ref. | |
72 if (m_buffer) { | |
73 m_string = String(); // Clear the string to remove the reference to m_bu
ffer if any before checking the reference count of m_buffer. | |
74 if (!m_buffer->hasOneRef()) { | |
75 if (m_buffer->is8Bit()) | |
76 allocateBuffer(m_buffer->characters8(), m_buffer->length()); | |
77 else | |
78 allocateBuffer(m_buffer->characters16(), m_buffer->length()); | |
79 } | |
80 m_length = newSize; | |
81 return; | |
82 } | |
83 | |
84 // Since m_length && !m_buffer, the string must be valid in m_string, and m_
string.length() > 0. | |
85 ASSERT(!m_string.isEmpty()); | |
86 ASSERT(m_length == m_string.length()); | |
87 ASSERT(newSize < m_string.length()); | |
88 m_length = newSize; | |
89 m_string = StringImpl::create(m_string.impl(), 0, newSize); | |
90 } | |
91 | |
92 // Allocate a new 8 bit buffer, copying in currentCharacters (these may come fro
m either m_string | |
93 // or m_buffer, neither will be reassigned until the copy has completed). | |
94 void StringBuilder::allocateBuffer(const LChar* currentCharacters, unsigned requ
iredLength) | |
95 { | |
96 ASSERT(m_is8Bit); | |
97 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | |
98 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters8); | |
99 memcpy(m_bufferCharacters8, currentCharacters, static_cast<size_t>(m_length)
* sizeof(LChar)); // This can't overflow. | |
100 | |
101 // Update the builder state. | |
102 m_buffer = buffer.release(); | |
103 m_string = String(); | |
104 } | |
105 | |
106 // Allocate a new 16 bit buffer, copying in currentCharacters (these may come fr
om either m_string | |
107 // or m_buffer, neither will be reassigned until the copy has completed). | |
108 void StringBuilder::allocateBuffer(const UChar* currentCharacters, unsigned requ
iredLength) | |
109 { | |
110 ASSERT(!m_is8Bit); | |
111 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | |
112 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); | |
113 memcpy(m_bufferCharacters16, currentCharacters, static_cast<size_t>(m_length
) * sizeof(UChar)); // This can't overflow. | |
114 | |
115 // Update the builder state. | |
116 m_buffer = buffer.release(); | |
117 m_string = String(); | |
118 } | |
119 | |
120 // Allocate a new 16 bit buffer, copying in currentCharacters (which is 8 bit an
d may come | |
121 // from either m_string or m_buffer, neither will be reassigned until the copy h
as completed). | |
122 void StringBuilder::allocateBufferUpConvert(const LChar* currentCharacters, unsi
gned requiredLength) | |
123 { | |
124 ASSERT(m_is8Bit); | |
125 // Copy the existing data into a new buffer, set result to point to the end
of the existing data. | |
126 RefPtr<StringImpl> buffer = StringImpl::createUninitialized(requiredLength,
m_bufferCharacters16); | |
127 for (unsigned i = 0; i < m_length; ++i) | |
128 m_bufferCharacters16[i] = currentCharacters[i]; | |
129 | |
130 m_is8Bit = false; | |
131 | |
132 // Update the builder state. | |
133 m_buffer = buffer.release(); | |
134 m_string = String(); | |
135 } | |
136 | |
137 template <> | |
138 void StringBuilder::reallocateBuffer<LChar>(unsigned requiredLength) | |
139 { | |
140 // If the buffer has only one ref (by this StringBuilder), reallocate it, | |
141 // otherwise fall back to "allocate and copy" method. | |
142 m_string = String(); | |
143 | |
144 ASSERT(m_is8Bit); | |
145 ASSERT(m_buffer->is8Bit()); | |
146 | |
147 if (m_buffer->hasOneRef()) | |
148 m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_
bufferCharacters8); | |
149 else | |
150 allocateBuffer(m_buffer->characters8(), requiredLength); | |
151 } | |
152 | |
153 template <> | |
154 void StringBuilder::reallocateBuffer<UChar>(unsigned requiredLength) | |
155 { | |
156 // If the buffer has only one ref (by this StringBuilder), reallocate it, | |
157 // otherwise fall back to "allocate and copy" method. | |
158 m_string = String(); | |
159 | |
160 if (m_buffer->is8Bit()) | |
161 allocateBufferUpConvert(m_buffer->characters8(), requiredLength); | |
162 else if (m_buffer->hasOneRef()) | |
163 m_buffer = StringImpl::reallocate(m_buffer.release(), requiredLength, m_
bufferCharacters16); | |
164 else | |
165 allocateBuffer(m_buffer->characters16(), requiredLength); | |
166 } | |
167 | |
168 void StringBuilder::reserveCapacity(unsigned newCapacity) | |
169 { | |
170 if (m_buffer) { | |
171 // If there is already a buffer, then grow if necessary. | |
172 if (newCapacity > m_buffer->length()) { | |
173 if (m_buffer->is8Bit()) | |
174 reallocateBuffer<LChar>(newCapacity); | |
175 else | |
176 reallocateBuffer<UChar>(newCapacity); | |
177 } | |
178 } else { | |
179 // Grow the string, if necessary. | |
180 if (newCapacity > m_length) { | |
181 if (!m_length) { | |
182 LChar* nullPlaceholder = 0; | |
183 allocateBuffer(nullPlaceholder, newCapacity); | |
184 } else if (m_string.is8Bit()) | |
185 allocateBuffer(m_string.characters8(), newCapacity); | |
186 else | |
187 allocateBuffer(m_string.characters16(), newCapacity); | |
188 } | |
189 } | |
190 } | |
191 | |
192 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, | |
193 // return a pointer to the newly allocated storage. | |
194 template <typename CharType> | |
195 ALWAYS_INLINE CharType* StringBuilder::appendUninitialized(unsigned length) | |
196 { | |
197 ASSERT(length); | |
198 | |
199 // Calculate the new size of the builder after appending. | |
200 unsigned requiredLength = length + m_length; | |
201 RELEASE_ASSERT(requiredLength >= length); | |
202 | |
203 if ((m_buffer) && (requiredLength <= m_buffer->length())) { | |
204 // If the buffer is valid it must be at least as long as the current bui
lder contents! | |
205 ASSERT(m_buffer->length() >= m_length); | |
206 unsigned currentLength = m_length; | |
207 m_string = String(); | |
208 m_length = requiredLength; | |
209 return getBufferCharacters<CharType>() + currentLength; | |
210 } | |
211 | |
212 return appendUninitializedSlow<CharType>(requiredLength); | |
213 } | |
214 | |
215 // Make 'length' additional capacity be available in m_buffer, update m_string &
m_length, | |
216 // return a pointer to the newly allocated storage. | |
217 template <typename CharType> | |
218 CharType* StringBuilder::appendUninitializedSlow(unsigned requiredLength) | |
219 { | |
220 ASSERT(requiredLength); | |
221 | |
222 if (m_buffer) { | |
223 // If the buffer is valid it must be at least as long as the current bui
lder contents! | |
224 ASSERT(m_buffer->length() >= m_length); | |
225 | |
226 reallocateBuffer<CharType>(std::max(requiredLength, std::max(minimumCapa
city, m_buffer->length() * 2))); | |
227 } else { | |
228 ASSERT(m_string.length() == m_length); | |
229 allocateBuffer(m_length ? m_string.getCharacters<CharType>() : 0, std::m
ax(requiredLength, std::max(minimumCapacity, m_length * 2))); | |
230 } | |
231 | |
232 CharType* result = getBufferCharacters<CharType>() + m_length; | |
233 m_length = requiredLength; | |
234 return result; | |
235 } | |
236 | |
237 void StringBuilder::append(const UChar* characters, unsigned length) | |
238 { | |
239 if (!length) | |
240 return; | |
241 | |
242 ASSERT(characters); | |
243 | |
244 if (m_is8Bit) { | |
245 if (length == 1 && !(*characters & ~0xff)) { | |
246 // Append as 8 bit character | |
247 LChar lChar = static_cast<LChar>(*characters); | |
248 append(&lChar, 1); | |
249 return; | |
250 } | |
251 | |
252 // Calculate the new size of the builder after appending. | |
253 unsigned requiredLength = length + m_length; | |
254 RELEASE_ASSERT(requiredLength >= length); | |
255 | |
256 if (m_buffer) { | |
257 // If the buffer is valid it must be at least as long as the current
builder contents! | |
258 ASSERT(m_buffer->length() >= m_length); | |
259 | |
260 allocateBufferUpConvert(m_buffer->characters8(), requiredLength); | |
261 } else { | |
262 ASSERT(m_string.length() == m_length); | |
263 allocateBufferUpConvert(m_string.isNull() ? 0 : m_string.characters8
(), std::max(requiredLength, std::max(minimumCapacity, m_length * 2))); | |
264 } | |
265 | |
266 memcpy(m_bufferCharacters16 + m_length, characters, static_cast<size_t>(
length) * sizeof(UChar)); | |
267 m_length = requiredLength; | |
268 } else | |
269 memcpy(appendUninitialized<UChar>(length), characters, static_cast<size_
t>(length) * sizeof(UChar)); | |
270 } | |
271 | |
272 void StringBuilder::append(const LChar* characters, unsigned length) | |
273 { | |
274 if (!length) | |
275 return; | |
276 ASSERT(characters); | |
277 | |
278 if (m_is8Bit) { | |
279 LChar* dest = appendUninitialized<LChar>(length); | |
280 if (length > 8) | |
281 memcpy(dest, characters, static_cast<size_t>(length) * sizeof(LChar)
); | |
282 else { | |
283 const LChar* end = characters + length; | |
284 while (characters < end) | |
285 *(dest++) = *(characters++); | |
286 } | |
287 } else { | |
288 UChar* dest = appendUninitialized<UChar>(length); | |
289 const LChar* end = characters + length; | |
290 while (characters < end) | |
291 *(dest++) = *(characters++); | |
292 } | |
293 } | |
294 | |
295 void StringBuilder::appendNumber(int number) | |
296 { | |
297 numberToStringSigned<StringBuilder>(number, this); | |
298 } | |
299 | |
300 void StringBuilder::appendNumber(unsigned int number) | |
301 { | |
302 numberToStringUnsigned<StringBuilder>(number, this); | |
303 } | |
304 | |
305 void StringBuilder::appendNumber(long number) | |
306 { | |
307 numberToStringSigned<StringBuilder>(number, this); | |
308 } | |
309 | |
310 void StringBuilder::appendNumber(unsigned long number) | |
311 { | |
312 numberToStringUnsigned<StringBuilder>(number, this); | |
313 } | |
314 | |
315 void StringBuilder::appendNumber(long long number) | |
316 { | |
317 numberToStringSigned<StringBuilder>(number, this); | |
318 } | |
319 | |
320 void StringBuilder::appendNumber(unsigned long long number) | |
321 { | |
322 numberToStringUnsigned<StringBuilder>(number, this); | |
323 } | |
324 | |
325 bool StringBuilder::canShrink() const | |
326 { | |
327 // Only shrink the buffer if it's less than 80% full. Need to tune this heur
istic! | |
328 return m_buffer && m_buffer->length() > (m_length + (m_length >> 2)); | |
329 } | |
330 | |
331 void StringBuilder::shrinkToFit() | |
332 { | |
333 if (canShrink()) { | |
334 if (m_is8Bit) | |
335 reallocateBuffer<LChar>(m_length); | |
336 else | |
337 reallocateBuffer<UChar>(m_length); | |
338 m_string = m_buffer; | |
339 m_buffer = 0; | |
340 } | |
341 } | |
342 | |
343 } // namespace WTF | |
OLD | NEW |