00001
00002
00003
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
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
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
00078 string()
00079 : array(0), allocated(1), used(1)
00080 {
00081 array = allocator.allocate(1);
00082 array[0] = 0x0;
00083 }
00084
00085
00087 string(const string<T,TAlloc>& other)
00088 : array(0), allocated(0), used(0)
00089 {
00090 *this = other;
00091 }
00092
00094 template <class B, class A>
00095 string(const string<B, A>& other)
00096 : array(0), allocated(0), used(0)
00097 {
00098 *this = other;
00099 }
00100
00101
00103 explicit string(const double number)
00104 : array(0), allocated(0), used(0)
00105 {
00106 c8 tmpbuf[255];
00107 snprintf(tmpbuf, 255, "%0.6f", number);
00108 *this = tmpbuf;
00109 }
00110
00111
00113 explicit string(int number)
00114 : array(0), allocated(0), used(0)
00115 {
00116
00117
00118 bool negative = false;
00119 if (number < 0)
00120 {
00121 number *= -1;
00122 negative = true;
00123 }
00124
00125
00126
00127 c8 tmpbuf[16]={0};
00128 u32 idx = 15;
00129
00130
00131
00132 if (!number)
00133 {
00134 tmpbuf[14] = '0';
00135 *this = &tmpbuf[14];
00136 return;
00137 }
00138
00139
00140
00141 while(number && idx)
00142 {
00143 --idx;
00144 tmpbuf[idx] = (c8)('0' + (number % 10));
00145 number /= 10;
00146 }
00147
00148
00149
00150 if (negative)
00151 {
00152 --idx;
00153 tmpbuf[idx] = '-';
00154 }
00155
00156 *this = &tmpbuf[idx];
00157 }
00158
00159
00161 explicit string(unsigned int number)
00162 : array(0), allocated(0), used(0)
00163 {
00164
00165
00166 c8 tmpbuf[16]={0};
00167 u32 idx = 15;
00168
00169
00170
00171 if (!number)
00172 {
00173 tmpbuf[14] = '0';
00174 *this = &tmpbuf[14];
00175 return;
00176 }
00177
00178
00179
00180 while(number && idx)
00181 {
00182 --idx;
00183 tmpbuf[idx] = (c8)('0' + (number % 10));
00184 number /= 10;
00185 }
00186
00187 *this = &tmpbuf[idx];
00188 }
00189
00190
00192 template <class B>
00193 string(const B* const c, u32 length)
00194 : array(0), allocated(0), used(0)
00195 {
00196 if (!c)
00197 {
00198
00199 *this="";
00200 return;
00201 }
00202
00203 allocated = used = length+1;
00204 array = allocator.allocate(used);
00205
00206 for (u32 l = 0; l<length; ++l)
00207 array[l] = (T)c[l];
00208
00209 array[length] = 0;
00210 }
00211
00212
00214 template <class B>
00215 string(const B* const c)
00216 : array(0), allocated(0), used(0)
00217 {
00218 *this = c;
00219 }
00220
00221
00223 ~string()
00224 {
00225 allocator.deallocate(array);
00226 }
00227
00228
00230 string<T,TAlloc>& operator=(const string<T,TAlloc>& other)
00231 {
00232 if (this == &other)
00233 return *this;
00234
00235 used = other.size()+1;
00236 if (used>allocated)
00237 {
00238 allocator.deallocate(array);
00239 allocated = used;
00240 array = allocator.allocate(used);
00241 }
00242
00243 const T* p = other.c_str();
00244 for (u32 i=0; i<used; ++i, ++p)
00245 array[i] = *p;
00246
00247 return *this;
00248 }
00249
00251 template <class B, class A>
00252 string<T,TAlloc>& operator=(const string<B,A>& other)
00253 {
00254 *this = other.c_str();
00255 return *this;
00256 }
00257
00258
00260 template <class B>
00261 string<T,TAlloc>& operator=(const B* const c)
00262 {
00263 if (!c)
00264 {
00265 if (!array)
00266 {
00267 array = allocator.allocate(1);
00268 allocated = 1;
00269 }
00270 used = 1;
00271 array[0] = 0x0;
00272 return *this;
00273 }
00274
00275 if ((void*)c == (void*)array)
00276 return *this;
00277
00278 u32 len = 0;
00279 const B* p = c;
00280 do
00281 {
00282 ++len;
00283 } while(*p++);
00284
00285
00286
00287 T* oldArray = array;
00288
00289 used = len;
00290 if (used>allocated)
00291 {
00292 allocated = used;
00293 array = allocator.allocate(used);
00294 }
00295
00296 for (u32 l = 0; l<len; ++l)
00297 array[l] = (T)c[l];
00298
00299 if (oldArray != array)
00300 allocator.deallocate(oldArray);
00301
00302 return *this;
00303 }
00304
00305
00307 string<T,TAlloc> operator+(const string<T,TAlloc>& other) const
00308 {
00309 string<T,TAlloc> str(*this);
00310 str.append(other);
00311
00312 return str;
00313 }
00314
00315
00317 template <class B>
00318 string<T,TAlloc> operator+(const B* const c) const
00319 {
00320 string<T,TAlloc> str(*this);
00321 str.append(c);
00322
00323 return str;
00324 }
00325
00326
00328 T& operator [](const u32 index)
00329 {
00330 _IRR_DEBUG_BREAK_IF(index>=used)
00331 return array[index];
00332 }
00333
00334
00336 const T& operator [](const u32 index) const
00337 {
00338 _IRR_DEBUG_BREAK_IF(index>=used)
00339 return array[index];
00340 }
00341
00342
00344 bool operator ==(const T* const str) const
00345 {
00346 if (!str)
00347 return false;
00348
00349 u32 i;
00350 for(i=0; array[i] && str[i]; ++i)
00351 if (array[i] != str[i])
00352 return false;
00353
00354 return !array[i] && !str[i];
00355 }
00356
00357
00359 bool operator ==(const string<T,TAlloc>& other) const
00360 {
00361 for(u32 i=0; array[i] && other.array[i]; ++i)
00362 if (array[i] != other.array[i])
00363 return false;
00364
00365 return used == other.used;
00366 }
00367
00368
00370 bool operator <(const string<T,TAlloc>& other) const
00371 {
00372 for(u32 i=0; array[i] && other.array[i]; ++i)
00373 {
00374 s32 diff = array[i] - other.array[i];
00375 if ( diff )
00376 return diff < 0;
00377 }
00378
00379 return used < other.used;
00380 }
00381
00382
00384 bool operator !=(const T* const str) const
00385 {
00386 return !(*this == str);
00387 }
00388
00389
00391 bool operator !=(const string<T,TAlloc>& other) const
00392 {
00393 return !(*this == other);
00394 }
00395
00396
00398
00400 u32 size() const
00401 {
00402 return used-1;
00403 }
00404
00405
00407
00408 const T* c_str() const
00409 {
00410 return array;
00411 }
00412
00413
00415 void make_lower()
00416 {
00417 for (u32 i=0; i<used; ++i)
00418 array[i] = locale_lower ( array[i] );
00419 }
00420
00421
00423 void make_upper()
00424 {
00425 for (u32 i=0; i<used; ++i)
00426 array[i] = locale_upper ( array[i] );
00427 }
00428
00429
00431
00433 bool equals_ignore_case(const string<T,TAlloc>& other) const
00434 {
00435 for(u32 i=0; array[i] && other[i]; ++i)
00436 if (locale_lower( array[i]) != locale_lower(other[i]))
00437 return false;
00438
00439 return used == other.used;
00440 }
00441
00443
00446 bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const
00447 {
00448 if ( (u32) sourcePos > used )
00449 return false;
00450
00451 u32 i;
00452 for( i=0; array[sourcePos + i] && other[i]; ++i)
00453 if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
00454 return false;
00455
00456 return array[sourcePos + i] == 0 && other[i] == 0;
00457 }
00458
00459
00461
00463 bool lower_ignore_case(const string<T,TAlloc>& other) const
00464 {
00465 for(u32 i=0; array[i] && other.array[i]; ++i)
00466 {
00467 s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
00468 if ( diff )
00469 return diff < 0;
00470 }
00471
00472 return used < other.used;
00473 }
00474
00475
00477
00480 bool equalsn(const string<T,TAlloc>& other, u32 n) const
00481 {
00482 u32 i;
00483 for(i=0; array[i] && other[i] && i < n; ++i)
00484 if (array[i] != other[i])
00485 return false;
00486
00487
00488
00489 return (i == n) || (used == other.used);
00490 }
00491
00492
00494
00497 bool equalsn(const T* const str, u32 n) const
00498 {
00499 if (!str)
00500 return false;
00501 u32 i;
00502 for(i=0; array[i] && str[i] && i < n; ++i)
00503 if (array[i] != str[i])
00504 return false;
00505
00506
00507
00508 return (i == n) || (array[i] == 0 && str[i] == 0);
00509 }
00510
00511
00513
00514 void append(T character)
00515 {
00516 if (used + 1 > allocated)
00517 reallocate(used + 1);
00518
00519 ++used;
00520
00521 array[used-2] = character;
00522 array[used-1] = 0;
00523 }
00524
00525
00527
00528 void append(const T* const other)
00529 {
00530 if (!other)
00531 return;
00532
00533 u32 len = 0;
00534 const T* p = other;
00535 while(*p)
00536 {
00537 ++len;
00538 ++p;
00539 }
00540
00541 if (used + len > allocated)
00542 reallocate(used + len);
00543
00544 --used;
00545 ++len;
00546
00547 for (u32 l=0; l<len; ++l)
00548 array[l+used] = *(other+l);
00549
00550 used += len;
00551 }
00552
00553
00555
00556 void append(const string<T,TAlloc>& other)
00557 {
00558 --used;
00559 u32 len = other.size()+1;
00560
00561 if (used + len > allocated)
00562 reallocate(used + len);
00563
00564 for (u32 l=0; l<len; ++l)
00565 array[used+l] = other[l];
00566
00567 used += len;
00568 }
00569
00570
00572
00574 void append(const string<T,TAlloc>& other, u32 length)
00575 {
00576 if (other.size() < length)
00577 {
00578 append(other);
00579 return;
00580 }
00581
00582 if (used + length > allocated)
00583 reallocate(used + length);
00584
00585 --used;
00586
00587 for (u32 l=0; l<length; ++l)
00588 array[l+used] = other[l];
00589 used += length;
00590
00591
00592 array[used]=0;
00593 ++used;
00594 }
00595
00596
00598
00599 void reserve(u32 count)
00600 {
00601 if (count < allocated)
00602 return;
00603
00604 reallocate(count);
00605 }
00606
00607
00609
00612 s32 findFirst(T c) const
00613 {
00614 for (u32 i=0; i<used; ++i)
00615 if (array[i] == c)
00616 return i;
00617
00618 return -1;
00619 }
00620
00622
00628 s32 findFirstChar(const T* const c, u32 count) const
00629 {
00630 if (!c)
00631 return -1;
00632
00633 for (u32 i=0; i<used; ++i)
00634 for (u32 j=0; j<count; ++j)
00635 if (array[i] == c[j])
00636 return i;
00637
00638 return -1;
00639 }
00640
00641
00643
00649 template <class B>
00650 s32 findFirstCharNotInList(const B* const c, u32 count) const
00651 {
00652 for (u32 i=0; i<used-1; ++i)
00653 {
00654 u32 j;
00655 for (j=0; j<count; ++j)
00656 if (array[i] == c[j])
00657 break;
00658
00659 if (j==count)
00660 return i;
00661 }
00662
00663 return -1;
00664 }
00665
00667
00673 template <class B>
00674 s32 findLastCharNotInList(const B* const c, u32 count) const
00675 {
00676 for (s32 i=(s32)(used-2); i>=0; --i)
00677 {
00678 u32 j;
00679 for (j=0; j<count; ++j)
00680 if (array[i] == c[j])
00681 break;
00682
00683 if (j==count)
00684 return i;
00685 }
00686
00687 return -1;
00688 }
00689
00691
00695 s32 findNext(T c, u32 startPos) const
00696 {
00697 for (u32 i=startPos; i<used; ++i)
00698 if (array[i] == c)
00699 return i;
00700
00701 return -1;
00702 }
00703
00704
00706
00710 s32 findLast(T c, s32 start = -1) const
00711 {
00712 start = core::clamp ( start < 0 ? (s32)(used) - 1 : start, 0, (s32)(used) - 1 );
00713 for (s32 i=start; i>=0; --i)
00714 if (array[i] == c)
00715 return i;
00716
00717 return -1;
00718 }
00719
00721
00727 s32 findLastChar(const T* const c, u32 count) const
00728 {
00729 if (!c)
00730 return -1;
00731
00732 for (s32 i=used-1; i>=0; --i)
00733 for (u32 j=0; j<count; ++j)
00734 if (array[i] == c[j])
00735 return i;
00736
00737 return -1;
00738 }
00739
00740
00742
00746 template <class B>
00747 s32 find(const B* const str, const u32 start = 0) const
00748 {
00749 if (str && *str)
00750 {
00751 u32 len = 0;
00752
00753 while (str[len])
00754 ++len;
00755
00756 if (len > used-1)
00757 return -1;
00758
00759 for (u32 i=start; i<used-len; ++i)
00760 {
00761 u32 j=0;
00762
00763 while(str[j] && array[i+j] == str[j])
00764 ++j;
00765
00766 if (!str[j])
00767 return i;
00768 }
00769 }
00770
00771 return -1;
00772 }
00773
00774
00776
00778 string<T,TAlloc> subString(u32 begin, s32 length) const
00779 {
00780
00781
00782 if ((length <= 0) || (begin>=size()))
00783 return string<T,TAlloc>("");
00784
00785 if ((length+begin) > size())
00786 length = size()-begin;
00787
00788 string<T,TAlloc> o;
00789 o.reserve(length+1);
00790
00791 for (s32 i=0; i<length; ++i)
00792 o.array[i] = array[i+begin];
00793
00794 o.array[length] = 0;
00795 o.used = o.allocated;
00796
00797 return o;
00798 }
00799
00800
00802
00803 string<T,TAlloc>& operator += (T c)
00804 {
00805 append(c);
00806 return *this;
00807 }
00808
00809
00811
00812 string<T,TAlloc>& operator += (const T* const c)
00813 {
00814 append(c);
00815 return *this;
00816 }
00817
00818
00820
00821 string<T,TAlloc>& operator += (const string<T,TAlloc>& other)
00822 {
00823 append(other);
00824 return *this;
00825 }
00826
00827
00829
00830 string<T,TAlloc>& operator += (const int i)
00831 {
00832 append(string<T,TAlloc>(i));
00833 return *this;
00834 }
00835
00836
00838
00839 string<T,TAlloc>& operator += (const unsigned int i)
00840 {
00841 append(string<T,TAlloc>(i));
00842 return *this;
00843 }
00844
00845
00847
00848 string<T,TAlloc>& operator += (const long i)
00849 {
00850 append(string<T,TAlloc>(i));
00851 return *this;
00852 }
00853
00854
00856
00857 string<T,TAlloc>& operator += (const unsigned long& i)
00858 {
00859 append(string<T,TAlloc>(i));
00860 return *this;
00861 }
00862
00863
00865
00866 string<T,TAlloc>& operator += (const double i)
00867 {
00868 append(string<T,TAlloc>(i));
00869 return *this;
00870 }
00871
00872
00874
00875 string<T,TAlloc>& operator += (const float i)
00876 {
00877 append(string<T,TAlloc>(i));
00878 return *this;
00879 }
00880
00881
00883
00885 void replace(T toReplace, T replaceWith)
00886 {
00887 for (u32 i=0; i<used; ++i)
00888 if (array[i] == toReplace)
00889 array[i] = replaceWith;
00890 }
00891
00892
00894
00895 void remove(T c)
00896 {
00897 u32 pos = 0;
00898 u32 found = 0;
00899 for (u32 i=0; i<used; ++i)
00900 {
00901 if (array[i] == c)
00902 {
00903 ++found;
00904 continue;
00905 }
00906
00907 array[pos++] = array[i];
00908 }
00909 used -= found;
00910 array[used-1] = 0;
00911 }
00912
00913
00915
00916 void remove(const string<T,TAlloc> toRemove)
00917 {
00918 u32 size = toRemove.size();
00919 if ( size == 0 )
00920 return;
00921 u32 pos = 0;
00922 u32 found = 0;
00923 for (u32 i=0; i<used; ++i)
00924 {
00925 u32 j = 0;
00926 while (j < size)
00927 {
00928 if (array[i + j] != toRemove[j])
00929 break;
00930 ++j;
00931 }
00932 if (j == size)
00933 {
00934 found += size;
00935 i += size - 1;
00936 continue;
00937 }
00938
00939 array[pos++] = array[i];
00940 }
00941 used -= found;
00942 array[used-1] = 0;
00943 }
00944
00945
00947
00948 void removeChars(const string<T,TAlloc> & characters)
00949 {
00950 u32 pos = 0;
00951 u32 found = 0;
00952 for (u32 i=0; i<used; ++i)
00953 {
00954
00955
00956 bool docontinue = false;
00957 for (u32 j=0; j<characters.size(); ++j)
00958 {
00959 if (characters[j] == array[i])
00960 {
00961 ++found;
00962 docontinue = true;
00963 break;
00964 }
00965 }
00966 if (docontinue)
00967 continue;
00968
00969 array[pos++] = array[i];
00970 }
00971 used -= found;
00972 array[used-1] = 0;
00973 }
00974
00975
00977
00979 string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
00980 {
00981
00982 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
00983 if (begin == -1)
00984 return (*this="");
00985
00986 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
00987
00988 return (*this = subString(begin, (end +1) - begin));
00989 }
00990
00991
00993
00996 void erase(u32 index)
00997 {
00998 _IRR_DEBUG_BREAK_IF(index>=used)
00999
01000 for (u32 i=index+1; i<used; ++i)
01001 array[i-1] = array[i];
01002
01003 --used;
01004 }
01005
01007 void validate()
01008 {
01009
01010 for (u32 i=0; i<allocated; ++i)
01011 {
01012 if (array[i] == 0)
01013 {
01014 used = i + 1;
01015 return;
01016 }
01017 }
01018
01019
01020 if ( allocated > 0 )
01021 {
01022 used = allocated;
01023 array[used-1] = 0;
01024 }
01025 else
01026 {
01027 used = 0;
01028 }
01029 }
01030
01032 T lastChar() const
01033 {
01034 return used > 1 ? array[used-2] : 0;
01035 }
01036
01038
01055 template<class container>
01056 u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
01057 {
01058 if (!c)
01059 return 0;
01060
01061 const u32 oldSize=ret.size();
01062 u32 lastpos = 0;
01063 bool lastWasSeparator = false;
01064 for (u32 i=0; i<used; ++i)
01065 {
01066 bool foundSeparator = false;
01067 for (u32 j=0; j<count; ++j)
01068 {
01069 if (array[i] == c[j])
01070 {
01071 if ((!ignoreEmptyTokens || i - lastpos != 0) &&
01072 !lastWasSeparator)
01073 ret.push_back(string<T,TAlloc>(&array[lastpos], i - lastpos));
01074 foundSeparator = true;
01075 lastpos = (keepSeparators ? i : i + 1);
01076 break;
01077 }
01078 }
01079 lastWasSeparator = foundSeparator;
01080 }
01081 if ((used - 1) > lastpos)
01082 ret.push_back(string<T,TAlloc>(&array[lastpos], (used - 1) - lastpos));
01083 return ret.size()-oldSize;
01084 }
01085
01086 private:
01087
01089 void reallocate(u32 new_size)
01090 {
01091 T* old_array = array;
01092
01093 array = allocator.allocate(new_size);
01094 allocated = new_size;
01095
01096 u32 amount = used < new_size ? used : new_size;
01097 for (u32 i=0; i<amount; ++i)
01098 array[i] = old_array[i];
01099
01100 if (allocated < used)
01101 used = allocated;
01102
01103 allocator.deallocate(old_array);
01104 }
01105
01106
01107
01108 T* array;
01109 u32 allocated;
01110 u32 used;
01111 TAlloc allocator;
01112 };
01113
01114
01116 typedef string<c8> stringc;
01117
01119 typedef string<wchar_t> stringw;
01120
01121
01122 }
01123 }
01124
01125 #endif
01126