IrrlichtEngine
irrString.h
Go to the documentation of this file.
00001 // Copyright (C) 2002-2011 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; i<used; ++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; i<used; ++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; ++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; ++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; ++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) - 1 : start, 0, (s32)(used) - 1 );
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=used-1; 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; ++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                 // Don't take the string terminator into account.
01098                 --used;
01099 
01100                 // Start replacing.
01101                 pos = 0;
01102                 while ((pos = find(other, pos)) != -1)
01103                 {
01104                         T* start = array + pos + other_size - 1;
01105                         T* ptr   = array + used;
01106                         T* end   = array + used + delta;
01107 
01108                         // Shift characters to make room for the string.
01109                         while (ptr != start)
01110                         {
01111                                 *end = *ptr;
01112                                 --ptr;
01113                                 --end;
01114                         }
01115 
01116                         // Add the new string now.
01117                         for (u32 i = 0; i < replace_size; ++i)
01118                                 array[pos + i] = replace[i];
01119 
01120                         pos += replace_size;
01121                         used += delta;
01122                 }
01123 
01124                 // Terminate the string and return ourself.
01125                 array[used] = 0;
01126                 ++used;
01127                 return *this;
01128         }
01129 
01130 
01132 
01133         string<T,TAlloc>& remove(T c)
01134         {
01135                 u32 pos = 0;
01136                 u32 found = 0;
01137                 for (u32 i=0; i<used; ++i)
01138                 {
01139                         if (array[i] == c)
01140                         {
01141                                 ++found;
01142                                 continue;
01143                         }
01144 
01145                         array[pos++] = array[i];
01146                 }
01147                 used -= found;
01148                 array[used-1] = 0;
01149                 return *this;
01150         }
01151 
01152 
01154 
01155         string<T,TAlloc>& remove(const string<T,TAlloc>& toRemove)
01156         {
01157                 u32 size = toRemove.size();
01158                 if ( size == 0 )
01159                         return *this;
01160                 u32 pos = 0;
01161                 u32 found = 0;
01162                 for (u32 i=0; i<used; ++i)
01163                 {
01164                         u32 j = 0;
01165                         while (j < size)
01166                         {
01167                                 if (array[i + j] != toRemove[j])
01168                                         break;
01169                                 ++j;
01170                         }
01171                         if (j == size)
01172                         {
01173                                 found += size;
01174                                 i += size - 1;
01175                                 continue;
01176                         }
01177 
01178                         array[pos++] = array[i];
01179                 }
01180                 used -= found;
01181                 array[used-1] = 0;
01182                 return *this;
01183         }
01184 
01185 
01187 
01188         string<T,TAlloc>& removeChars(const string<T,TAlloc> & characters)
01189         {
01190                 if (characters.size() == 0)
01191                         return *this;
01192 
01193                 u32 pos = 0;
01194                 u32 found = 0;
01195                 for (u32 i=0; i<used; ++i)
01196                 {
01197                         // Don't use characters.findFirst as it finds the \0,
01198                         // causing used to become incorrect.
01199                         bool docontinue = false;
01200                         for (u32 j=0; j<characters.size(); ++j)
01201                         {
01202                                 if (characters[j] == array[i])
01203                                 {
01204                                         ++found;
01205                                         docontinue = true;
01206                                         break;
01207                                 }
01208                         }
01209                         if (docontinue)
01210                                 continue;
01211 
01212                         array[pos++] = array[i];
01213                 }
01214                 used -= found;
01215                 array[used-1] = 0;
01216 
01217                 return *this;
01218         }
01219 
01220 
01222 
01224         string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
01225         {
01226                 // find start and end of the substring without the specified characters
01227                 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
01228                 if (begin == -1)
01229                         return (*this="");
01230 
01231                 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
01232 
01233                 return (*this = subString(begin, (end +1) - begin));
01234         }
01235 
01236 
01238 
01241         string<T,TAlloc>& erase(u32 index)
01242         {
01243                 _IRR_DEBUG_BREAK_IF(index>=used) // access violation
01244 
01245                 for (u32 i=index+1; i<used; ++i)
01246                         array[i-1] = array[i];
01247 
01248                 --used;
01249                 return *this;
01250         }
01251 
01253         string<T,TAlloc>& validate()
01254         {
01255                 // terminate on existing null
01256                 for (u32 i=0; i<allocated; ++i)
01257                 {
01258                         if (array[i] == 0)
01259                         {
01260                                 used = i + 1;
01261                                 return *this;
01262                         }
01263                 }
01264 
01265                 // terminate
01266                 if ( allocated > 0 )
01267                 {
01268                         used = allocated;
01269                         array[used-1] = 0;
01270                 }
01271                 else
01272                 {
01273                         used = 0;
01274                 }
01275 
01276                 return *this;
01277         }
01278 
01280         T lastChar() const
01281         {
01282                 return used > 1 ? array[used-2] : 0;
01283         }
01284 
01286 
01303         template<class container>
01304         u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
01305         {
01306                 if (!c)
01307                         return 0;
01308 
01309                 const u32 oldSize=ret.size();
01310                 u32 lastpos = 0;
01311                 bool lastWasSeparator = false;
01312                 for (u32 i=0; i<used; ++i)
01313                 {
01314                         bool foundSeparator = false;
01315                         for (u32 j=0; j<count; ++j)
01316                         {
01317                                 if (array[i] == c[j])
01318                                 {
01319                                         if ((!ignoreEmptyTokens || i - lastpos != 0) &&
01320                                                         !lastWasSeparator)
01321                                                 ret.push_back(string<T,TAlloc>(&array[lastpos], i - lastpos));
01322                                         foundSeparator = true;
01323                                         lastpos = (keepSeparators ? i : i + 1);
01324                                         break;
01325                                 }
01326                         }
01327                         lastWasSeparator = foundSeparator;
01328                 }
01329                 if ((used - 1) > lastpos)
01330                         ret.push_back(string<T,TAlloc>(&array[lastpos], (used - 1) - lastpos));
01331                 return ret.size()-oldSize;
01332         }
01333 
01334 private:
01335 
01337         void reallocate(u32 new_size)
01338         {
01339                 T* old_array = array;
01340 
01341                 array = allocator.allocate(new_size); //new T[new_size];
01342                 allocated = new_size;
01343 
01344                 u32 amount = used < new_size ? used : new_size;
01345                 for (u32 i=0; i<amount; ++i)
01346                         array[i] = old_array[i];
01347 
01348                 if (allocated < used)
01349                         used = allocated;
01350 
01351                 allocator.deallocate(old_array); // delete [] old_array;
01352         }
01353 
01354         //--- member variables
01355 
01356         T* array;
01357         u32 allocated;
01358         u32 used;
01359         TAlloc allocator;
01360 };
01361 
01362 
01364 typedef string<c8> stringc;
01365 
01367 typedef string<wchar_t> stringw;
01368 
01369 
01370 } // end namespace core
01371 } // end namespace irr
01372 
01373 #endif
01374