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>& other)
00088 : array(0), allocated(0), used(0)
00089 {
00090 *this = other;
00091 }
00092
00094 template <class B>
00095 string(const string<B>& 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 virtual ~string()
00224 {
00225 allocator.deallocate(array);
00226 }
00227
00228
00230 string<T>& operator=(const string<T>& other)
00231 {
00232 if (this == &other)
00233 return *this;
00234
00235 allocator.deallocate(array);
00236 allocated = used = other.size()+1;
00237 array = allocator.allocate(used);
00238
00239 const T* p = other.c_str();
00240 for (u32 i=0; i<used; ++i, ++p)
00241 array[i] = *p;
00242
00243 return *this;
00244 }
00245
00247 template <class B>
00248 string<T>& operator=(const string<B>& other)
00249 {
00250 *this = other.c_str();
00251 return *this;
00252 }
00253
00254
00256 template <class B>
00257 string<T>& operator=(const B* const c)
00258 {
00259 if (!c)
00260 {
00261 if (!array)
00262 {
00263 array = allocator.allocate(1);
00264 allocated = 1;
00265 }
00266 used = 1;
00267 array[0] = 0x0;
00268 return *this;
00269 }
00270
00271 if ((void*)c == (void*)array)
00272 return *this;
00273
00274 u32 len = 0;
00275 const B* p = c;
00276 while(*p)
00277 {
00278 ++len;
00279 ++p;
00280 }
00281
00282
00283
00284 T* oldArray = array;
00285
00286 ++len;
00287 allocated = used = len;
00288 array = allocator.allocate(used);
00289
00290 for (u32 l = 0; l<len; ++l)
00291 array[l] = (T)c[l];
00292
00293 allocator.deallocate(oldArray);
00294 return *this;
00295 }
00296
00297
00299 string<T> operator+(const string<T>& other) const
00300 {
00301 string<T> str(*this);
00302 str.append(other);
00303
00304 return str;
00305 }
00306
00307
00309 template <class B>
00310 string<T> operator+(const B* const c) const
00311 {
00312 string<T> str(*this);
00313 str.append(c);
00314
00315 return str;
00316 }
00317
00318
00320 T& operator [](const u32 index)
00321 {
00322 _IRR_DEBUG_BREAK_IF(index>=used)
00323 return array[index];
00324 }
00325
00326
00328 const T& operator [](const u32 index) const
00329 {
00330 _IRR_DEBUG_BREAK_IF(index>=used)
00331 return array[index];
00332 }
00333
00334
00336 bool operator ==(const T* const str) const
00337 {
00338 if (!str)
00339 return false;
00340
00341 u32 i;
00342 for(i=0; array[i] && str[i]; ++i)
00343 if (array[i] != str[i])
00344 return false;
00345
00346 return !array[i] && !str[i];
00347 }
00348
00349
00351 bool operator ==(const string<T>& other) const
00352 {
00353 for(u32 i=0; array[i] && other.array[i]; ++i)
00354 if (array[i] != other.array[i])
00355 return false;
00356
00357 return used == other.used;
00358 }
00359
00360
00362 bool operator <(const string<T>& other) const
00363 {
00364 for(u32 i=0; array[i] && other.array[i]; ++i)
00365 {
00366 s32 diff = array[i] - other.array[i];
00367 if ( diff )
00368 return diff < 0;
00369
00370
00371
00372
00373 }
00374
00375 return used < other.used;
00376 }
00377
00378
00380 bool operator !=(const T* const str) const
00381 {
00382 return !(*this == str);
00383 }
00384
00385
00387 bool operator !=(const string<T>& other) const
00388 {
00389 return !(*this == other);
00390 }
00391
00392
00394
00395 u32 size() const
00396 {
00397 return used-1;
00398 }
00399
00400
00402
00403 const T* c_str() const
00404 {
00405 return array;
00406 }
00407
00408
00410 void make_lower()
00411 {
00412 for (u32 i=0; i<used; ++i)
00413 array[i] = locale_lower ( array[i] );
00414 }
00415
00416
00418 void make_upper()
00419 {
00420 for (u32 i=0; i<used; ++i)
00421 array[i] = locale_upper ( array[i] );
00422 }
00423
00424
00426
00428 bool equals_ignore_case(const string<T>& other) const
00429 {
00430 for(u32 i=0; array[i] && other[i]; ++i)
00431 if (locale_lower( array[i]) != locale_lower(other[i]))
00432 return false;
00433
00434 return used == other.used;
00435 }
00436
00438
00441 bool equals_substring_ignore_case(const string<T>&other, const s32 sourcePos = 0 ) const
00442 {
00443 if ( (u32) sourcePos > used )
00444 return false;
00445
00446 u32 i;
00447 for( i=0; array[sourcePos + i] && other[i]; ++i)
00448 if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
00449 return false;
00450
00451 return array[sourcePos + i] == 0 && other[i] == 0;
00452 }
00453
00454
00456
00458 bool lower_ignore_case(const string<T>& other) const
00459 {
00460 for(u32 i=0; array[i] && other.array[i]; ++i)
00461 {
00462 s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
00463 if ( diff )
00464 return diff < 0;
00465 }
00466
00467 return used < other.used;
00468 }
00469
00470
00472
00475 bool equalsn(const string<T>& other, u32 n) const
00476 {
00477 u32 i;
00478 for(i=0; array[i] && other[i] && i < n; ++i)
00479 if (array[i] != other[i])
00480 return false;
00481
00482
00483
00484 return (i == n) || (used == other.used);
00485 }
00486
00487
00489
00492 bool equalsn(const T* const str, u32 n) const
00493 {
00494 if (!str)
00495 return false;
00496 u32 i;
00497 for(i=0; array[i] && str[i] && i < n; ++i)
00498 if (array[i] != str[i])
00499 return false;
00500
00501
00502
00503 return (i == n) || (array[i] == 0 && str[i] == 0);
00504 }
00505
00506
00508
00509 void append(T character)
00510 {
00511 if (used + 1 > allocated)
00512 reallocate(used + 1);
00513
00514 ++used;
00515
00516 array[used-2] = character;
00517 array[used-1] = 0;
00518 }
00519
00520
00522
00523 void append(const T* const other)
00524 {
00525 if (!other)
00526 return;
00527
00528 u32 len = 0;
00529 const T* p = other;
00530 while(*p)
00531 {
00532 ++len;
00533 ++p;
00534 }
00535
00536 if (used + len > allocated)
00537 reallocate(used + len);
00538
00539 --used;
00540 ++len;
00541
00542 for (u32 l=0; l<len; ++l)
00543 array[l+used] = *(other+l);
00544
00545 used += len;
00546 }
00547
00548
00550
00551 void append(const string<T>& other)
00552 {
00553 --used;
00554 u32 len = other.size()+1;
00555
00556 if (used + len > allocated)
00557 reallocate(used + len);
00558
00559 for (u32 l=0; l<len; ++l)
00560 array[used+l] = other[l];
00561
00562 used += len;
00563 }
00564
00565
00567
00569 void append(const string<T>& other, u32 length)
00570 {
00571 if (other.size() < length)
00572 {
00573 append(other);
00574 return;
00575 }
00576
00577 if (used + length > allocated)
00578 reallocate(used + length);
00579
00580 --used;
00581
00582 for (u32 l=0; l<length; ++l)
00583 array[l+used] = other[l];
00584 used += length;
00585
00586
00587 array[used]=0;
00588 ++used;
00589 }
00590
00591
00593
00594 void reserve(u32 count)
00595 {
00596 if (count < allocated)
00597 return;
00598
00599 reallocate(count);
00600 }
00601
00602
00604
00607 s32 findFirst(T c) const
00608 {
00609 for (u32 i=0; i<used; ++i)
00610 if (array[i] == c)
00611 return i;
00612
00613 return -1;
00614 }
00615
00617
00623 s32 findFirstChar(const T* const c, u32 count) const
00624 {
00625 if (!c)
00626 return -1;
00627
00628 for (u32 i=0; i<used; ++i)
00629 for (u32 j=0; j<count; ++j)
00630 if (array[i] == c[j])
00631 return i;
00632
00633 return -1;
00634 }
00635
00636
00638
00644 template <class B>
00645 s32 findFirstCharNotInList(const B* const c, u32 count) const
00646 {
00647 for (u32 i=0; i<used-1; ++i)
00648 {
00649 u32 j;
00650 for (j=0; j<count; ++j)
00651 if (array[i] == c[j])
00652 break;
00653
00654 if (j==count)
00655 return i;
00656 }
00657
00658 return -1;
00659 }
00660
00662
00668 template <class B>
00669 s32 findLastCharNotInList(const B* const c, u32 count) const
00670 {
00671 for (s32 i=(s32)(used-2); i>=0; --i)
00672 {
00673 u32 j;
00674 for (j=0; j<count; ++j)
00675 if (array[i] == c[j])
00676 break;
00677
00678 if (j==count)
00679 return i;
00680 }
00681
00682 return -1;
00683 }
00684
00686
00690 s32 findNext(T c, u32 startPos) const
00691 {
00692 for (u32 i=startPos; i<used; ++i)
00693 if (array[i] == c)
00694 return i;
00695
00696 return -1;
00697 }
00698
00699
00701
00705 s32 findLast(T c, s32 start = -1) const
00706 {
00707 start = core::clamp ( start < 0 ? (s32)(used) - 1 : start, 0, (s32)(used) - 1 );
00708 for (s32 i=start; i>=0; --i)
00709 if (array[i] == c)
00710 return i;
00711
00712 return -1;
00713 }
00714
00716
00722 s32 findLastChar(const T* const c, u32 count) const
00723 {
00724 if (!c)
00725 return -1;
00726
00727 for (s32 i=used-1; i>=0; --i)
00728 for (u32 j=0; j<count; ++j)
00729 if (array[i] == c[j])
00730 return i;
00731
00732 return -1;
00733 }
00734
00735
00737
00740 template <class B>
00741 s32 find(const B* const str) const
00742 {
00743 if (str && *str)
00744 {
00745 u32 len = 0;
00746
00747 while (str[len])
00748 ++len;
00749
00750 if (len > used-1)
00751 return -1;
00752
00753 for (u32 i=0; i<used-len; ++i)
00754 {
00755 u32 j=0;
00756
00757 while(str[j] && array[i+j] == str[j])
00758 ++j;
00759
00760 if (!str[j])
00761 return i;
00762 }
00763 }
00764
00765 return -1;
00766 }
00767
00768
00770
00772 string<T> subString(u32 begin, s32 length) const
00773 {
00774
00775
00776 if ((length <= 0) || (begin>=size()))
00777 return string<T>("");
00778
00779 if ((length+begin) > size())
00780 length = size()-begin;
00781
00782 string<T> o;
00783 o.reserve(length+1);
00784
00785 for (s32 i=0; i<length; ++i)
00786 o.array[i] = array[i+begin];
00787
00788 o.array[length] = 0;
00789 o.used = o.allocated;
00790
00791 return o;
00792 }
00793
00794
00796
00797 string<T>& operator += (T c)
00798 {
00799 append(c);
00800 return *this;
00801 }
00802
00803
00805
00806 string<T>& operator += (const T* const c)
00807 {
00808 append(c);
00809 return *this;
00810 }
00811
00812
00814
00815 string<T>& operator += (const string<T>& other)
00816 {
00817 append(other);
00818 return *this;
00819 }
00820
00821
00823
00824 string<T>& operator += (const int i)
00825 {
00826 append(string<T>(i));
00827 return *this;
00828 }
00829
00830
00832
00833 string<T>& operator += (const unsigned int i)
00834 {
00835 append(string<T>(i));
00836 return *this;
00837 }
00838
00839
00841
00842 string<T>& operator += (const long i)
00843 {
00844 append(string<T>(i));
00845 return *this;
00846 }
00847
00848
00850
00851 string<T>& operator += (const unsigned long& i)
00852 {
00853 append(string<T>(i));
00854 return *this;
00855 }
00856
00857
00859
00860 string<T>& operator += (const double i)
00861 {
00862 append(string<T>(i));
00863 return *this;
00864 }
00865
00866
00868
00869 string<T>& operator += (const float i)
00870 {
00871 append(string<T>(i));
00872 return *this;
00873 }
00874
00875
00877
00879 void replace(T toReplace, T replaceWith)
00880 {
00881 for (u32 i=0; i<used; ++i)
00882 if (array[i] == toReplace)
00883 array[i] = replaceWith;
00884 }
00885
00886
00888
00890 string<T>& trim(const string<T> & whitespace = " \t\n\r")
00891 {
00892
00893 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
00894 if (begin == -1)
00895 return (*this="");
00896
00897 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
00898
00899 return (*this = subString(begin, (end +1) - begin));
00900 }
00901
00902
00904
00907 void erase(u32 index)
00908 {
00909 _IRR_DEBUG_BREAK_IF(index>=used)
00910
00911 for (u32 i=index+1; i<used; ++i)
00912 array[i-1] = array[i];
00913
00914 --used;
00915 }
00916
00918 void validate()
00919 {
00920
00921 for (u32 i=0; i<allocated; ++i)
00922 {
00923 if (array[i] == 0)
00924 {
00925 used = i + 1;
00926 return;
00927 }
00928 }
00929
00930
00931 if ( allocated > 0 )
00932 {
00933 used = allocated - 1;
00934 array[used] = 0;
00935 }
00936 else
00937 {
00938 used = 0;
00939 }
00940 }
00941
00943 inline T lastChar() const
00944 {
00945 return used > 1 ? array[used-2] : 0;
00946 }
00947
00948 private:
00949
00951 void reallocate(u32 new_size)
00952 {
00953 T* old_array = array;
00954
00955 array = allocator.allocate(new_size);
00956 allocated = new_size;
00957
00958 u32 amount = used < new_size ? used : new_size;
00959 for (u32 i=0; i<amount; ++i)
00960 array[i] = old_array[i];
00961
00962 if (allocated < used)
00963 used = allocated;
00964
00965 allocator.deallocate(old_array);
00966 }
00967
00968
00969
00970 T* array;
00971 TAlloc allocator;
00972 u32 allocated;
00973 u32 used;
00974 };
00975
00976
00978 typedef string<c8> stringc;
00979
00981 typedef string<wchar_t> stringw;
00982
00983
00984 }
00985 }
00986
00987 #endif
00988