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