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