Home | History | Annotate | Download | only in text
      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:
     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 
     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(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 
    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 
    118     void append(const char* characters)
    119     {
    120         if (characters)
    121             append(characters, strlen(characters));
    122     }
    123 
    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 
    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 
    151     void append(char c)
    152     {
    153         append(static_cast<LChar>(c));
    154     }
    155 
    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>
    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 
    177     String toString()
    178     {
    179         shrinkToFit();
    180         if (m_string.isNull())
    181             reifyString();
    182         return m_string;
    183     }
    184 
    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 
    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 
    213     unsigned length() const
    214     {
    215         return m_length;
    216     }
    217 
    218     bool isEmpty() const { return !m_length; }
    219 
    220     void reserveCapacity(unsigned newCapacity);
    221 
    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 
    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 
    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 
    263     bool is8Bit() const { return m_is8Bit; }
    264 
    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 
    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>
    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>
    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 
    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>
    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>
    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