| Irrlicht 3D Engine |

irrString.h
Go to the documentation of this file.

    00001 // Copyright (C) 2002-2012 Nikolaus Gebhardt
    00002 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
    00003 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
    00004
    00005 #ifndef __IRR_STRING_H_INCLUDED__
    00006 #define __IRR_STRING_H_INCLUDED__
    00007
    00008 #include "irrTypes.h"
    00009 #include "irrAllocator.h"
    00010 #include "irrMath.h"
    00011 #include <stdio.h>
    00012 #include <string.h>
    00013 #include <stdlib.h>
    00014
    00015 namespace irr
    00016 {
    00017 namespace core
    00018 {
    00019
    00021
    00032 enum eLocaleID
    00033 {
    00034     IRR_LOCALE_ANSI = 0,
    00035     IRR_LOCALE_GERMAN = 1
    00036 };
    00037
    00038 static eLocaleID locale_current = IRR_LOCALE_ANSI;
    00039 static inline void locale_set ( eLocaleID id )
    00040 {
    00041     locale_current = id;
    00042 }
    00043
    00045 static inline u32 locale_lower ( u32 x )
    00046 {
    00047     switch ( locale_current )
    00048     {
    00049         case IRR_LOCALE_GERMAN:
    00050         case IRR_LOCALE_ANSI:
    00051             break;
    00052     }
    00053     // ansi
    00054     return x >= 'A' && x <= 'Z' ? x + 0x20 : x;
    00055 }
    00056
    00058 static inline u32 locale_upper ( u32 x )
    00059 {
    00060     switch ( locale_current )
    00061     {
    00062         case IRR_LOCALE_GERMAN:
    00063         case IRR_LOCALE_ANSI:
    00064             break;
    00065     }
    00066
    00067     // ansi
    00068     return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;
    00069 }
    00070
    00071
    00072 template <typename T, typename TAlloc = irrAllocator<T> >
    00073 class string
    00074 {
    00075 public:
    00076
    00077     typedef T char_type;
    00078
    00080     string()
    00081     : array(0), allocated(1), used(1)
    00082     {
    00083         array = allocator.allocate(1); // new T[1];
    00084         array[0] = 0;
    00085     }
    00086
    00087
    00089     string(const string<T,TAlloc>& other)
    00090     : array(0), allocated(0), used(0)
    00091     {
    00092         *this = other;
    00093     }
    00094
    00096     template <class B, class A>
    00097     string(const string<B, A>& other)
    00098     : array(0), allocated(0), used(0)
    00099     {
    00100         *this = other;
    00101     }
    00102
    00103
    00105     explicit string(const double number)
    00106     : array(0), allocated(0), used(0)
    00107     {
    00108         c8 tmpbuf[255];
    00109         snprintf(tmpbuf, 255, "%0.6f", number);
    00110         *this = tmpbuf;
    00111     }
    00112
    00113
    00115     explicit string(int number)
    00116     : array(0), allocated(0), used(0)
    00117     {
    00118         // store if negative and make positive
    00119
    00120         bool negative = false;
    00121         if (number < 0)
    00122         {
    00123             number *= -1;
    00124             negative = true;
    00125         }
    00126
    00127         // temporary buffer for 16 numbers
    00128
    00129         c8 tmpbuf[16]={0};
    00130         u32 idx = 15;
    00131
    00132         // special case '0'
    00133
    00134         if (!number)
    00135         {
    00136             tmpbuf[14] = '0';
    00137             *this = &tmpbuf[14];
    00138             return;
    00139         }
    00140
    00141         // add numbers
    00142
    00143         while(number && idx)
    00144         {
    00145             --idx;
    00146             tmpbuf[idx] = (c8)('0' + (number % 10));
    00147             number /= 10;
    00148         }
    00149
    00150         // add sign
    00151
    00152         if (negative)
    00153         {
    00154             --idx;
    00155             tmpbuf[idx] = '-';
    00156         }
    00157
    00158         *this = &tmpbuf[idx];
    00159     }
    00160
    00161
    00163     explicit string(unsigned int number)
    00164     : array(0), allocated(0), used(0)
    00165     {
    00166         // temporary buffer for 16 numbers
    00167
    00168         c8 tmpbuf[16]={0};
    00169         u32 idx = 15;
    00170
    00171         // special case '0'
    00172
    00173         if (!number)
    00174         {
    00175             tmpbuf[14] = '0';
    00176             *this = &tmpbuf[14];
    00177             return;
    00178         }
    00179
    00180         // add numbers
    00181
    00182         while(number && idx)
    00183         {
    00184             --idx;
    00185             tmpbuf[idx] = (c8)('0' + (number % 10));
    00186             number /= 10;
    00187         }
    00188
    00189         *this = &tmpbuf[idx];
    00190     }
    00191
    00192
    00194     explicit string(long number)
    00195     : array(0), allocated(0), used(0)
    00196     {
    00197         // store if negative and make positive
    00198
    00199         bool negative = false;
    00200         if (number < 0)
    00201         {
    00202             number *= -1;
    00203             negative = true;
    00204         }
    00205
    00206         // temporary buffer for 16 numbers
    00207
    00208         c8 tmpbuf[16]={0};
    00209         u32 idx = 15;
    00210
    00211         // special case '0'
    00212
    00213         if (!number)
    00214         {
    00215             tmpbuf[14] = '0';
    00216             *this = &tmpbuf[14];
    00217             return;
    00218         }
    00219
    00220         // add numbers
    00221
    00222         while(number && idx)
    00223         {
    00224             --idx;
    00225             tmpbuf[idx] = (c8)('0' + (number % 10));
    00226             number /= 10;
    00227         }
    00228
    00229         // add sign
    00230
    00231         if (negative)
    00232         {
    00233             --idx;
    00234             tmpbuf[idx] = '-';
    00235         }
    00236
    00237         *this = &tmpbuf[idx];
    00238     }
    00239
    00240
    00242     explicit string(unsigned long number)
    00243     : array(0), allocated(0), used(0)
    00244     {
    00245         // temporary buffer for 16 numbers
    00246
    00247         c8 tmpbuf[16]={0};
    00248         u32 idx = 15;
    00249
    00250         // special case '0'
    00251
    00252         if (!number)
    00253         {
    00254             tmpbuf[14] = '0';
    00255             *this = &tmpbuf[14];
    00256             return;
    00257         }
    00258
    00259         // add numbers
    00260
    00261         while(number && idx)
    00262         {
    00263             --idx;
    00264             tmpbuf[idx] = (c8)('0' + (number % 10));
    00265             number /= 10;
    00266         }
    00267
    00268         *this = &tmpbuf[idx];
    00269     }
    00270
    00271
    00273     template <class B>
    00274     string(const B* const c, u32 length)
    00275     : array(0), allocated(0), used(0)
    00276     {
    00277         if (!c)
    00278         {
    00279             // correctly init the string to an empty one
    00280             *this="";
    00281             return;
    00282         }
    00283
    00284         allocated = used = length+1;
    00285         array = allocator.allocate(used); // new T[used];
    00286
    00287         for (u32 l = 0; l<length; ++l)
    00288             array[l] = (T)c[l];
    00289
    00290         array[length] = 0;
    00291     }
    00292
    00293
    00295     template <class B>
    00296     string(const B* const c)
    00297     : array(0), allocated(0), used(0)
    00298     {
    00299         *this = c;
    00300     }
    00301
    00302
    00304     ~string()
    00305     {
    00306         allocator.deallocate(array); // delete [] array;
    00307     }
    00308
    00309
    00311     string<T,TAlloc>& operator=(const string<T,TAlloc>& other)
    00312     {
    00313         if (this == &other)
    00314             return *this;
    00315
    00316         used = other.size()+1;
    00317         if (used>allocated)
    00318         {
    00319             allocator.deallocate(array); // delete [] array;
    00320             allocated = used;
    00321             array = allocator.allocate(used); //new T[used];
    00322         }
    00323
    00324         const T* p = other.c_str();
    00325         for (u32 i=0; i<used; ++i, ++p)
    00326             array[i] = *p;
    00327
    00328         return *this;
    00329     }
    00330
    00332     template <class B, class A>
    00333     string<T,TAlloc>& operator=(const string<B,A>& other)
    00334     {
    00335         *this = other.c_str();
    00336         return *this;
    00337     }
    00338
    00339
    00341     template <class B>
    00342     string<T,TAlloc>& operator=(const B* const c)
    00343     {
    00344         if (!c)
    00345         {
    00346             if (!array)
    00347             {
    00348                 array = allocator.allocate(1); //new T[1];
    00349                 allocated = 1;
    00350             }
    00351             used = 1;
    00352             array[0] = 0x0;
    00353             return *this;
    00354         }
    00355
    00356         if ((void*)c == (void*)array)
    00357             return *this;
    00358
    00359         u32 len = 0;
    00360         const B* p = c;
    00361         do
    00362         {
    00363             ++len;
    00364         } while(*p++);
    00365
    00366         // we'll keep the old string for a while, because the new
    00367         // string could be a part of the current string.
    00368         T* oldArray = array;
    00369
    00370         used = len;
    00371         if (used>allocated)
    00372         {
    00373             allocated = used;
    00374             array = allocator.allocate(used); //new T[used];
    00375         }
    00376
    00377         for (u32 l = 0; l<len; ++l)
    00378             array[l] = (T)c[l];
    00379
    00380         if (oldArray != array)
    00381             allocator.deallocate(oldArray); // delete [] oldArray;
    00382
    00383         return *this;
    00384     }
    00385
    00386
    00388     string<T,TAlloc> operator+(const string<T,TAlloc>& other) const
    00389     {
    00390         string<T,TAlloc> str(*this);
    00391         str.append(other);
    00392
    00393         return str;
    00394     }
    00395
    00396
    00398     template <class B>
    00399     string<T,TAlloc> operator+(const B* const c) const
    00400     {
    00401         string<T,TAlloc> str(*this);
    00402         str.append(c);
    00403
    00404         return str;
    00405     }
    00406
    00407
    00409     T& operator [](const u32 index)
    00410     {
    00411         _IRR_DEBUG_BREAK_IF(index>=used) // bad index
    00412         return array[index];
    00413     }
    00414
    00415
    00417     const T& operator [](const u32 index) const
    00418     {
    00419         _IRR_DEBUG_BREAK_IF(index>=used) // bad index
    00420         return array[index];
    00421     }
    00422
    00423
    00425     bool operator==(const T* const str) const
    00426     {
    00427         if (!str)
    00428             return false;
    00429
    00430         u32 i;
    00431         for (i=0; array[i] && str[i]; ++i)
    00432             if (array[i] != str[i])
    00433                 return false;
    00434
    00435         return (!array[i] && !str[i]);
    00436     }
    00437
    00438
    00440     bool operator==(const string<T,TAlloc>& other) const
    00441     {
    00442         for (u32 i=0; array[i] && other.array[i]; ++i)
    00443             if (array[i] != other.array[i])
    00444                 return false;
    00445
    00446         return used == other.used;
    00447     }
    00448
    00449
    00451     bool operator<(const string<T,TAlloc>& other) const
    00452     {
    00453         for (u32 i=0; array[i] && other.array[i]; ++i)
    00454         {
    00455             const s32 diff = array[i] - other.array[i];
    00456             if (diff)
    00457                 return (diff < 0);
    00458         }
    00459
    00460         return (used < other.used);
    00461     }
    00462
    00463
    00465     bool operator!=(const T* const str) const
    00466     {
    00467         return !(*this == str);
    00468     }
    00469
    00470
    00472     bool operator!=(const string<T,TAlloc>& other) const
    00473     {
    00474         return !(*this == other);
    00475     }
    00476
    00477
    00479
    00481     u32 size() const
    00482     {
    00483         return used-1;
    00484     }
    00485
    00488     bool empty() const
    00489     {
    00490         return (size() == 0);
    00491     }
    00492
    00494
    00495     const T* c_str() const
    00496     {
    00497         return array;
    00498     }
    00499
    00500
    00502     string<T,TAlloc>& make_lower()
    00503     {
    00504         for (u32 i=0; array[i]; ++i)
    00505             array[i] = locale_lower ( array[i] );
    00506         return *this;
    00507     }
    00508
    00509
    00511     string<T,TAlloc>& make_upper()
    00512     {
    00513         for (u32 i=0; array[i]; ++i)
    00514             array[i] = locale_upper ( array[i] );
    00515         return *this;
    00516     }
    00517
    00518
    00520
    00522     bool equals_ignore_case(const string<T,TAlloc>& other) const
    00523     {
    00524         for(u32 i=0; array[i] && other[i]; ++i)
    00525             if (locale_lower( array[i]) != locale_lower(other[i]))
    00526                 return false;
    00527
    00528         return used == other.used;
    00529     }
    00530
    00532
    00535     bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const
    00536     {
    00537         if ( (u32) sourcePos >= used )
    00538             return false;
    00539
    00540         u32 i;
    00541         for( i=0; array[sourcePos + i] && other[i]; ++i)
    00542             if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
    00543                 return false;
    00544
    00545         return array[sourcePos + i] == 0 && other[i] == 0;
    00546     }
    00547
    00548
    00550
    00552     bool lower_ignore_case(const string<T,TAlloc>& other) const
    00553     {
    00554         for(u32 i=0; array[i] && other.array[i]; ++i)
    00555         {
    00556             s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
    00557             if ( diff )
    00558                 return diff < 0;
    00559         }
    00560
    00561         return used < other.used;
    00562     }
    00563
    00564
    00566
    00569     bool equalsn(const string<T,TAlloc>& other, u32 n) const
    00570     {
    00571         u32 i;
    00572         for(i=0; array[i] && other[i] && i < n; ++i)
    00573             if (array[i] != other[i])
    00574                 return false;
    00575
    00576         // if one (or both) of the strings was smaller then they
    00577         // are only equal if they have the same length
    00578         return (i == n) || (used == other.used);
    00579     }
    00580
    00581
    00583
    00586     bool equalsn(const T* const str, u32 n) const
    00587     {
    00588         if (!str)
    00589             return false;
    00590         u32 i;
    00591         for(i=0; array[i] && str[i] && i < n; ++i)
    00592             if (array[i] != str[i])
    00593                 return false;
    00594
    00595         // if one (or both) of the strings was smaller then they
    00596         // are only equal if they have the same length
    00597         return (i == n) || (array[i] == 0 && str[i] == 0);
    00598     }
    00599
    00600
    00602
    00603     string<T,TAlloc>& append(T character)
    00604     {
    00605         if (used + 1 > allocated)
    00606             reallocate(used + 1);
    00607
    00608         ++used;
    00609
    00610         array[used-2] = character;
    00611         array[used-1] = 0;
    00612
    00613         return *this;
    00614     }
    00615
    00616
    00618
    00620     string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)
    00621     {
    00622         if (!other)
    00623             return *this;
    00624
    00625         u32 len = 0;
    00626         const T* p = other;
    00627         while(*p)
    00628         {
    00629             ++len;
    00630             ++p;
    00631         }
    00632         if (len > length)
    00633             len = length;
    00634
    00635         if (used + len > allocated)
    00636             reallocate(used + len);
    00637
    00638         --used;
    00639         ++len;
    00640
    00641         for (u32 l=0; l<len; ++l)
    00642             array[l+used] = *(other+l);
    00643
    00644         used += len;
    00645
    00646         return *this;
    00647     }
    00648
    00649
    00651
    00652     string<T,TAlloc>& append(const string<T,TAlloc>& other)
    00653     {
    00654         if (other.size() == 0)
    00655             return *this;
    00656
    00657         --used;
    00658         u32 len = other.size()+1;
    00659
    00660         if (used + len > allocated)
    00661             reallocate(used + len);
    00662
    00663         for (u32 l=0; l<len; ++l)
    00664             array[used+l] = other[l];
    00665
    00666         used += len;
    00667
    00668         return *this;
    00669     }
    00670
    00671
    00673
    00675     string<T,TAlloc>& append(const string<T,TAlloc>& other, u32 length)
    00676     {
    00677         if (other.size() == 0)
    00678             return *this;
    00679
    00680         if (other.size() < length)
    00681         {
    00682             append(other);
    00683             return *this;
    00684         }
    00685
    00686         if (used + length > allocated)
    00687             reallocate(used + length);
    00688
    00689         --used;
    00690
    00691         for (u32 l=0; l<length; ++l)
    00692             array[l+used] = other[l];
    00693         used += length;
    00694
    00695         // ensure proper termination
    00696         array[used]=0;
    00697         ++used;
    00698
    00699         return *this;
    00700     }
    00701
    00702
    00704
    00705     void reserve(u32 count)
    00706     {
    00707         if (count < allocated)
    00708             return;
    00709
    00710         reallocate(count);
    00711     }
    00712
    00713
    00715
    00718     s32 findFirst(T c) const
    00719     {
    00720         for (u32 i=0; i<used-1; ++i)
    00721             if (array[i] == c)
    00722                 return i;
    00723
    00724         return -1;
    00725     }
    00726
    00728
    00734     s32 findFirstChar(const T* const c, u32 count=1) const
    00735     {
    00736         if (!c || !count)
    00737             return -1;
    00738
    00739         for (u32 i=0; i<used-1; ++i)
    00740             for (u32 j=0; j<count; ++j)
    00741                 if (array[i] == c[j])
    00742                     return i;
    00743
    00744         return -1;
    00745     }
    00746
    00747
    00749
    00755     template <class B>
    00756     s32 findFirstCharNotInList(const B* const c, u32 count=1) const
    00757     {
    00758         if (!c || !count)
    00759             return -1;
    00760
    00761         for (u32 i=0; i<used-1; ++i)
    00762         {
    00763             u32 j;
    00764             for (j=0; j<count; ++j)
    00765                 if (array[i] == c[j])
    00766                     break;
    00767
    00768             if (j==count)
    00769                 return i;
    00770         }
    00771
    00772         return -1;
    00773     }
    00774
    00776
    00782     template <class B>
    00783     s32 findLastCharNotInList(const B* const c, u32 count=1) const
    00784     {
    00785         if (!c || !count)
    00786             return -1;
    00787
    00788         for (s32 i=(s32)(used-2); i>=0; --i)
    00789         {
    00790             u32 j;
    00791             for (j=0; j<count; ++j)
    00792                 if (array[i] == c[j])
    00793                     break;
    00794
    00795             if (j==count)
    00796                 return i;
    00797         }
    00798
    00799         return -1;
    00800     }
    00801
    00803
    00807     s32 findNext(T c, u32 startPos) const
    00808     {
    00809         for (u32 i=startPos; i<used-1; ++i)
    00810             if (array[i] == c)
    00811                 return i;
    00812
    00813         return -1;
    00814     }
    00815
    00816
    00818
    00822     s32 findLast(T c, s32 start = -1) const
    00823     {
    00824         start = core::clamp ( start < 0 ? (s32)(used) - 2 : start, 0, (s32)(used) - 2 );
    00825         for (s32 i=start; i>=0; --i)
    00826             if (array[i] == c)
    00827                 return i;
    00828
    00829         return -1;
    00830     }
    00831
    00833
    00839     s32 findLastChar(const T* const c, u32 count=1) const
    00840     {
    00841         if (!c || !count)
    00842             return -1;
    00843
    00844         for (s32 i=(s32)used-2; i>=0; --i)
    00845             for (u32 j=0; j<count; ++j)
    00846                 if (array[i] == c[j])
    00847                     return i;
    00848
    00849         return -1;
    00850     }
    00851
    00852
    00854
    00858     template <class B>
    00859     s32 find(const B* const str, const u32 start = 0) const
    00860     {
    00861         if (str && *str)
    00862         {
    00863             u32 len = 0;
    00864
    00865             while (str[len])
    00866                 ++len;
    00867
    00868             if (len > used-1)
    00869                 return -1;
    00870
    00871             for (u32 i=start; i<used-len; ++i)
    00872             {
    00873                 u32 j=0;
    00874
    00875                 while(str[j] && array[i+j] == str[j])
    00876                     ++j;
    00877
    00878                 if (!str[j])
    00879                     return i;
    00880             }
    00881         }
    00882
    00883         return -1;
    00884     }
    00885
    00886
    00888
    00891     string<T> subString(u32 begin, s32 length, bool make_lower = false ) const
    00892     {
    00893         // if start after string
    00894         // or no proper substring length
    00895         if ((length <= 0) || (begin>=size()))
    00896             return string<T>("");
    00897         // clamp length to maximal value
    00898         if ((length+begin) > size())
    00899             length = size()-begin;
    00900
    00901         string<T> o;
    00902         o.reserve(length+1);
    00903
    00904         s32 i;
    00905         if ( !make_lower )
    00906         {
    00907             for (i=0; i<length; ++i)
    00908                 o.array[i] = array[i+begin];
    00909         }
    00910         else
    00911         {
    00912             for (i=0; i<length; ++i)
    00913                 o.array[i] = locale_lower ( array[i+begin] );
    00914         }
    00915
    00916         o.array[length] = 0;
    00917         o.used = length + 1;
    00918
    00919         return o;
    00920     }
    00921
    00922
    00924
    00925     string<T,TAlloc>& operator += (T c)
    00926     {
    00927         append(c);
    00928         return *this;
    00929     }
    00930
    00931
    00933
    00934     string<T,TAlloc>& operator += (const T* const c)
    00935     {
    00936         append(c);
    00937         return *this;
    00938     }
    00939
    00940
    00942
    00943     string<T,TAlloc>& operator += (const string<T,TAlloc>& other)
    00944     {
    00945         append(other);
    00946         return *this;
    00947     }
    00948
    00949
    00951
    00952     string<T,TAlloc>& operator += (const int i)
    00953     {
    00954         append(string<T,TAlloc>(i));
    00955         return *this;
    00956     }
    00957
    00958
    00960
    00961     string<T,TAlloc>& operator += (const unsigned int i)
    00962     {
    00963         append(string<T,TAlloc>(i));
    00964         return *this;
    00965     }
    00966
    00967
    00969
    00970     string<T,TAlloc>& operator += (const long i)
    00971     {
    00972         append(string<T,TAlloc>(i));
    00973         return *this;
    00974     }
    00975
    00976
    00978
    00979     string<T,TAlloc>& operator += (const unsigned long i)
    00980     {
    00981         append(string<T,TAlloc>(i));
    00982         return *this;
    00983     }
    00984
    00985
    00987
    00988     string<T,TAlloc>& operator += (const double i)
    00989     {
    00990         append(string<T,TAlloc>(i));
    00991         return *this;
    00992     }
    00993
    00994
    00996
    00997     string<T,TAlloc>& operator += (const float i)
    00998     {
    00999         append(string<T,TAlloc>(i));
    01000         return *this;
    01001     }
    01002
    01003
    01005
    01007     string<T,TAlloc>& replace(T toReplace, T replaceWith)
    01008     {
    01009         for (u32 i=0; i<used-1; ++i)
    01010             if (array[i] == toReplace)
    01011                 array[i] = replaceWith;
    01012         return *this;
    01013     }
    01014
    01015
    01017
    01019     string<T,TAlloc>& replace(const string<T,TAlloc>& toReplace, const string<T,TAlloc>& replaceWith)
    01020     {
    01021         if (toReplace.size() == 0)
    01022             return *this;
    01023
    01024         const T* other = toReplace.c_str();
    01025         const T* replace = replaceWith.c_str();
    01026         const u32 other_size = toReplace.size();
    01027         const u32 replace_size = replaceWith.size();
    01028
    01029         // Determine the delta.  The algorithm will change depending on the delta.
    01030         s32 delta = replace_size - other_size;
    01031
    01032         // A character for character replace.  The string will not shrink or grow.
    01033         if (delta == 0)
    01034         {
    01035             s32 pos = 0;
    01036             while ((pos = find(other, pos)) != -1)
    01037             {
    01038                 for (u32 i = 0; i < replace_size; ++i)
    01039                     array[pos + i] = replace[i];
    01040                 ++pos;
    01041             }
    01042             return *this;
    01043         }
    01044
    01045         // We are going to be removing some characters.  The string will shrink.
    01046         if (delta < 0)
    01047         {
    01048             u32 i = 0;
    01049             for (u32 pos = 0; pos < used; ++i, ++pos)
    01050             {
    01051                 // Is this potentially a match?
    01052                 if (array[pos] == *other)
    01053                 {
    01054                     // Check to see if we have a match.
    01055                     u32 j;
    01056                     for (j = 0; j < other_size; ++j)
    01057                     {
    01058                         if (array[pos + j] != other[j])
    01059                             break;
    01060                     }
    01061
    01062                     // If we have a match, replace characters.
    01063                     if (j == other_size)
    01064                     {
    01065                         for (j = 0; j < replace_size; ++j)
    01066                             array[i + j] = replace[j];
    01067                         i += replace_size - 1;
    01068                         pos += other_size - 1;
    01069                         continue;
    01070                     }
    01071                 }
    01072
    01073                 // No match found, just copy characters.
    01074                 array[i] = array[pos];
    01075             }
    01076             array[i-1] = 0;
    01077             used = i;
    01078
    01079             return *this;
    01080         }
    01081
    01082         // We are going to be adding characters, so the string size will increase.
    01083         // Count the number of times toReplace exists in the string so we can allocate the new size.
    01084         u32 find_count = 0;
    01085         s32 pos = 0;
    01086         while ((pos = find(other, pos)) != -1)
    01087         {
    01088             ++find_count;
    01089             ++pos;
    01090         }
    01091
    01092         // Re-allocate the string now, if needed.
    01093         u32 len = delta * find_count;
    01094         if (used + len > allocated)
    01095             reallocate(used + len);
    01096
    01097         // Start replacing.
    01098         pos = 0;
    01099         while ((pos = find(other, pos)) != -1)
    01100         {
    01101             T* start = array + pos + other_size - 1;
    01102             T* ptr   = array + used - 1;
    01103             T* end   = array + delta + used -1;
    01104
    01105             // Shift characters to make room for the string.
    01106             while (ptr != start)
    01107             {
    01108                 *end = *ptr;
    01109                 --ptr;
    01110                 --end;
    01111             }
    01112
    01113             // Add the new string now.
    01114             for (u32 i = 0; i < replace_size; ++i)
    01115                 array[pos + i] = replace[i];
    01116
    01117             pos += replace_size;
    01118             used += delta;
    01119         }
    01120
    01121         return *this;
    01122     }
    01123
    01124
    01126
    01127     string<T,TAlloc>& remove(T c)
    01128     {
    01129         u32 pos = 0;
    01130         u32 found = 0;
    01131         for (u32 i=0; i<used-1; ++i)
    01132         {
    01133             if (array[i] == c)
    01134             {
    01135                 ++found;
    01136                 continue;
    01137             }
    01138
    01139             array[pos++] = array[i];
    01140         }
    01141         used -= found;
    01142         array[used-1] = 0;
    01143         return *this;
    01144     }
    01145
    01146
    01148
    01149     string<T,TAlloc>& remove(const string<T,TAlloc>& toRemove)
    01150     {
    01151         u32 size = toRemove.size();
    01152         if ( size == 0 )
    01153             return *this;
    01154         u32 pos = 0;
    01155         u32 found = 0;
    01156         for (u32 i=0; i<used-1; ++i)
    01157         {
    01158             u32 j = 0;
    01159             while (j < size)
    01160             {
    01161                 if (array[i + j] != toRemove[j])
    01162                     break;
    01163                 ++j;
    01164             }
    01165             if (j == size)
    01166             {
    01167                 found += size;
    01168                 i += size - 1;
    01169                 continue;
    01170             }
    01171
    01172             array[pos++] = array[i];
    01173         }
    01174         used -= found;
    01175         array[used-1] = 0;
    01176         return *this;
    01177     }
    01178
    01179
    01181
    01182     string<T,TAlloc>& removeChars(const string<T,TAlloc> & characters)
    01183     {
    01184         if (characters.size() == 0)
    01185             return *this;
    01186
    01187         u32 pos = 0;
    01188         u32 found = 0;
    01189         for (u32 i=0; i<used-1; ++i)
    01190         {
    01191             // Don't use characters.findFirst as it finds the \0,
    01192             // causing used to become incorrect.
    01193             bool docontinue = false;
    01194             for (u32 j=0; j<characters.size(); ++j)
    01195             {
    01196                 if (characters[j] == array[i])
    01197                 {
    01198                     ++found;
    01199                     docontinue = true;
    01200                     break;
    01201                 }
    01202             }
    01203             if (docontinue)
    01204                 continue;
    01205
    01206             array[pos++] = array[i];
    01207         }
    01208         used -= found;
    01209         array[used-1] = 0;
    01210
    01211         return *this;
    01212     }
    01213
    01214
    01216
    01218     string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
    01219     {
    01220         // find start and end of the substring without the specified characters
    01221         const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
    01222         if (begin == -1)
    01223             return (*this="");
    01224
    01225         const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
    01226
    01227         return (*this = subString(begin, (end +1) - begin));
    01228     }
    01229
    01230
    01232
    01235     string<T,TAlloc>& erase(u32 index)
    01236     {
    01237         _IRR_DEBUG_BREAK_IF(index>=used) // access violation
    01238
    01239         for (u32 i=index+1; i<used; ++i)
    01240             array[i-1] = array[i];
    01241
    01242         --used;
    01243         return *this;
    01244     }
    01245
    01247     string<T,TAlloc>& validate()
    01248     {
    01249         // terminate on existing null
    01250         for (u32 i=0; i<allocated; ++i)
    01251         {
    01252             if (array[i] == 0)
    01253             {
    01254                 used = i + 1;
    01255                 return *this;
    01256             }
    01257         }
    01258
    01259         // terminate
    01260         if ( allocated > 0 )
    01261         {
    01262             used = allocated;
    01263             array[used-1] = 0;
    01264         }
    01265         else
    01266         {
    01267             used = 0;
    01268         }
    01269
    01270         return *this;
    01271     }
    01272
    01274     T lastChar() const
    01275     {
    01276         return used > 1 ? array[used-2] : 0;
    01277     }
    01278
    01280
    01297     template<class container>
    01298     u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
    01299     {
    01300         if (!c)
    01301             return 0;
    01302
    01303         const u32 oldSize=ret.size();
    01304         u32 lastpos = 0;
    01305         bool lastWasSeparator = false;
    01306         for (u32 i=0; i<used; ++i)
    01307         {
    01308             bool foundSeparator = false;
    01309             for (u32 j=0; j<count; ++j)
    01310             {
    01311                 if (array[i] == c[j])
    01312                 {
    01313                     if ((!ignoreEmptyTokens || i - lastpos != 0) &&
    01314                             !lastWasSeparator)
    01315                         ret.push_back(string<T,TAlloc>(&array[lastpos], i - lastpos));
    01316                     foundSeparator = true;
    01317                     lastpos = (keepSeparators ? i : i + 1);
    01318                     break;
    01319                 }
    01320             }
    01321             lastWasSeparator = foundSeparator;
    01322         }
    01323         if ((used - 1) > lastpos)
    01324             ret.push_back(string<T,TAlloc>(&array[lastpos], (used - 1) - lastpos));
    01325         return ret.size()-oldSize;
    01326     }
    01327
    01328 private:
    01329
    01331     void reallocate(u32 new_size)
    01332     {
    01333         T* old_array = array;
    01334
    01335         array = allocator.allocate(new_size); //new T[new_size];
    01336         allocated = new_size;
    01337
    01338         u32 amount = used < new_size ? used : new_size;
    01339         for (u32 i=0; i<amount; ++i)
    01340             array[i] = old_array[i];
    01341
    01342         if (allocated < used)
    01343             used = allocated;
    01344
    01345         allocator.deallocate(old_array); // delete [] old_array;
    01346     }
    01347
    01348     //--- member variables
    01349
    01350     T* array;
    01351     u32 allocated;
    01352     u32 used;
    01353     TAlloc allocator;
    01354 };
    01355
    01356
    01358 typedef string<c8> stringc;
    01359
    01361 typedef string<wchar_t> stringw;
    01362
    01363
    01364 } // end namespace core
    01365 } // end namespace irr
    01366
    01367 #endif
    01368