• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009, 2010, 2012, 2013 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/WTFExport.h"
31 #include "wtf/text/AtomicString.h"
32 #include "wtf/text/WTFString.h"
33 
34 namespace WTF {
35 
36 class WTF_EXPORT 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:
StringBuilder()41     StringBuilder()
42         : m_bufferCharacters8(0)
43         , m_length(0)
44         , m_is8Bit(true)
45     {
46     }
47 
48     void append(const UChar*, unsigned);
49     void append(const LChar*, unsigned);
50 
append(const char * characters,unsigned length)51     ALWAYS_INLINE void append(const char* characters, unsigned length) { append(reinterpret_cast<const LChar*>(characters), length); }
52 
append(const String & string)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 
append(const StringBuilder & other)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 
append(const String & string,unsigned offset,unsigned length)92     void append(const String& string, unsigned offset, unsigned length)
93     {
94         if (!string.length())
95             return;
96 
97         unsigned extent = offset + length;
98         if (extent < offset || extent > string.length())
99             return;
100 
101         if (string.is8Bit())
102             append(string.characters8() + offset, length);
103         else
104             append(string.characters16() + offset, length);
105     }
106 
append(const StringView & string)107     void append(const StringView& string)
108     {
109         if (!string.length())
110             return;
111 
112         if (string.is8Bit())
113             append(string.characters8(), string.length());
114         else
115             append(string.characters16(), string.length());
116     }
117 
append(const char * characters)118     void append(const char* characters)
119     {
120         if (characters)
121             append(characters, strlen(characters));
122     }
123 
append(UChar c)124     void append(UChar c)
125     {
126         if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
127             if (!m_is8Bit) {
128                 m_bufferCharacters16[m_length++] = c;
129                 return;
130             }
131 
132             if (!(c & ~0xff)) {
133                 m_bufferCharacters8[m_length++] = static_cast<LChar>(c);
134                 return;
135             }
136         }
137         append(&c, 1);
138     }
139 
append(LChar c)140     void append(LChar c)
141     {
142         if (m_buffer && m_length < m_buffer->length() && m_string.isNull()) {
143             if (m_is8Bit)
144                 m_bufferCharacters8[m_length++] = c;
145             else
146                 m_bufferCharacters16[m_length++] = c;
147         } else
148             append(&c, 1);
149     }
150 
append(char c)151     void append(char c)
152     {
153         append(static_cast<LChar>(c));
154     }
155 
append(UChar32 c)156     void append(UChar32 c)
157     {
158         if (U_IS_BMP(c)) {
159             append(static_cast<UChar>(c));
160             return;
161         }
162         append(U16_LEAD(c));
163         append(U16_TRAIL(c));
164     }
165 
166     template<unsigned charactersCount>
appendLiteral(const char (& characters)[charactersCount])167     ALWAYS_INLINE void appendLiteral(const char (&characters)[charactersCount]) { append(characters, charactersCount - 1); }
168 
169     void appendNumber(int);
170     void appendNumber(unsigned);
171     void appendNumber(long);
172     void appendNumber(unsigned long);
173     void appendNumber(long long);
174     void appendNumber(unsigned long long);
175     void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
176 
toString()177     String toString()
178     {
179         shrinkToFit();
180         if (m_string.isNull())
181             reifyString();
182         return m_string;
183     }
184 
substring(unsigned position,unsigned length)185     String substring(unsigned position, unsigned length) const
186     {
187         if (!m_length)
188             return emptyString();
189         if (!m_string.isNull())
190             return m_string.substring(position, length);
191         return reifySubstring(position, length);
192     }
193 
toAtomicString()194     AtomicString toAtomicString() const
195     {
196         if (!m_length)
197             return emptyAtom;
198 
199         // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large.
200         if (canShrink()) {
201             if (is8Bit())
202                 return AtomicString(characters8(), length());
203             return AtomicString(characters16(), length());
204         }
205 
206         if (!m_string.isNull())
207             return AtomicString(m_string);
208 
209         ASSERT(m_buffer);
210         return AtomicString(m_buffer.get(), 0, m_length);
211     }
212 
length()213     unsigned length() const
214     {
215         return m_length;
216     }
217 
isEmpty()218     bool isEmpty() const { return !m_length; }
219 
220     void reserveCapacity(unsigned newCapacity);
221 
capacity()222     unsigned capacity() const
223     {
224         return m_buffer ? m_buffer->length() : m_length;
225     }
226 
227     void resize(unsigned newSize);
228 
229     bool canShrink() const;
230 
231     void shrinkToFit();
232 
233     UChar operator[](unsigned i) const
234     {
235         ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
236         if (m_is8Bit)
237             return characters8()[i];
238         return characters16()[i];
239     }
240 
characters8()241     const LChar* characters8() const
242     {
243         ASSERT(m_is8Bit);
244         if (!m_length)
245             return 0;
246         if (!m_string.isNull())
247             return m_string.characters8();
248         ASSERT(m_buffer);
249         return m_buffer->characters8();
250     }
251 
characters16()252     const UChar* characters16() const
253     {
254         ASSERT(!m_is8Bit);
255         if (!m_length)
256             return 0;
257         if (!m_string.isNull())
258             return m_string.characters16();
259         ASSERT(m_buffer);
260         return m_buffer->characters16();
261     }
262 
is8Bit()263     bool is8Bit() const { return m_is8Bit; }
264 
clear()265     void clear()
266     {
267         m_length = 0;
268         m_string = String();
269         m_buffer = nullptr;
270         m_bufferCharacters8 = 0;
271         m_is8Bit = true;
272     }
273 
swap(StringBuilder & stringBuilder)274     void swap(StringBuilder& stringBuilder)
275     {
276         std::swap(m_length, stringBuilder.m_length);
277         m_string.swap(stringBuilder.m_string);
278         m_buffer.swap(stringBuilder.m_buffer);
279         std::swap(m_is8Bit, stringBuilder.m_is8Bit);
280         std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
281     }
282 
283 private:
284     void allocateBuffer(const LChar* currentCharacters, unsigned requiredLength);
285     void allocateBuffer(const UChar* currentCharacters, unsigned requiredLength);
286     void allocateBufferUpConvert(const LChar* currentCharacters, unsigned requiredLength);
287     template <typename CharType>
288     void reallocateBuffer(unsigned requiredLength);
289     template <typename CharType>
290     ALWAYS_INLINE CharType* appendUninitialized(unsigned length);
291     template <typename CharType>
292     CharType* appendUninitializedSlow(unsigned length);
293     template <typename CharType>
294     ALWAYS_INLINE CharType * getBufferCharacters();
295     void reifyString();
296     String reifySubstring(unsigned position, unsigned length) const;
297 
298     String m_string; // Pointers first: crbug.com/232031
299     RefPtr<StringImpl> m_buffer;
300     union {
301         LChar* m_bufferCharacters8;
302         UChar* m_bufferCharacters16;
303     };
304     unsigned m_length;
305     bool m_is8Bit;
306 };
307 
308 template <>
309 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
310 {
311     ASSERT(m_is8Bit);
312     return m_bufferCharacters8;
313 }
314 
315 template <>
316 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
317 {
318     ASSERT(!m_is8Bit);
319     return m_bufferCharacters16;
320 }
321 
322 template <typename CharType>
equal(const StringBuilder & s,const CharType * buffer,unsigned length)323 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
324 {
325     if (s.length() != length)
326         return false;
327 
328     if (s.is8Bit())
329         return equal(s.characters8(), buffer, length);
330 
331     return equal(s.characters16(), buffer, length);
332 }
333 
334 template<typename CharType>
equalIgnoringCase(const StringBuilder & s,const CharType * buffer,unsigned length)335 bool equalIgnoringCase(const StringBuilder& s, const CharType* buffer, unsigned length)
336 {
337     if (s.length() != length)
338         return false;
339 
340     if (s.is8Bit())
341         return equalIgnoringCase(s.characters8(), buffer, length);
342 
343     return equalIgnoringCase(s.characters16(), buffer, length);
344 }
345 
equalIgnoringCase(const StringBuilder & s,const char * string)346 inline bool equalIgnoringCase(const StringBuilder& s, const char* string)
347 {
348     return equalIgnoringCase(s, reinterpret_cast<const LChar*>(string), strlen(string));
349 }
350 
351 template <typename StringType>
equal(const StringBuilder & a,const StringType & b)352 bool equal(const StringBuilder& a, const StringType& b)
353 {
354     if (a.length() != b.length())
355         return false;
356 
357     if (!a.length())
358         return true;
359 
360     if (a.is8Bit()) {
361         if (b.is8Bit())
362             return equal(a.characters8(), b.characters8(), a.length());
363         return equal(a.characters8(), b.characters16(), a.length());
364     }
365 
366     if (b.is8Bit())
367         return equal(a.characters16(), b.characters8(), a.length());
368     return equal(a.characters16(), b.characters16(), a.length());
369 }
370 
371 template <typename StringType>
equalIgnoringCase(const StringBuilder & a,const StringType & b)372 bool equalIgnoringCase(const StringBuilder& a, const StringType& b)
373 {
374     if (a.length() != b.length())
375         return false;
376 
377     if (!a.length())
378         return true;
379 
380     if (a.is8Bit()) {
381         if (b.is8Bit())
382             return equalIgnoringCase(a.characters8(), b.characters8(), a.length());
383         return equalIgnoringCase(a.characters8(), b.characters16(), a.length());
384     }
385 
386     if (b.is8Bit())
387         return equalIgnoringCase(a.characters16(), b.characters8(), a.length());
388     return equalIgnoringCase(a.characters16(), b.characters16(), a.length());
389 }
390 
391 inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); }
392 inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); }
393 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); }
394 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); }
395 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); }
396 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); }
397 
398 } // namespace WTF
399 
400 using WTF::StringBuilder;
401 
402 #endif // StringBuilder_h
403