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 "third_party/blink/renderer/platform/wtf/text/string_builder.h"
28
29 #include <algorithm>
30 #include "base/optional.h"
31 #include "base/strings/string_util.h"
32 #include "third_party/blink/renderer/platform/wtf/dtoa.h"
33 #include "third_party/blink/renderer/platform/wtf/text/integer_to_string_conversion.h"
34 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
35
36 namespace WTF {
37
ToString()38 String StringBuilder::ToString() {
39 if (!length_)
40 return g_empty_string;
41 if (string_.IsNull()) {
42 if (is_8bit_)
43 string_ = String(Characters8(), length_);
44 else
45 string_ = String(Characters16(), length_);
46 ClearBuffer();
47 }
48 return string_;
49 }
50
ToAtomicString()51 AtomicString StringBuilder::ToAtomicString() {
52 if (!length_)
53 return g_empty_atom;
54 if (string_.IsNull()) {
55 if (is_8bit_)
56 string_ = AtomicString(Characters8(), length_);
57 else
58 string_ = AtomicString(Characters16(), length_);
59 ClearBuffer();
60 }
61 return AtomicString(string_);
62 }
63
Substring(unsigned start,unsigned length) const64 String StringBuilder::Substring(unsigned start, unsigned length) const {
65 if (start >= length_)
66 return g_empty_string;
67 if (!string_.IsNull())
68 return string_.Substring(start, length);
69 length = std::min(length, length_ - start);
70 if (is_8bit_)
71 return String(Characters8() + start, length);
72 return String(Characters16() + start, length);
73 }
74
Swap(StringBuilder & builder)75 void StringBuilder::Swap(StringBuilder& builder) {
76 base::Optional<Buffer8> buffer8;
77 base::Optional<Buffer16> buffer16;
78 if (has_buffer_) {
79 if (is_8bit_) {
80 buffer8 = std::move(buffer8_);
81 buffer8_.~Buffer8();
82 } else {
83 buffer16 = std::move(buffer16_);
84 buffer16_.~Buffer16();
85 }
86 }
87
88 if (builder.has_buffer_) {
89 if (builder.is_8bit_) {
90 new (&buffer8_) Buffer8(std::move(builder.buffer8_));
91 builder.buffer8_.~Buffer8();
92 } else {
93 new (&buffer16_) Buffer16(std::move(builder.buffer16_));
94 builder.buffer16_.~Buffer16();
95 }
96 }
97
98 if (buffer8)
99 new (&builder.buffer8_) Buffer8(std::move(*buffer8));
100 else if (buffer16)
101 new (&builder.buffer16_) Buffer16(std::move(*buffer16));
102
103 std::swap(string_, builder.string_);
104 std::swap(length_, builder.length_);
105 std::swap(is_8bit_, builder.is_8bit_);
106 std::swap(has_buffer_, builder.has_buffer_);
107 }
108
ClearBuffer()109 void StringBuilder::ClearBuffer() {
110 if (!has_buffer_)
111 return;
112 if (is_8bit_)
113 buffer8_.~Buffer8();
114 else
115 buffer16_.~Buffer16();
116 has_buffer_ = false;
117 }
118
Ensure16Bit()119 void StringBuilder::Ensure16Bit() {
120 EnsureBuffer16(0);
121 }
122
Clear()123 void StringBuilder::Clear() {
124 ClearBuffer();
125 string_ = String();
126 length_ = 0;
127 is_8bit_ = true;
128 }
129
Capacity() const130 unsigned StringBuilder::Capacity() const {
131 if (!HasBuffer())
132 return 0;
133 if (is_8bit_)
134 return buffer8_.capacity();
135 return buffer16_.capacity();
136 }
137
ReserveCapacity(unsigned new_capacity)138 void StringBuilder::ReserveCapacity(unsigned new_capacity) {
139 if (is_8bit_)
140 EnsureBuffer8(new_capacity);
141 else
142 EnsureBuffer16(new_capacity);
143 }
144
Resize(unsigned new_size)145 void StringBuilder::Resize(unsigned new_size) {
146 DCHECK_LE(new_size, length_);
147 string_ = string_.Left(new_size);
148 length_ = new_size;
149 if (HasBuffer()) {
150 if (is_8bit_)
151 buffer8_.resize(new_size);
152 else
153 buffer16_.resize(new_size);
154 }
155 }
156
CreateBuffer8(unsigned added_size)157 void StringBuilder::CreateBuffer8(unsigned added_size) {
158 DCHECK(!HasBuffer());
159 DCHECK(is_8bit_);
160 new (&buffer8_) Buffer8;
161 has_buffer_ = true;
162 // createBuffer is called right before appending addedSize more bytes. We
163 // want to ensure we have enough space to fit m_string plus the added
164 // size.
165 //
166 // We also ensure that we have at least the initialBufferSize of extra space
167 // for appending new bytes to avoid future mallocs for appending short
168 // strings or single characters. This is a no-op if m_length == 0 since
169 // initialBufferSize() is the same as the inline capacity of the vector.
170 // This allows doing append(string); append('\0') without extra mallocs.
171 buffer8_.ReserveInitialCapacity(length_ +
172 std::max(added_size, InitialBufferSize()));
173 length_ = 0;
174 Append(string_);
175 string_ = String();
176 }
177
CreateBuffer16(unsigned added_size)178 void StringBuilder::CreateBuffer16(unsigned added_size) {
179 DCHECK(is_8bit_ || !HasBuffer());
180 Buffer8 buffer8;
181 unsigned length = length_;
182 if (has_buffer_) {
183 buffer8 = std::move(buffer8_);
184 buffer8_.~Buffer8();
185 }
186 new (&buffer16_) Buffer16;
187 has_buffer_ = true;
188 // See createBuffer8's call to reserveInitialCapacity for why we do this.
189 buffer16_.ReserveInitialCapacity(
190 length_ +
191 std::max<unsigned>(added_size, InitialBufferSize() / sizeof(UChar)));
192 is_8bit_ = false;
193 length_ = 0;
194 if (!buffer8.IsEmpty()) {
195 Append(buffer8.data(), length);
196 return;
197 }
198 Append(string_);
199 string_ = String();
200 }
201
Append(const UChar * characters,unsigned length)202 void StringBuilder::Append(const UChar* characters, unsigned length) {
203 if (!length)
204 return;
205 DCHECK(characters);
206
207 // If there's only one char we use append(UChar) instead since it will
208 // check for latin1 and avoid converting to 16bit if possible.
209 if (length == 1) {
210 Append(*characters);
211 return;
212 }
213
214 EnsureBuffer16(length);
215 buffer16_.Append(characters, length);
216 length_ += length;
217 }
218
Append(const LChar * characters,unsigned length)219 void StringBuilder::Append(const LChar* characters, unsigned length) {
220 if (!length)
221 return;
222 DCHECK(characters);
223
224 if (is_8bit_) {
225 EnsureBuffer8(length);
226 buffer8_.Append(characters, length);
227 length_ += length;
228 return;
229 }
230
231 EnsureBuffer16(length);
232 buffer16_.Append(characters, length);
233 length_ += length;
234 }
235
AppendNumber(bool number)236 void StringBuilder::AppendNumber(bool number) {
237 AppendNumber(static_cast<uint8_t>(number));
238 }
239
AppendNumber(float number)240 void StringBuilder::AppendNumber(float number) {
241 AppendNumber(static_cast<double>(number));
242 }
243
AppendNumber(double number,unsigned precision)244 void StringBuilder::AppendNumber(double number, unsigned precision) {
245 NumberToStringBuffer buffer;
246 Append(NumberToFixedPrecisionString(number, precision, buffer));
247 }
248
AppendFormat(const char * format,...)249 void StringBuilder::AppendFormat(const char* format, ...) {
250 va_list args;
251
252 static constexpr unsigned kDefaultSize = 256;
253 Vector<char, kDefaultSize> buffer(kDefaultSize);
254
255 va_start(args, format);
256 int length = base::vsnprintf(buffer.data(), kDefaultSize, format, args);
257 va_end(args);
258 DCHECK_GE(length, 0);
259
260 if (length >= static_cast<int>(kDefaultSize)) {
261 buffer.Grow(length + 1);
262 va_start(args, format);
263 length = base::vsnprintf(buffer.data(), buffer.size(), format, args);
264 va_end(args);
265 }
266
267 DCHECK_LT(static_cast<wtf_size_t>(length), buffer.size());
268 Append(reinterpret_cast<const LChar*>(buffer.data()), length);
269 }
270
erase(unsigned index)271 void StringBuilder::erase(unsigned index) {
272 if (index >= length_)
273 return;
274
275 if (is_8bit_) {
276 EnsureBuffer8(0);
277 buffer8_.EraseAt(index);
278 } else {
279 EnsureBuffer16(0);
280 buffer16_.EraseAt(index);
281 }
282 --length_;
283 }
284
285 } // namespace WTF
286