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