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