Home | History | Annotate | Download | only in text
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef StringConcatenate_h
     27 #define StringConcatenate_h
     28 
     29 #include <wtf/text/WTFString.h>
     30 
     31 namespace WTF {
     32 
     33 template<typename StringType>
     34 class StringTypeAdapter {
     35 };
     36 
     37 template<>
     38 class StringTypeAdapter<char> {
     39 public:
     40     StringTypeAdapter<char>(char buffer)
     41         : m_buffer(buffer)
     42     {
     43     }
     44 
     45     unsigned length() { return 1; }
     46     void writeTo(UChar* destination) { *destination = m_buffer; }
     47 
     48 private:
     49     unsigned char m_buffer;
     50 };
     51 
     52 template<>
     53 class StringTypeAdapter<UChar> {
     54 public:
     55     StringTypeAdapter<UChar>(UChar buffer)
     56         : m_buffer(buffer)
     57     {
     58     }
     59 
     60     unsigned length() { return 1; }
     61     void writeTo(UChar* destination) { *destination = m_buffer; }
     62 
     63 private:
     64     UChar m_buffer;
     65 };
     66 
     67 template<>
     68 class StringTypeAdapter<char*> {
     69 public:
     70     StringTypeAdapter<char*>(char* buffer)
     71         : m_buffer(buffer)
     72         , m_length(strlen(buffer))
     73     {
     74     }
     75 
     76     unsigned length() { return m_length; }
     77 
     78     void writeTo(UChar* destination)
     79     {
     80         for (unsigned i = 0; i < m_length; ++i) {
     81             unsigned char c = m_buffer[i];
     82             destination[i] = c;
     83         }
     84     }
     85 
     86 private:
     87     const char* m_buffer;
     88     unsigned m_length;
     89 };
     90 
     91 template<>
     92 class StringTypeAdapter<const UChar*> {
     93 public:
     94     StringTypeAdapter<const UChar*>(const UChar* buffer)
     95         : m_buffer(buffer)
     96     {
     97         size_t len = 0;
     98         while (m_buffer[len] != UChar(0))
     99             len++;
    100 
    101         if (len > std::numeric_limits<unsigned>::max())
    102             CRASH();
    103 
    104         m_length = len;
    105     }
    106 
    107     unsigned length() { return m_length; }
    108 
    109     void writeTo(UChar* destination)
    110     {
    111         memcpy(destination, m_buffer, static_cast<size_t>(m_length) * sizeof(UChar));
    112     }
    113 
    114 private:
    115     const UChar* m_buffer;
    116     unsigned m_length;
    117 };
    118 
    119 template<>
    120 class StringTypeAdapter<const char*> {
    121 public:
    122     StringTypeAdapter<const char*>(const char* buffer)
    123         : m_buffer(buffer)
    124         , m_length(strlen(buffer))
    125     {
    126     }
    127 
    128     unsigned length() { return m_length; }
    129 
    130     void writeTo(UChar* destination)
    131     {
    132         for (unsigned i = 0; i < m_length; ++i) {
    133             unsigned char c = m_buffer[i];
    134             destination[i] = c;
    135         }
    136     }
    137 
    138 private:
    139     const char* m_buffer;
    140     unsigned m_length;
    141 };
    142 
    143 template<>
    144 class StringTypeAdapter<Vector<char> > {
    145 public:
    146     StringTypeAdapter<Vector<char> >(const Vector<char>& buffer)
    147         : m_buffer(buffer)
    148     {
    149     }
    150 
    151     size_t length() { return m_buffer.size(); }
    152 
    153     void writeTo(UChar* destination)
    154     {
    155         for (size_t i = 0; i < m_buffer.size(); ++i) {
    156             unsigned char c = m_buffer[i];
    157             destination[i] = c;
    158         }
    159     }
    160 
    161 private:
    162     const Vector<char>& m_buffer;
    163 };
    164 
    165 template<>
    166 class StringTypeAdapter<String> {
    167 public:
    168     StringTypeAdapter<String>(const String& string)
    169         : m_buffer(string)
    170     {
    171     }
    172 
    173     unsigned length() { return m_buffer.length(); }
    174 
    175     void writeTo(UChar* destination)
    176     {
    177         const UChar* data = m_buffer.characters();
    178         unsigned length = m_buffer.length();
    179         for (unsigned i = 0; i < length; ++i)
    180             destination[i] = data[i];
    181     }
    182 
    183 private:
    184     const String& m_buffer;
    185 };
    186 
    187 inline void sumWithOverflow(unsigned& total, unsigned addend, bool& overflow)
    188 {
    189     unsigned oldTotal = total;
    190     total = oldTotal + addend;
    191     if (total < oldTotal)
    192         overflow = true;
    193 }
    194 
    195 template<typename StringType1, typename StringType2>
    196 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2)
    197 {
    198     StringTypeAdapter<StringType1> adapter1(string1);
    199     StringTypeAdapter<StringType2> adapter2(string2);
    200 
    201     UChar* buffer;
    202     bool overflow = false;
    203     unsigned length = adapter1.length();
    204     sumWithOverflow(length, adapter2.length(), overflow);
    205     if (overflow)
    206         return 0;
    207     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    208     if (!resultImpl)
    209         return 0;
    210 
    211     UChar* result = buffer;
    212     adapter1.writeTo(result);
    213     result += adapter1.length();
    214     adapter2.writeTo(result);
    215 
    216     return resultImpl.release();
    217 }
    218 
    219 template<typename StringType1, typename StringType2, typename StringType3>
    220 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3)
    221 {
    222     StringTypeAdapter<StringType1> adapter1(string1);
    223     StringTypeAdapter<StringType2> adapter2(string2);
    224     StringTypeAdapter<StringType3> adapter3(string3);
    225 
    226     UChar* buffer = 0;
    227     bool overflow = false;
    228     unsigned length = adapter1.length();
    229     sumWithOverflow(length, adapter2.length(), overflow);
    230     sumWithOverflow(length, adapter3.length(), overflow);
    231     if (overflow)
    232         return 0;
    233     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    234     if (!resultImpl)
    235         return 0;
    236 
    237     UChar* result = buffer;
    238     adapter1.writeTo(result);
    239     result += adapter1.length();
    240     adapter2.writeTo(result);
    241     result += adapter2.length();
    242     adapter3.writeTo(result);
    243 
    244     return resultImpl.release();
    245 }
    246 
    247 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
    248 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
    249 {
    250     StringTypeAdapter<StringType1> adapter1(string1);
    251     StringTypeAdapter<StringType2> adapter2(string2);
    252     StringTypeAdapter<StringType3> adapter3(string3);
    253     StringTypeAdapter<StringType4> adapter4(string4);
    254 
    255     UChar* buffer;
    256     bool overflow = false;
    257     unsigned length = adapter1.length();
    258     sumWithOverflow(length, adapter2.length(), overflow);
    259     sumWithOverflow(length, adapter3.length(), overflow);
    260     sumWithOverflow(length, adapter4.length(), overflow);
    261     if (overflow)
    262         return 0;
    263     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    264     if (!resultImpl)
    265         return 0;
    266 
    267     UChar* result = buffer;
    268     adapter1.writeTo(result);
    269     result += adapter1.length();
    270     adapter2.writeTo(result);
    271     result += adapter2.length();
    272     adapter3.writeTo(result);
    273     result += adapter3.length();
    274     adapter4.writeTo(result);
    275 
    276     return resultImpl.release();
    277 }
    278 
    279 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
    280 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
    281 {
    282     StringTypeAdapter<StringType1> adapter1(string1);
    283     StringTypeAdapter<StringType2> adapter2(string2);
    284     StringTypeAdapter<StringType3> adapter3(string3);
    285     StringTypeAdapter<StringType4> adapter4(string4);
    286     StringTypeAdapter<StringType5> adapter5(string5);
    287 
    288     UChar* buffer;
    289     bool overflow = false;
    290     unsigned length = adapter1.length();
    291     sumWithOverflow(length, adapter2.length(), overflow);
    292     sumWithOverflow(length, adapter3.length(), overflow);
    293     sumWithOverflow(length, adapter4.length(), overflow);
    294     sumWithOverflow(length, adapter5.length(), overflow);
    295     if (overflow)
    296         return 0;
    297     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    298     if (!resultImpl)
    299         return 0;
    300 
    301     UChar* result = buffer;
    302     adapter1.writeTo(result);
    303     result += adapter1.length();
    304     adapter2.writeTo(result);
    305     result += adapter2.length();
    306     adapter3.writeTo(result);
    307     result += adapter3.length();
    308     adapter4.writeTo(result);
    309     result += adapter4.length();
    310     adapter5.writeTo(result);
    311 
    312     return resultImpl.release();
    313 }
    314 
    315 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
    316 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
    317 {
    318     StringTypeAdapter<StringType1> adapter1(string1);
    319     StringTypeAdapter<StringType2> adapter2(string2);
    320     StringTypeAdapter<StringType3> adapter3(string3);
    321     StringTypeAdapter<StringType4> adapter4(string4);
    322     StringTypeAdapter<StringType5> adapter5(string5);
    323     StringTypeAdapter<StringType6> adapter6(string6);
    324 
    325     UChar* buffer;
    326     bool overflow = false;
    327     unsigned length = adapter1.length();
    328     sumWithOverflow(length, adapter2.length(), overflow);
    329     sumWithOverflow(length, adapter3.length(), overflow);
    330     sumWithOverflow(length, adapter4.length(), overflow);
    331     sumWithOverflow(length, adapter5.length(), overflow);
    332     sumWithOverflow(length, adapter6.length(), overflow);
    333     if (overflow)
    334         return 0;
    335     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    336     if (!resultImpl)
    337         return 0;
    338 
    339     UChar* result = buffer;
    340     adapter1.writeTo(result);
    341     result += adapter1.length();
    342     adapter2.writeTo(result);
    343     result += adapter2.length();
    344     adapter3.writeTo(result);
    345     result += adapter3.length();
    346     adapter4.writeTo(result);
    347     result += adapter4.length();
    348     adapter5.writeTo(result);
    349     result += adapter5.length();
    350     adapter6.writeTo(result);
    351 
    352     return resultImpl.release();
    353 }
    354 
    355 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
    356 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
    357 {
    358     StringTypeAdapter<StringType1> adapter1(string1);
    359     StringTypeAdapter<StringType2> adapter2(string2);
    360     StringTypeAdapter<StringType3> adapter3(string3);
    361     StringTypeAdapter<StringType4> adapter4(string4);
    362     StringTypeAdapter<StringType5> adapter5(string5);
    363     StringTypeAdapter<StringType6> adapter6(string6);
    364     StringTypeAdapter<StringType7> adapter7(string7);
    365 
    366     UChar* buffer;
    367     bool overflow = false;
    368     unsigned length = adapter1.length();
    369     sumWithOverflow(length, adapter2.length(), overflow);
    370     sumWithOverflow(length, adapter3.length(), overflow);
    371     sumWithOverflow(length, adapter4.length(), overflow);
    372     sumWithOverflow(length, adapter5.length(), overflow);
    373     sumWithOverflow(length, adapter6.length(), overflow);
    374     sumWithOverflow(length, adapter7.length(), overflow);
    375     if (overflow)
    376         return 0;
    377     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    378     if (!resultImpl)
    379         return 0;
    380 
    381     UChar* result = buffer;
    382     adapter1.writeTo(result);
    383     result += adapter1.length();
    384     adapter2.writeTo(result);
    385     result += adapter2.length();
    386     adapter3.writeTo(result);
    387     result += adapter3.length();
    388     adapter4.writeTo(result);
    389     result += adapter4.length();
    390     adapter5.writeTo(result);
    391     result += adapter5.length();
    392     adapter6.writeTo(result);
    393     result += adapter6.length();
    394     adapter7.writeTo(result);
    395 
    396     return resultImpl.release();
    397 }
    398 
    399 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
    400 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
    401 {
    402     StringTypeAdapter<StringType1> adapter1(string1);
    403     StringTypeAdapter<StringType2> adapter2(string2);
    404     StringTypeAdapter<StringType3> adapter3(string3);
    405     StringTypeAdapter<StringType4> adapter4(string4);
    406     StringTypeAdapter<StringType5> adapter5(string5);
    407     StringTypeAdapter<StringType6> adapter6(string6);
    408     StringTypeAdapter<StringType7> adapter7(string7);
    409     StringTypeAdapter<StringType8> adapter8(string8);
    410 
    411     UChar* buffer;
    412     bool overflow = false;
    413     unsigned length = adapter1.length();
    414     sumWithOverflow(length, adapter2.length(), overflow);
    415     sumWithOverflow(length, adapter3.length(), overflow);
    416     sumWithOverflow(length, adapter4.length(), overflow);
    417     sumWithOverflow(length, adapter5.length(), overflow);
    418     sumWithOverflow(length, adapter6.length(), overflow);
    419     sumWithOverflow(length, adapter7.length(), overflow);
    420     sumWithOverflow(length, adapter8.length(), overflow);
    421     if (overflow)
    422         return 0;
    423     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    424     if (!resultImpl)
    425         return 0;
    426 
    427     UChar* result = buffer;
    428     adapter1.writeTo(result);
    429     result += adapter1.length();
    430     adapter2.writeTo(result);
    431     result += adapter2.length();
    432     adapter3.writeTo(result);
    433     result += adapter3.length();
    434     adapter4.writeTo(result);
    435     result += adapter4.length();
    436     adapter5.writeTo(result);
    437     result += adapter5.length();
    438     adapter6.writeTo(result);
    439     result += adapter6.length();
    440     adapter7.writeTo(result);
    441     result += adapter7.length();
    442     adapter8.writeTo(result);
    443 
    444     return resultImpl.release();
    445 }
    446 
    447 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
    448 PassRefPtr<StringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
    449 {
    450     StringTypeAdapter<StringType1> adapter1(string1);
    451     StringTypeAdapter<StringType2> adapter2(string2);
    452     StringTypeAdapter<StringType3> adapter3(string3);
    453     StringTypeAdapter<StringType4> adapter4(string4);
    454     StringTypeAdapter<StringType5> adapter5(string5);
    455     StringTypeAdapter<StringType6> adapter6(string6);
    456     StringTypeAdapter<StringType7> adapter7(string7);
    457     StringTypeAdapter<StringType8> adapter8(string8);
    458     StringTypeAdapter<StringType9> adapter9(string9);
    459 
    460     UChar* buffer;
    461     bool overflow = false;
    462     unsigned length = adapter1.length();
    463     sumWithOverflow(length, adapter2.length(), overflow);
    464     sumWithOverflow(length, adapter3.length(), overflow);
    465     sumWithOverflow(length, adapter4.length(), overflow);
    466     sumWithOverflow(length, adapter5.length(), overflow);
    467     sumWithOverflow(length, adapter6.length(), overflow);
    468     sumWithOverflow(length, adapter7.length(), overflow);
    469     sumWithOverflow(length, adapter8.length(), overflow);
    470     sumWithOverflow(length, adapter9.length(), overflow);
    471     if (overflow)
    472         return 0;
    473     RefPtr<StringImpl> resultImpl = StringImpl::tryCreateUninitialized(length, buffer);
    474     if (!resultImpl)
    475         return 0;
    476 
    477     UChar* result = buffer;
    478     adapter1.writeTo(result);
    479     result += adapter1.length();
    480     adapter2.writeTo(result);
    481     result += adapter2.length();
    482     adapter3.writeTo(result);
    483     result += adapter3.length();
    484     adapter4.writeTo(result);
    485     result += adapter4.length();
    486     adapter5.writeTo(result);
    487     result += adapter5.length();
    488     adapter6.writeTo(result);
    489     result += adapter6.length();
    490     adapter7.writeTo(result);
    491     result += adapter7.length();
    492     adapter8.writeTo(result);
    493     result += adapter8.length();
    494     adapter9.writeTo(result);
    495 
    496     return resultImpl.release();
    497 }
    498 
    499 
    500 // Convenience only.
    501 template<typename StringType1>
    502 String makeString(StringType1 string1)
    503 {
    504     return String(string1);
    505 }
    506 
    507 template<typename StringType1, typename StringType2>
    508 String makeString(StringType1 string1, StringType2 string2)
    509 {
    510     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2);
    511     if (!resultImpl)
    512         CRASH();
    513     return resultImpl.release();
    514 }
    515 
    516 template<typename StringType1, typename StringType2, typename StringType3>
    517 String makeString(StringType1 string1, StringType2 string2, StringType3 string3)
    518 {
    519     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3);
    520     if (!resultImpl)
    521         CRASH();
    522     return resultImpl.release();
    523 }
    524 
    525 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
    526 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
    527 {
    528     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4);
    529     if (!resultImpl)
    530         CRASH();
    531     return resultImpl.release();
    532 }
    533 
    534 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
    535 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
    536 {
    537     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5);
    538     if (!resultImpl)
    539         CRASH();
    540     return resultImpl.release();
    541 }
    542 
    543 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
    544 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
    545 {
    546     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6);
    547     if (!resultImpl)
    548         CRASH();
    549     return resultImpl.release();
    550 }
    551 
    552 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
    553 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
    554 {
    555     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7);
    556     if (!resultImpl)
    557         CRASH();
    558     return resultImpl.release();
    559 }
    560 
    561 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
    562 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
    563 {
    564     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
    565     if (!resultImpl)
    566         CRASH();
    567     return resultImpl.release();
    568 }
    569 
    570 template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8, typename StringType9>
    571 String makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8, StringType9 string9)
    572 {
    573     RefPtr<StringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8, string9);
    574     if (!resultImpl)
    575         CRASH();
    576     return resultImpl.release();
    577 }
    578 
    579 } // namespace WTF
    580 
    581 using WTF::makeString;
    582 
    583 #endif
    584