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 
    176     String toString()
    177     {
    178         shrinkToFit();
    179         if (m_string.isNull())
    180             reifyString();
    181         return m_string;
    182     }
    183 
    184     String substring(unsigned position, unsigned length) const
    185     {
    186         if (!m_length)
    187             return emptyString();
    188         if (!m_string.isNull())
    189             return m_string.substring(position, length);
    190         return reifySubstring(position, length);
    191     }
    192 
    193     AtomicString toAtomicString() const
    194     {
    195         if (!m_length)
    196             return emptyAtom;
    197 
    198         // If the buffer is sufficiently over-allocated, make a new AtomicString from a copy so its buffer is not so large.
    199         if (canShrink()) {
    200             if (is8Bit())
    201                 return AtomicString(characters8(), length());
    202             return AtomicString(characters16(), length());
    203         }
    204 
    205         if (!m_string.isNull())
    206             return AtomicString(m_string);
    207 
    208         ASSERT(m_buffer);
    209         return AtomicString(m_buffer.get(), 0, m_length);
    210     }
    211 
    212     unsigned length() const
    213     {
    214         return m_length;
    215     }
    216 
    217     bool isEmpty() const { return !m_length; }
    218 
    219     void reserveCapacity(unsigned newCapacity);
    220 
    221     unsigned capacity() const
    222     {
    223         return m_buffer ? m_buffer->length() : m_length;
    224     }
    225 
    226     void resize(unsigned newSize);
    227 
    228     bool canShrink() const;
    229 
    230     void shrinkToFit();
    231 
    232     UChar operator[](unsigned i) const
    233     {
    234         ASSERT_WITH_SECURITY_IMPLICATION(i < m_length);
    235         if (m_is8Bit)
    236             return characters8()[i];
    237         return characters16()[i];
    238     }
    239 
    240     const LChar* characters8() const
    241     {
    242         ASSERT(m_is8Bit);
    243         if (!m_length)
    244             return 0;
    245         if (!m_string.isNull())
    246             return m_string.characters8();
    247         ASSERT(m_buffer);
    248         return m_buffer->characters8();
    249     }
    250 
    251     const UChar* characters16() const
    252     {
    253         ASSERT(!m_is8Bit);
    254         if (!m_length)
    255             return 0;
    256         if (!m_string.isNull())
    257             return m_string.characters16();
    258         ASSERT(m_buffer);
    259         return m_buffer->characters16();
    260     }
    261 
    262     bool is8Bit() const { return m_is8Bit; }
    263 
    264     void clear()
    265     {
    266         m_length = 0;
    267         m_string = String();
    268         m_buffer = 0;
    269         m_bufferCharacters8 = 0;
    270         m_is8Bit = true;
    271     }
    272 
    273     void swap(StringBuilder& stringBuilder)
    274     {
    275         std::swap(m_length, stringBuilder.m_length);
    276         m_string.swap(stringBuilder.m_string);
    277         m_buffer.swap(stringBuilder.m_buffer);
    278         std::swap(m_is8Bit, stringBuilder.m_is8Bit);
    279         std::swap(m_bufferCharacters8, stringBuilder.m_bufferCharacters8);
    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     void reifyString();
    295     String reifySubstring(unsigned position, unsigned length) const;
    296 
    297     String m_string; // Pointers first: crbug.com/232031
    298     RefPtr<StringImpl> m_buffer;
    299     union {
    300         LChar* m_bufferCharacters8;
    301         UChar* m_bufferCharacters16;
    302     };
    303     unsigned m_length;
    304     bool m_is8Bit;
    305 };
    306 
    307 template <>
    308 ALWAYS_INLINE LChar* StringBuilder::getBufferCharacters<LChar>()
    309 {
    310     ASSERT(m_is8Bit);
    311     return m_bufferCharacters8;
    312 }
    313 
    314 template <>
    315 ALWAYS_INLINE UChar* StringBuilder::getBufferCharacters<UChar>()
    316 {
    317     ASSERT(!m_is8Bit);
    318     return m_bufferCharacters16;
    319 }
    320 
    321 template <typename CharType>
    322 bool equal(const StringBuilder& s, const CharType* buffer, unsigned length)
    323 {
    324     if (s.length() != length)
    325         return false;
    326 
    327     if (s.is8Bit())
    328         return equal(s.characters8(), buffer, length);
    329 
    330     return equal(s.characters16(), buffer, length);
    331 }
    332 
    333 template<typename CharType>
    334 bool equalIgnoringCase(const StringBuilder& s, const CharType* buffer, unsigned length)
    335 {
    336     if (s.length() != length)
    337         return false;
    338 
    339     if (s.is8Bit())
    340         return equalIgnoringCase(s.characters8(), buffer, length);
    341 
    342     return equalIgnoringCase(s.characters16(), buffer, length);
    343 }
    344 
    345 inline bool equalIgnoringCase(const StringBuilder& s, const char* string)
    346 {
    347     return equalIgnoringCase(s, reinterpret_cast<const LChar*>(string), strlen(string));
    348 }
    349 
    350 template <typename StringType>
    351 bool equal(const StringBuilder& a, const StringType& b)
    352 {
    353     if (a.length() != b.length())
    354         return false;
    355 
    356     if (!a.length())
    357         return true;
    358 
    359     if (a.is8Bit()) {
    360         if (b.is8Bit())
    361             return equal(a.characters8(), b.characters8(), a.length());
    362         return equal(a.characters8(), b.characters16(), a.length());
    363     }
    364 
    365     if (b.is8Bit())
    366         return equal(a.characters16(), b.characters8(), a.length());
    367     return equal(a.characters16(), b.characters16(), a.length());
    368 }
    369 
    370 template <typename StringType>
    371 bool equalIgnoringCase(const StringBuilder& a, const StringType& b)
    372 {
    373     if (a.length() != b.length())
    374         return false;
    375 
    376     if (!a.length())
    377         return true;
    378 
    379     if (a.is8Bit()) {
    380         if (b.is8Bit())
    381             return equalIgnoringCase(a.characters8(), b.characters8(), a.length());
    382         return equalIgnoringCase(a.characters8(), b.characters16(), a.length());
    383     }
    384 
    385     if (b.is8Bit())
    386         return equalIgnoringCase(a.characters16(), b.characters8(), a.length());
    387     return equalIgnoringCase(a.characters16(), b.characters16(), a.length());
    388 }
    389 
    390 inline bool operator==(const StringBuilder& a, const StringBuilder& b) { return equal(a, b); }
    391 inline bool operator!=(const StringBuilder& a, const StringBuilder& b) { return !equal(a, b); }
    392 inline bool operator==(const StringBuilder& a, const String& b) { return equal(a, b); }
    393 inline bool operator!=(const StringBuilder& a, const String& b) { return !equal(a, b); }
    394 inline bool operator==(const String& a, const StringBuilder& b) { return equal(b, a); }
    395 inline bool operator!=(const String& a, const StringBuilder& b) { return !equal(b, a); }
    396 
    397 } // namespace WTF
    398 
    399 using WTF::StringBuilder;
    400 
    401 #endif // StringBuilder_h
    402