8224d22d6b8827fdd11e69cba46061430c81db14
[WebKit-https.git] / Source / WTF / wtf / text / StringBuilder.h
1 /*
2  * Copyright (C) 2009-2010, 2012-2013, 2016 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 #ifndef StringBuilder_h
28 #define StringBuilder_h
29
30 #include <wtf/text/AtomicString.h>
31 #include <wtf/text/StringView.h>
32 #include <wtf/text/WTFString.h>
33
34 namespace WTF {
35
36 class StringBuilder {
37     // Disallow copying since it's expensive and we don't want code to do it by accident.
38     WTF_MAKE_NONCOPYABLE(StringBuilder);
39
40 public:
41     StringBuilder()
42         : m_length(0)
43         , m_is8Bit(true)
44         , m_bufferCharacters8(0)
45     {
46     }
47
48     WTF_EXPORT_PRIVATE void append(const UChar*, unsigned);
49     WTF_EXPORT_PRIVATE void append(const LChar*, unsigned);
50
51     ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast<const LChar*>(characters), length); }
52
53     void append(const String& string)
54     {
55         if (!string.length())
56             return;
57
58         // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
59         // then just retain the string.
60         if (!m_length && !m_buffer) {
61             m_string = string;
62             m_length = string.length();
63             m_is8Bit = m_string.is8Bit();
64             return;
65         }
66
67         if (string.is8Bit())
68             append(string.characters8(), string.length());
69         else
70             append(string.characters16(), string.length());
71     }
72
73     void append(const StringBuilder& other)
74     {
75         if (!other.m_length)
76             return;
77
78         // If we're appending to an empty string, and there is not a buffer (reserveCapacity has not been called)
79         // then just retain the string.
80         if (!m_length && !m_buffer && !other.m_string.isNull()) {
81             m_string = other.m_string;
82             m_length = other.m_length;
83             return;
84         }
85
86         if (other.is8Bit())
87             append(other.characters8(), other.m_length);
88         else
89             append(other.characters16(), other.m_length);
90     }
91
92     void append(StringView stringView)
93     {
94         if (stringView.is8Bit())
95             append(stringView.characters8(), stringView.length());
96         else
97             append(stringView.characters16(), stringView.length());
98     }
99     
100     void append(const String& string, unsigned offset, unsigned length)
101     {
102         if (!string.length())
103             return;
104
105         if ((offset + length) > string.length())
106             return;
107
108         if (string.is8Bit())
109             append(string.characters8() + offset, length);
110         else
111             append(string.characters16() + offset, length);
112     }
113
114     void append(const char* characters)
115     {
116         if (characters)
117             append(characters, strlen(characters));
118     }
119
120     void append(UChar c)
121     {
122         if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
123             if (!m_is8Bit) {
124                 m_bufferCharacters16[m_length++] = c;
125                 return;
126             }
127
128             if (!(c & ~0xff)) {
129                 m_bufferCharacters8[m_length++] = static_cast<LChar>(c);
130                 return;
131             }
132         }
133         append(&c, 1);
134     }
135
136     void append(LChar c)
137     {
138         if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
139             if (m_is8Bit)
140                 m_bufferCharacters8[m_length++] = c;
141             else
142                 m_bufferCharacters16[m_length++] = c;
143         } else
144             append(&c, 1);
145     }
146
147     void append(char c)
148     {
149         append(static_cast<LChar>(c));
150     }
151
152     void append(UChar32 c)
153     {
154         if (U_IS_BMP(c)) {
155             append(static_cast<UChar>(c));
156             return;
157         }
158         append(U16_LEAD(c));
159         append(U16_TRAIL(c));
160     }
161
162     WTF_EXPORT_PRIVATE void appendQuotedJSONString(const String&);
163
164     template<unsigned charactersCount>
165     ALWAYS_INLINE void appendLiteral(const char (&characters)[charactersCount]) { append(characters, charactersCount - 1); }
166
167     WTF_EXPORT_PRIVATE void appendNumber(int);
168     WTF_EXPORT_PRIVATE void appendNumber(unsigned int);
169     WTF_EXPORT_PRIVATE void appendNumber(long);
170     WTF_EXPORT_PRIVATE void appendNumber(unsigned long);
171     WTF_EXPORT_PRIVATE void appendNumber(long long);
172     WTF_EXPORT_PRIVATE void appendNumber(unsigned long long);
173     WTF_EXPORT_PRIVATE void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
174     WTF_EXPORT_PRIVATE void appendECMAScriptNumber(double);
175     WTF_EXPORT_PRIVATE void appendFixedWidthNumber(double, unsigned decimalPlaces);
176
177     String toString()
178     {
179         shrinkToFit();
180         if (m_string.isNull())
181             reifyString();
182         return m_string;
183     }
184
185     const String& toStringPreserveCapacity() const
186     {
187         if (m_string.isNull())
188             reifyString();
189         return m_string;
190     }
191
192     AtomicString toAtomicString() const
193     {
194         if (!m_length)
195             return emptyAtom;
196
197         // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large.
198         if (canShrink()) {
199             if (is8Bit())
200                 return AtomicString(characters8(), length());
201             return AtomicString(characters16(), length());            
202         }
203
204         if (!m_string.isNull())
205             return AtomicString(m_string);
206
207         ASSERT(m_buffer);
208         return AtomicString(m_buffer.get(), 0, m_length);
209     }
210
211     unsigned length() const
212     {
213         return m_length;
214     }
215
216     bool isEmpty() const { return !m_length; }
217
218     WTF_EXPORT_PRIVATE void reserveCapacity(unsigned newCapacity);
219
220     unsigned capacity() const
221     {
222         return m_buffer ? m_buffer->length() : m_length;
223     }
224
225     WTF_EXPORT_PRIVATE void resize(unsigned newSize);
226
227     WTF_EXPORT_PRIVATE bool canShrink() const;
228
229     WTF_EXPORT_PRIVATE void shrinkToFit();
230
231     UChar operator[](unsigned i) const
232     {
233         ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
234         if (m_is8Bit)
235             return characters8()[i];
236         return characters16()[i];
237     }
238
239     const LChar* characters8() const
240     {
241         ASSERT(m_is8Bit);
242         if (!m_length)
243             return 0;
244         if (!m_string.isNull())
245             return m_string.characters8();
246         ASSERT(m_buffer);
247         return m_buffer->characters8();
248     }
249
250     const UChar* characters16() const
251     {
252         ASSERT(!m_is8Bit);
253         if (!m_length)
254             return 0;
255         if (!m_string.isNull())
256             return m_string.characters16();
257         ASSERT(m_buffer);
258         return m_buffer->characters16();
259     }
260     
261     bool is8Bit() const { return m_is8Bit; }
262
263     void clear()
264     {
265         m_length = 0;
266         m_string = String();
267         m_buffer = nullptr;
268         m_bufferCharacters8 = 0;
269         m_is8Bit = true;
270     }
271
272     void swap(StringBuilder& stringBuilder)
273     {
274         std::swap(m_length, stringBuilder.m_length);
275         m_string.swap(stringBuilder.m_string);
276         m_buffer.swap(stringBuilder.m_buffer);
277         std::swap(m_is8Bit, stringBuilder.m_is8Bit);
278         std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
279         ASSERT(!m_buffer || m_buffer->length() >= m_length);
280     }
281
282 private:
283     void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
284     void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
285     void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
286     template <typename CharType>
287     void reallocateBuffer(unsigned requiredLength);
288     template <typename CharType>
289     ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
290     template <typename CharType>
291     CharType* appendUninitializedSlow(unsigned length);
292     template <typename CharType>
293     ALWAYS_INLINE CharType * getBufferCharacters();
294     WTF_EXPORT_PRIVATE void reifyString() const;
295
296     unsigned m_length;
297     mutable String m_string;
298     RefPtr<StringImpl> m_buffer;
299     bool m_is8Bit;
300     union {
301         LChar* m_bufferCharacters8;
302         UChar* m_bufferCharacters16;
303     };
304 };
305
306 template <>
307 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
308 {
309     ASSERT(m_is8Bit);
310     return m_bufferCharacters8;
311 }
312
313 template <>
314 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
315 {
316     ASSERT(!m_is8Bit);
317     return m_bufferCharacters16;
318 }    
319
320 template <typename CharType>
321 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
322 {
323     if (s.length() != length)
324         return false;
325
326     if (s.is8Bit())
327         return equal(s.characters8(), buffer, length);
328
329     return equal(s.characters16(), buffer, length);
330 }
331
332 template <typename StringType>
333 bool equal(const StringBuilder& a, const StringType& b)
334 {
335     if (a.length() != b.length())
336         return false;
337
338     if (!a.length())
339         return true;
340
341     if (a.is8Bit()) {
342         if (b.is8Bit())
343             return equal(a.characters8(), b.characters8(), a.length());
344         return equal(a.characters8(), b.characters16(), a.length());
345     }
346
347     if (b.is8Bit())
348         return equal(a.characters16(), b.characters8(), a.length());
349     return equal(a.characters16(), b.characters16(), a.length());
350 }
351
352 inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); }
353 inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); }
354 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); }
355 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); }
356 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); }
357 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); }
358
359 } // namespace WTF
360
361 using WTF::StringBuilder;
362
363 #endif // StringBuilder_h