Home | Namespaces | Hierarchy | Alphabetical List | Class list | Files | Namespace Members | Class members | File members | Tutorials

irrString.h

Go to the documentation of this file.
00001 // Copyright (C) 2002-2009 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 
00078         string()
00079         : array(0), allocated(1), used(1)
00080         {
00081                 array = allocator.allocate(1); // new T[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                 // store if negative and make positive
00117 
00118                 bool negative = false;
00119                 if (number < 0)
00120                 {
00121                         number *= -1;
00122                         negative = true;
00123                 }
00124 
00125                 // temporary buffer for 16 numbers
00126 
00127                 c8 tmpbuf[16]={0};
00128                 u32 idx = 15;
00129 
00130                 // special case '0'
00131 
00132                 if (!number)
00133                 {
00134                         tmpbuf[14] = '0';
00135                         *this = &tmpbuf[14];
00136                         return;
00137                 }
00138 
00139                 // add numbers
00140 
00141                 while(number && idx)
00142                 {
00143                         --idx;
00144                         tmpbuf[idx] = (c8)('0' + (number % 10));
00145                         number /= 10;
00146                 }
00147 
00148                 // add sign
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                 // temporary buffer for 16 numbers
00165 
00166                 c8 tmpbuf[16]={0};
00167                 u32 idx = 15;
00168 
00169                 // special case '0'
00170 
00171                 if (!number)
00172                 {
00173                         tmpbuf[14] = '0';
00174                         *this = &tmpbuf[14];
00175                         return;
00176                 }
00177 
00178                 // add numbers
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                         // correctly init the string to an empty one
00199                         *this="";
00200                         return;
00201                 }
00202 
00203                 allocated = used = length+1;
00204                 array = allocator.allocate(used); // new T[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); // delete [] 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); // delete [] array;
00236                 allocated = used = other.size()+1;
00237                 array = allocator.allocate(used); //new T[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); //new T[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                 // we'll take the old string for a while, because the new
00283                 // string could be a part of the current string.
00284                 T* oldArray = array;
00285 
00286                 ++len;
00287                 allocated = used = len;
00288                 array = allocator.allocate(used); //new T[used];
00289 
00290                 for (u32 l = 0; l<len; ++l)
00291                         array[l] = (T)c[l];
00292 
00293                 allocator.deallocate(oldArray); // delete [] 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) // bad index
00323                 return array[index];
00324         }
00325 
00326 
00328         const T& operator [](const u32 index) const
00329         {
00330                 _IRR_DEBUG_BREAK_IF(index>=used) // bad index
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                         if (array[i] != other.array[i])
00371                                 return (array[i] < other.array[i]);
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                 // if one (or both) of the strings was smaller then they
00483                 // are only equal if they have the same length
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                 // if one (or both) of the strings was smaller then they
00502                 // are only equal if they have the same length
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                 // ensure proper termination
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                 // if start after string
00775                 // or no proper substring length
00776                 if ((length <= 0) || (begin>=size()))
00777                         return string<T>("");
00778                 // clamp length to maximal value
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                 // find start and end of the substring without the specified characters
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) // access violation
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                 // terminate on existing null
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                 // terminate
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); //new T[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); // delete [] old_array;
00966         }
00967 
00968         //--- member variables
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 } // end namespace core
00985 } // end namespace irr
00986 
00987 #endif
00988 

The Irrlicht Engine
The Irrlicht Engine Documentation © 2003-2009 by Nikolaus Gebhardt. Generated on Sun Jan 10 09:24:04 2010 by Doxygen (1.5.6)