Home | Namespaces | Hierarchy | Alphabetical List | Class list | Files | Namespace Members | Class members | File members | Tutorials
irrString.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2010 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine" and the "irrXML" project.
3 // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h
4 
5 #ifndef __IRR_STRING_H_INCLUDED__
6 #define __IRR_STRING_H_INCLUDED__
7 
8 #include "irrTypes.h"
9 #include "irrAllocator.h"
10 #include "irrMath.h"
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 
15 namespace irr
16 {
17 namespace core
18 {
19 
21 
33 {
36 };
37 
38 static eLocaleID locale_current = IRR_LOCALE_ANSI;
39 static inline void locale_set ( eLocaleID id )
40 {
41  locale_current = id;
42 }
43 
45 static inline u32 locale_lower ( u32 x )
46 {
47  switch ( locale_current )
48  {
49  case IRR_LOCALE_GERMAN:
50  case IRR_LOCALE_ANSI:
51  break;
52  }
53  // ansi
54  return x >= 'A' && x <= 'Z' ? x + 0x20 : x;
55 }
56 
58 static inline u32 locale_upper ( u32 x )
59 {
60  switch ( locale_current )
61  {
62  case IRR_LOCALE_GERMAN:
63  case IRR_LOCALE_ANSI:
64  break;
65  }
66 
67  // ansi
68  return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;
69 }
70 
71 
72 template <typename T, typename TAlloc = irrAllocator<T> >
73 class string
74 {
75 public:
76 
79  : array(0), allocated(1), used(1)
80  {
81  array = allocator.allocate(1); // new T[1];
82  array[0] = 0x0;
83  }
84 
85 
87  string(const string<T,TAlloc>& other)
88  : array(0), allocated(0), used(0)
89  {
90  *this = other;
91  }
92 
94  template <class B, class A>
95  string(const string<B, A>& other)
96  : array(0), allocated(0), used(0)
97  {
98  *this = other;
99  }
100 
101 
103  explicit string(const double number)
104  : array(0), allocated(0), used(0)
105  {
106  c8 tmpbuf[255];
107  snprintf(tmpbuf, 255, "%0.6f", number);
108  *this = tmpbuf;
109  }
110 
111 
113  explicit string(int number)
114  : array(0), allocated(0), used(0)
115  {
116  // store if negative and make positive
117 
118  bool negative = false;
119  if (number < 0)
120  {
121  number *= -1;
122  negative = true;
123  }
124 
125  // temporary buffer for 16 numbers
126 
127  c8 tmpbuf[16]={0};
128  u32 idx = 15;
129 
130  // special case '0'
131 
132  if (!number)
133  {
134  tmpbuf[14] = '0';
135  *this = &tmpbuf[14];
136  return;
137  }
138 
139  // add numbers
140 
141  while(number && idx)
142  {
143  --idx;
144  tmpbuf[idx] = (c8)('0' + (number % 10));
145  number /= 10;
146  }
147 
148  // add sign
149 
150  if (negative)
151  {
152  --idx;
153  tmpbuf[idx] = '-';
154  }
155 
156  *this = &tmpbuf[idx];
157  }
158 
159 
161  explicit string(unsigned int number)
162  : array(0), allocated(0), used(0)
163  {
164  // temporary buffer for 16 numbers
165 
166  c8 tmpbuf[16]={0};
167  u32 idx = 15;
168 
169  // special case '0'
170 
171  if (!number)
172  {
173  tmpbuf[14] = '0';
174  *this = &tmpbuf[14];
175  return;
176  }
177 
178  // add numbers
179 
180  while(number && idx)
181  {
182  --idx;
183  tmpbuf[idx] = (c8)('0' + (number % 10));
184  number /= 10;
185  }
186 
187  *this = &tmpbuf[idx];
188  }
189 
190 
192  template <class B>
193  string(const B* const c, u32 length)
194  : array(0), allocated(0), used(0)
195  {
196  if (!c)
197  {
198  // correctly init the string to an empty one
199  *this="";
200  return;
201  }
202 
203  allocated = used = length+1;
204  array = allocator.allocate(used); // new T[used];
205 
206  for (u32 l = 0; l<length; ++l)
207  array[l] = (T)c[l];
208 
209  array[length] = 0;
210  }
211 
212 
214  template <class B>
215  string(const B* const c)
216  : array(0), allocated(0), used(0)
217  {
218  *this = c;
219  }
220 
221 
224  {
225  allocator.deallocate(array); // delete [] array;
226  }
227 
228 
231  {
232  if (this == &other)
233  return *this;
234 
235  used = other.size()+1;
236  if (used>allocated)
237  {
238  allocator.deallocate(array); // delete [] array;
239  allocated = used;
240  array = allocator.allocate(used); //new T[used];
241  }
242 
243  const T* p = other.c_str();
244  for (u32 i=0; i<used; ++i, ++p)
245  array[i] = *p;
246 
247  return *this;
248  }
249 
251  template <class B, class A>
253  {
254  *this = other.c_str();
255  return *this;
256  }
257 
258 
260  template <class B>
261  string<T,TAlloc>& operator=(const B* const c)
262  {
263  if (!c)
264  {
265  if (!array)
266  {
267  array = allocator.allocate(1); //new T[1];
268  allocated = 1;
269  }
270  used = 1;
271  array[0] = 0x0;
272  return *this;
273  }
274 
275  if ((void*)c == (void*)array)
276  return *this;
277 
278  u32 len = 0;
279  const B* p = c;
280  do
281  {
282  ++len;
283  } while(*p++);
284 
285  // we'll keep the old string for a while, because the new
286  // string could be a part of the current string.
287  T* oldArray = array;
288 
289  used = len;
290  if (used>allocated)
291  {
292  allocated = used;
293  array = allocator.allocate(used); //new T[used];
294  }
295 
296  for (u32 l = 0; l<len; ++l)
297  array[l] = (T)c[l];
298 
299  if (oldArray != array)
300  allocator.deallocate(oldArray); // delete [] oldArray;
301 
302  return *this;
303  }
304 
305 
308  {
309  string<T,TAlloc> str(*this);
310  str.append(other);
311 
312  return str;
313  }
314 
315 
317  template <class B>
318  string<T,TAlloc> operator+(const B* const c) const
319  {
320  string<T,TAlloc> str(*this);
321  str.append(c);
322 
323  return str;
324  }
325 
326 
328  T& operator [](const u32 index)
329  {
330  _IRR_DEBUG_BREAK_IF(index>=used) // bad index
331  return array[index];
332  }
333 
334 
336  const T& operator [](const u32 index) const
337  {
338  _IRR_DEBUG_BREAK_IF(index>=used) // bad index
339  return array[index];
340  }
341 
342 
344  bool operator ==(const T* const str) const
345  {
346  if (!str)
347  return false;
348 
349  u32 i;
350  for(i=0; array[i] && str[i]; ++i)
351  if (array[i] != str[i])
352  return false;
353 
354  return !array[i] && !str[i];
355  }
356 
357 
359  bool operator ==(const string<T,TAlloc>& other) const
360  {
361  for(u32 i=0; array[i] && other.array[i]; ++i)
362  if (array[i] != other.array[i])
363  return false;
364 
365  return used == other.used;
366  }
367 
368 
370  bool operator <(const string<T,TAlloc>& other) const
371  {
372  for(u32 i=0; array[i] && other.array[i]; ++i)
373  {
374  s32 diff = array[i] - other.array[i];
375  if ( diff )
376  return diff < 0;
377  }
378 
379  return used < other.used;
380  }
381 
382 
384  bool operator !=(const T* const str) const
385  {
386  return !(*this == str);
387  }
388 
389 
391  bool operator !=(const string<T,TAlloc>& other) const
392  {
393  return !(*this == other);
394  }
395 
396 
398 
400  u32 size() const
401  {
402  return used-1;
403  }
404 
405 
407 
408  const T* c_str() const
409  {
410  return array;
411  }
412 
413 
415  void make_lower()
416  {
417  for (u32 i=0; i<used; ++i)
418  array[i] = locale_lower ( array[i] );
419  }
420 
421 
423  void make_upper()
424  {
425  for (u32 i=0; i<used; ++i)
426  array[i] = locale_upper ( array[i] );
427  }
428 
429 
431 
433  bool equals_ignore_case(const string<T,TAlloc>& other) const
434  {
435  for(u32 i=0; array[i] && other[i]; ++i)
436  if (locale_lower( array[i]) != locale_lower(other[i]))
437  return false;
438 
439  return used == other.used;
440  }
441 
443 
446  bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const
447  {
448  if ( (u32) sourcePos > used )
449  return false;
450 
451  u32 i;
452  for( i=0; array[sourcePos + i] && other[i]; ++i)
453  if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
454  return false;
455 
456  return array[sourcePos + i] == 0 && other[i] == 0;
457  }
458 
459 
461 
463  bool lower_ignore_case(const string<T,TAlloc>& other) const
464  {
465  for(u32 i=0; array[i] && other.array[i]; ++i)
466  {
467  s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
468  if ( diff )
469  return diff < 0;
470  }
471 
472  return used < other.used;
473  }
474 
475 
477 
480  bool equalsn(const string<T,TAlloc>& other, u32 n) const
481  {
482  u32 i;
483  for(i=0; array[i] && other[i] && i < n; ++i)
484  if (array[i] != other[i])
485  return false;
486 
487  // if one (or both) of the strings was smaller then they
488  // are only equal if they have the same length
489  return (i == n) || (used == other.used);
490  }
491 
492 
494 
497  bool equalsn(const T* const str, u32 n) const
498  {
499  if (!str)
500  return false;
501  u32 i;
502  for(i=0; array[i] && str[i] && i < n; ++i)
503  if (array[i] != str[i])
504  return false;
505 
506  // if one (or both) of the strings was smaller then they
507  // are only equal if they have the same length
508  return (i == n) || (array[i] == 0 && str[i] == 0);
509  }
510 
511 
513 
514  void append(T character)
515  {
516  if (used + 1 > allocated)
517  reallocate(used + 1);
518 
519  ++used;
520 
521  array[used-2] = character;
522  array[used-1] = 0;
523  }
524 
525 
527 
528  void append(const T* const other)
529  {
530  if (!other)
531  return;
532 
533  u32 len = 0;
534  const T* p = other;
535  while(*p)
536  {
537  ++len;
538  ++p;
539  }
540 
541  if (used + len > allocated)
542  reallocate(used + len);
543 
544  --used;
545  ++len;
546 
547  for (u32 l=0; l<len; ++l)
548  array[l+used] = *(other+l);
549 
550  used += len;
551  }
552 
553 
555 
556  void append(const string<T,TAlloc>& other)
557  {
558  --used;
559  u32 len = other.size()+1;
560 
561  if (used + len > allocated)
562  reallocate(used + len);
563 
564  for (u32 l=0; l<len; ++l)
565  array[used+l] = other[l];
566 
567  used += len;
568  }
569 
570 
572 
574  void append(const string<T,TAlloc>& other, u32 length)
575  {
576  if (other.size() < length)
577  {
578  append(other);
579  return;
580  }
581 
582  if (used + length > allocated)
583  reallocate(used + length);
584 
585  --used;
586 
587  for (u32 l=0; l<length; ++l)
588  array[l+used] = other[l];
589  used += length;
590 
591  // ensure proper termination
592  array[used]=0;
593  ++used;
594  }
595 
596 
598 
599  void reserve(u32 count)
600  {
601  if (count < allocated)
602  return;
603 
604  reallocate(count);
605  }
606 
607 
609 
612  s32 findFirst(T c) const
613  {
614  for (u32 i=0; i<used; ++i)
615  if (array[i] == c)
616  return i;
617 
618  return -1;
619  }
620 
622 
628  s32 findFirstChar(const T* const c, u32 count) const
629  {
630  if (!c)
631  return -1;
632 
633  for (u32 i=0; i<used; ++i)
634  for (u32 j=0; j<count; ++j)
635  if (array[i] == c[j])
636  return i;
637 
638  return -1;
639  }
640 
641 
643 
649  template <class B>
650  s32 findFirstCharNotInList(const B* const c, u32 count) const
651  {
652  for (u32 i=0; i<used-1; ++i)
653  {
654  u32 j;
655  for (j=0; j<count; ++j)
656  if (array[i] == c[j])
657  break;
658 
659  if (j==count)
660  return i;
661  }
662 
663  return -1;
664  }
665 
667 
673  template <class B>
674  s32 findLastCharNotInList(const B* const c, u32 count) const
675  {
676  for (s32 i=(s32)(used-2); i>=0; --i)
677  {
678  u32 j;
679  for (j=0; j<count; ++j)
680  if (array[i] == c[j])
681  break;
682 
683  if (j==count)
684  return i;
685  }
686 
687  return -1;
688  }
689 
691 
695  s32 findNext(T c, u32 startPos) const
696  {
697  for (u32 i=startPos; i<used; ++i)
698  if (array[i] == c)
699  return i;
700 
701  return -1;
702  }
703 
704 
706 
710  s32 findLast(T c, s32 start = -1) const
711  {
712  start = core::clamp ( start < 0 ? (s32)(used) - 1 : start, 0, (s32)(used) - 1 );
713  for (s32 i=start; i>=0; --i)
714  if (array[i] == c)
715  return i;
716 
717  return -1;
718  }
719 
721 
727  s32 findLastChar(const T* const c, u32 count) const
728  {
729  if (!c)
730  return -1;
731 
732  for (s32 i=used-1; i>=0; --i)
733  for (u32 j=0; j<count; ++j)
734  if (array[i] == c[j])
735  return i;
736 
737  return -1;
738  }
739 
740 
742 
746  template <class B>
747  s32 find(const B* const str, const u32 start = 0) const
748  {
749  if (str && *str)
750  {
751  u32 len = 0;
752 
753  while (str[len])
754  ++len;
755 
756  if (len > used-1)
757  return -1;
758 
759  for (u32 i=start; i<used-len; ++i)
760  {
761  u32 j=0;
762 
763  while(str[j] && array[i+j] == str[j])
764  ++j;
765 
766  if (!str[j])
767  return i;
768  }
769  }
770 
771  return -1;
772  }
773 
774 
776 
778  string<T,TAlloc> subString(u32 begin, s32 length) const
779  {
780  // if start after string
781  // or no proper substring length
782  if ((length <= 0) || (begin>=size()))
783  return string<T,TAlloc>("");
784  // clamp length to maximal value
785  if ((length+begin) > size())
786  length = size()-begin;
787 
789  o.reserve(length+1);
790 
791  for (s32 i=0; i<length; ++i)
792  o.array[i] = array[i+begin];
793 
794  o.array[length] = 0;
795  o.used = o.allocated;
796 
797  return o;
798  }
799 
800 
802 
804  {
805  append(c);
806  return *this;
807  }
808 
809 
811 
812  string<T,TAlloc>& operator += (const T* const c)
813  {
814  append(c);
815  return *this;
816  }
817 
818 
820 
822  {
823  append(other);
824  return *this;
825  }
826 
827 
829 
831  {
833  return *this;
834  }
835 
836 
838 
839  string<T,TAlloc>& operator += (const unsigned int i)
840  {
842  return *this;
843  }
844 
845 
847 
849  {
851  return *this;
852  }
853 
854 
856 
857  string<T,TAlloc>& operator += (const unsigned long& i)
858  {
860  return *this;
861  }
862 
863 
865 
867  {
869  return *this;
870  }
871 
872 
874 
876  {
878  return *this;
879  }
880 
881 
883 
885  void replace(T toReplace, T replaceWith)
886  {
887  for (u32 i=0; i<used; ++i)
888  if (array[i] == toReplace)
889  array[i] = replaceWith;
890  }
891 
892 
894 
895  void remove(T c)
896  {
897  u32 pos = 0;
898  u32 found = 0;
899  for (u32 i=0; i<used; ++i)
900  {
901  if (array[i] == c)
902  {
903  ++found;
904  continue;
905  }
906 
907  array[pos++] = array[i];
908  }
909  used -= found;
910  array[used-1] = 0;
911  }
912 
913 
915 
916  void remove(const string<T,TAlloc> toRemove)
917  {
918  u32 size = toRemove.size();
919  if ( size == 0 )
920  return;
921  u32 pos = 0;
922  u32 found = 0;
923  for (u32 i=0; i<used; ++i)
924  {
925  u32 j = 0;
926  while (j < size)
927  {
928  if (array[i + j] != toRemove[j])
929  break;
930  ++j;
931  }
932  if (j == size)
933  {
934  found += size;
935  i += size - 1;
936  continue;
937  }
938 
939  array[pos++] = array[i];
940  }
941  used -= found;
942  array[used-1] = 0;
943  }
944 
945 
947 
948  void removeChars(const string<T,TAlloc> & characters)
949  {
950  u32 pos = 0;
951  u32 found = 0;
952  for (u32 i=0; i<used; ++i)
953  {
954  // Don't use characters.findFirst as it finds the \0,
955  // causing used to become incorrect.
956  bool docontinue = false;
957  for (u32 j=0; j<characters.size(); ++j)
958  {
959  if (characters[j] == array[i])
960  {
961  ++found;
962  docontinue = true;
963  break;
964  }
965  }
966  if (docontinue)
967  continue;
968 
969  array[pos++] = array[i];
970  }
971  used -= found;
972  array[used-1] = 0;
973  }
974 
975 
977 
979  string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
980  {
981  // find start and end of the substring without the specified characters
982  const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
983  if (begin == -1)
984  return (*this="");
985 
986  const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
987 
988  return (*this = subString(begin, (end +1) - begin));
989  }
990 
991 
993 
996  void erase(u32 index)
997  {
998  _IRR_DEBUG_BREAK_IF(index>=used) // access violation
999 
1000  for (u32 i=index+1; i<used; ++i)
1001  array[i-1] = array[i];
1002 
1003  --used;
1004  }
1005 
1007  void validate()
1008  {
1009  // terminate on existing null
1010  for (u32 i=0; i<allocated; ++i)
1011  {
1012  if (array[i] == 0)
1013  {
1014  used = i + 1;
1015  return;
1016  }
1017  }
1018 
1019  // terminate
1020  if ( allocated > 0 )
1021  {
1022  used = allocated;
1023  array[used-1] = 0;
1024  }
1025  else
1026  {
1027  used = 0;
1028  }
1029  }
1030 
1032  T lastChar() const
1033  {
1034  return used > 1 ? array[used-2] : 0;
1035  }
1036 
1038 
1055  template<class container>
1056  u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
1057  {
1058  if (!c)
1059  return 0;
1060 
1061  const u32 oldSize=ret.size();
1062  u32 lastpos = 0;
1063  bool lastWasSeparator = false;
1064  for (u32 i=0; i<used; ++i)
1065  {
1066  bool foundSeparator = false;
1067  for (u32 j=0; j<count; ++j)
1068  {
1069  if (array[i] == c[j])
1070  {
1071  if ((!ignoreEmptyTokens || i - lastpos != 0) &&
1072  !lastWasSeparator)
1073  ret.push_back(string<T,TAlloc>(&array[lastpos], i - lastpos));
1074  foundSeparator = true;
1075  lastpos = (keepSeparators ? i : i + 1);
1076  break;
1077  }
1078  }
1079  lastWasSeparator = foundSeparator;
1080  }
1081  if ((used - 1) > lastpos)
1082  ret.push_back(string<T,TAlloc>(&array[lastpos], (used - 1) - lastpos));
1083  return ret.size()-oldSize;
1084  }
1085 
1086 private:
1087 
1089  void reallocate(u32 new_size)
1090  {
1091  T* old_array = array;
1092 
1093  array = allocator.allocate(new_size); //new T[new_size];
1094  allocated = new_size;
1095 
1096  u32 amount = used < new_size ? used : new_size;
1097  for (u32 i=0; i<amount; ++i)
1098  array[i] = old_array[i];
1099 
1100  if (allocated < used)
1101  used = allocated;
1102 
1103  allocator.deallocate(old_array); // delete [] old_array;
1104  }
1105 
1106  //--- member variables
1107 
1108  T* array;
1109  u32 allocated;
1110  u32 used;
1111  TAlloc allocator;
1112 };
1113 
1114 
1117 
1120 
1121 
1122 } // end namespace core
1123 } // end namespace irr
1124 
1125 #endif
1126 

The Irrlicht Engine
The Irrlicht Engine Documentation © 2003-2010 by Nikolaus Gebhardt. Generated on Fri Mar 21 2014 04:40:17 by Doxygen (1.8.1.2)