Irrlicht 3D Engine
irrString.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2012 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 
35 // forward declarations
36 template <typename T, typename TAlloc = irrAllocator<T> >
37 class string;
38 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);
39 inline s32 isdigit(s32 c);
40 
42 {
45 };
46 
47 static eLocaleID locale_current = IRR_LOCALE_ANSI;
48 static inline void locale_set ( eLocaleID id )
49 {
50  locale_current = id;
51 }
52 
54 static inline u32 locale_lower ( u32 x )
55 {
56  switch ( locale_current )
57  {
58  case IRR_LOCALE_GERMAN:
59  case IRR_LOCALE_ANSI:
60  break;
61  }
62  // ansi
63  return x >= 'A' && x <= 'Z' ? x + 0x20 : x;
64 }
65 
67 static inline u32 locale_upper ( u32 x )
68 {
69  switch ( locale_current )
70  {
71  case IRR_LOCALE_GERMAN:
72  case IRR_LOCALE_ANSI:
73  break;
74  }
75 
76  // ansi
77  return x >= 'a' && x <= 'z' ? x + ( 'A' - 'a' ) : x;
78 }
79 
81 
84 IRRLICHT_API void utf8ToWchar(const char *in, wchar_t *out, const u64 len);
85 
87 
90 IRRLICHT_API void wcharToUtf8(const wchar_t *in, char *out, const u64 len);
91 
92 
93 template <typename T, typename TAlloc>
94 class string
95 {
96 public:
97 
98  typedef T char_type;
99 
102  : array(0), allocated(1), used(1)
103  {
104  array = allocator.allocate(1); // new T[1];
105  array[0] = 0;
106  }
107 
108 
110  string(const string<T,TAlloc>& other)
111  : array(0), allocated(0), used(0)
112  {
113  *this = other;
114  }
115 
117  template <class B, class A>
118  string(const string<B, A>& other)
119  : array(0), allocated(0), used(0)
120  {
121  *this = other;
122  }
123 
124 
126  explicit string(const double number)
127  : array(0), allocated(0), used(0)
128  {
129  c8 tmpbuf[255];
130  snprintf_irr(tmpbuf, 255, "%0.6f", number);
131  *this = tmpbuf;
132  }
133 
134 
136  explicit string(int number)
137  : array(0), allocated(0), used(0)
138  {
139  // store if negative and make positive
140 
141  bool negative = false;
142  if (number < 0)
143  {
144  number *= -1;
145  negative = true;
146  }
147 
148  // temporary buffer for 16 numbers
149 
150  c8 tmpbuf[16]={0};
151  u32 idx = 15;
152 
153  // special case '0'
154 
155  if (!number)
156  {
157  tmpbuf[14] = '0';
158  *this = &tmpbuf[14];
159  return;
160  }
161 
162  // add numbers
163 
164  while(number && idx)
165  {
166  --idx;
167  tmpbuf[idx] = (c8)('0' + (number % 10));
168  number /= 10;
169  }
170 
171  // add sign
172 
173  if (negative)
174  {
175  --idx;
176  tmpbuf[idx] = '-';
177  }
178 
179  *this = &tmpbuf[idx];
180  }
181 
182 
184  explicit string(unsigned int number)
185  : array(0), allocated(0), used(0)
186  {
187  // temporary buffer for 16 numbers
188 
189  c8 tmpbuf[16]={0};
190  u32 idx = 15;
191 
192  // special case '0'
193 
194  if (!number)
195  {
196  tmpbuf[14] = '0';
197  *this = &tmpbuf[14];
198  return;
199  }
200 
201  // add numbers
202 
203  while(number && idx)
204  {
205  --idx;
206  tmpbuf[idx] = (c8)('0' + (number % 10));
207  number /= 10;
208  }
209 
210  *this = &tmpbuf[idx];
211  }
212 
213 
215  explicit string(long number)
216  : array(0), allocated(0), used(0)
217  {
218  // store if negative and make positive
219 
220  bool negative = false;
221  if (number < 0)
222  {
223  number *= -1;
224  negative = true;
225  }
226 
227  // temporary buffer for 16 numbers
228 
229  c8 tmpbuf[16]={0};
230  u32 idx = 15;
231 
232  // special case '0'
233 
234  if (!number)
235  {
236  tmpbuf[14] = '0';
237  *this = &tmpbuf[14];
238  return;
239  }
240 
241  // add numbers
242 
243  while(number && idx)
244  {
245  --idx;
246  tmpbuf[idx] = (c8)('0' + (number % 10));
247  number /= 10;
248  }
249 
250  // add sign
251 
252  if (negative)
253  {
254  --idx;
255  tmpbuf[idx] = '-';
256  }
257 
258  *this = &tmpbuf[idx];
259  }
260 
261 
263  explicit string(unsigned long number)
264  : array(0), allocated(0), used(0)
265  {
266  // temporary buffer for 16 numbers
267 
268  c8 tmpbuf[16]={0};
269  u32 idx = 15;
270 
271  // special case '0'
272 
273  if (!number)
274  {
275  tmpbuf[14] = '0';
276  *this = &tmpbuf[14];
277  return;
278  }
279 
280  // add numbers
281 
282  while(number && idx)
283  {
284  --idx;
285  tmpbuf[idx] = (c8)('0' + (number % 10));
286  number /= 10;
287  }
288 
289  *this = &tmpbuf[idx];
290  }
291 
292 
294  template <class B>
295  string(const B* const c, u32 length)
296  : array(0), allocated(0), used(0)
297  {
298  if (!c)
299  {
300  // correctly init the string to an empty one
301  *this="";
302  return;
303  }
304 
305  allocated = used = length+1;
306  array = allocator.allocate(used); // new T[used];
307 
308  for (u32 l = 0; l<length; ++l)
309  array[l] = (T)c[l];
310 
311  array[length] = 0;
312  }
313 
314 
316  template <class B>
317  string(const B* const c)
318  : array(0), allocated(0), used(0)
319  {
320  *this = c;
321  }
322 
323 
326  {
327  allocator.deallocate(array); // delete [] array;
328  }
329 
330 
333  {
334  if (this == &other)
335  return *this;
336 
337  used = other.size()+1;
338  if (used>allocated)
339  {
340  allocator.deallocate(array); // delete [] array;
341  allocated = used;
342  array = allocator.allocate(used); //new T[used];
343  }
344 
345  const T* p = other.c_str();
346  for (u32 i=0; i<used; ++i, ++p)
347  array[i] = *p;
348 
349  return *this;
350  }
351 
353  template <class B, class A>
355  {
356  *this = other.c_str();
357  return *this;
358  }
359 
360 
362  template <class B>
363  string<T,TAlloc>& operator=(const B* const c)
364  {
365  if (!c)
366  {
367  if (!array)
368  {
369  array = allocator.allocate(1); //new T[1];
370  allocated = 1;
371  }
372  used = 1;
373  array[0] = 0x0;
374  return *this;
375  }
376 
377  if ((void*)c == (void*)array)
378  return *this;
379 
380  u32 len = 0;
381  const B* p = c;
382  do
383  {
384  ++len;
385  } while(*p++);
386 
387  // we'll keep the old string for a while, because the new
388  // string could be a part of the current string.
389  T* oldArray = array;
390 
391  used = len;
392  if (used>allocated)
393  {
394  allocated = used;
395  array = allocator.allocate(used); //new T[used];
396  }
397 
398  for (u32 l = 0; l<len; ++l)
399  array[l] = (T)c[l];
400 
401  if (oldArray != array)
402  allocator.deallocate(oldArray); // delete [] oldArray;
403 
404  return *this;
405  }
406 
407 
410  {
411  string<T,TAlloc> str(*this);
412  str.append(other);
413 
414  return str;
415  }
416 
417 
419  template <class B>
420  string<T,TAlloc> operator+(const B* const c) const
421  {
422  string<T,TAlloc> str(*this);
423  str.append(c);
424 
425  return str;
426  }
427 
428 
430  T& operator [](const u32 index)
431  {
432  _IRR_DEBUG_BREAK_IF(index>=used) // bad index
433  return array[index];
434  }
435 
436 
438  const T& operator [](const u32 index) const
439  {
440  _IRR_DEBUG_BREAK_IF(index>=used) // bad index
441  return array[index];
442  }
443 
444 
446  bool operator==(const T* const str) const
447  {
448  if (!str)
449  return false;
450 
451  u32 i;
452  for (i=0; array[i] && str[i]; ++i)
453  if (array[i] != str[i])
454  return false;
455 
456  return (!array[i] && !str[i]);
457  }
458 
459 
461  bool operator==(const string<T,TAlloc>& other) const
462  {
463  for (u32 i=0; array[i] && other.array[i]; ++i)
464  if (array[i] != other.array[i])
465  return false;
466 
467  return used == other.used;
468  }
469 
470 
472  bool operator<(const string<T,TAlloc>& other) const
473  {
474  for (u32 i=0; array[i] && other.array[i]; ++i)
475  {
476  const s32 diff = array[i] - other.array[i];
477  if (diff)
478  return (diff < 0);
479  }
480 
481  return (used < other.used);
482  }
483 
484 
486  bool operator!=(const T* const str) const
487  {
488  return !(*this == str);
489  }
490 
491 
493  bool operator!=(const string<T,TAlloc>& other) const
494  {
495  return !(*this == other);
496  }
497 
498 
500 
502  u32 size() const
503  {
504  return used-1;
505  }
506 
509  bool empty() const
510  {
511  return (size() == 0);
512  }
513 
514  void clear(bool releaseMemory=true)
515  {
516  if ( releaseMemory )
517  {
518  reallocate(1);
519  }
520  array[0] = 0;
521  used = 1;
522  }
523 
525 
526  const T* c_str() const
527  {
528  return array;
529  }
530 
531 
534  {
535  for (u32 i=0; array[i]; ++i)
536  array[i] = locale_lower ( array[i] );
537  return *this;
538  }
539 
540 
543  {
544  for (u32 i=0; array[i]; ++i)
545  array[i] = locale_upper ( array[i] );
546  return *this;
547  }
548 
549 
551 
553  bool equals_ignore_case(const string<T,TAlloc>& other) const
554  {
555  for(u32 i=0; array[i] && other[i]; ++i)
556  if (locale_lower( array[i]) != locale_lower(other[i]))
557  return false;
558 
559  return used == other.used;
560  }
561 
563 
566  bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const
567  {
568  if ( (u32) sourcePos >= used )
569  return false;
570 
571  u32 i;
572  for( i=0; array[sourcePos + i] && other[i]; ++i)
573  if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
574  return false;
575 
576  return array[sourcePos + i] == 0 && other[i] == 0;
577  }
578 
579 
581 
583  bool lower_ignore_case(const string<T,TAlloc>& other) const
584  {
585  for(u32 i=0; array[i] && other.array[i]; ++i)
586  {
587  s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
588  if ( diff )
589  return diff < 0;
590  }
591 
592  return used < other.used;
593  }
594 
595 
597 
600  bool equalsn(const string<T,TAlloc>& other, u32 n) const
601  {
602  u32 i;
603  for(i=0; i < n && array[i] && other[i]; ++i)
604  if (array[i] != other[i])
605  return false;
606 
607  // if one (or both) of the strings was smaller then they
608  // are only equal if they have the same length
609  return (i == n) || (used == other.used);
610  }
611 
612 
614 
617  bool equalsn(const T* const str, u32 n) const
618  {
619  if (!str)
620  return false;
621  u32 i;
622  for(i=0; i < n && array[i] && str[i]; ++i)
623  if (array[i] != str[i])
624  return false;
625 
626  // if one (or both) of the strings was smaller then they
627  // are only equal if they have the same length
628  return (i == n) || (array[i] == 0 && str[i] == 0);
629  }
630 
631 
633 
634  string<T,TAlloc>& append(T character)
635  {
636  if (used + 1 > allocated)
637  reallocate(used + 1);
638 
639  ++used;
640 
641  array[used-2] = character;
642  array[used-1] = 0;
643 
644  return *this;
645  }
646 
647 
649 
651  string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)
652  {
653  if (!other)
654  return *this;
655 
656  u32 len = 0;
657  const T* p = other;
658  while(*p)
659  {
660  ++len;
661  ++p;
662  }
663  if (len > length)
664  len = length;
665 
666  if (used + len > allocated)
667  reallocate(used + len);
668 
669  --used;
670  ++len;
671 
672  for (u32 l=0; l<len; ++l)
673  array[l+used] = *(other+l);
674 
675  used += len;
676 
677  return *this;
678  }
679 
680 
682 
684  {
685  if (other.size() == 0)
686  return *this;
687 
688  --used;
689  u32 len = other.size()+1;
690 
691  if (used + len > allocated)
692  reallocate(used + len);
693 
694  for (u32 l=0; l<len; ++l)
695  array[used+l] = other[l];
696 
697  used += len;
698 
699  return *this;
700  }
701 
702 
704 
707  {
708  if (other.size() == 0)
709  return *this;
710 
711  if (other.size() < length)
712  {
713  append(other);
714  return *this;
715  }
716 
717  if (used + length > allocated)
718  reallocate(used + length);
719 
720  --used;
721 
722  for (u32 l=0; l<length; ++l)
723  array[l+used] = other[l];
724  used += length;
725 
726  // ensure proper termination
727  array[used]=0;
728  ++used;
729 
730  return *this;
731  }
732 
734  //\param pos Insert the characters before this index
735  //\param s String to insert. Must be at least of size n
736  //\param n Number of characters from string s to use.
737  string<T,TAlloc>& insert(u32 pos, const char* s, u32 n)
738  {
739  if ( pos < used )
740  {
741  reserve(used+n);
742 
743  // move stuff behind insert point
744  const u32 end = used+n-1;
745  for (u32 i=0; i<used-pos; ++i)
746  {
747  array[end-i] = array[end-(i+n)];
748  }
749  used += n;
750 
751  for (u32 i=0; i<n; ++i)
752  {
753  array[pos+i] = s[i];
754  }
755  }
756 
757  return *this;
758  }
759 
761 
762  void reserve(u32 count)
763  {
764  if (count < allocated)
765  return;
766 
767  reallocate(count);
768  }
769 
770 
772 
775  s32 findFirst(T c) const
776  {
777  for (u32 i=0; i<used-1; ++i)
778  if (array[i] == c)
779  return i;
780 
781  return -1;
782  }
783 
785 
791  s32 findFirstChar(const T* const c, u32 count=1) const
792  {
793  if (!c || !count)
794  return -1;
795 
796  for (u32 i=0; i<used-1; ++i)
797  for (u32 j=0; j<count; ++j)
798  if (array[i] == c[j])
799  return i;
800 
801  return -1;
802  }
803 
804 
806 
812  template <class B>
813  s32 findFirstCharNotInList(const B* const c, u32 count=1) const
814  {
815  if (!c || !count)
816  return -1;
817 
818  for (u32 i=0; i<used-1; ++i)
819  {
820  u32 j;
821  for (j=0; j<count; ++j)
822  if (array[i] == c[j])
823  break;
824 
825  if (j==count)
826  return i;
827  }
828 
829  return -1;
830  }
831 
833 
839  template <class B>
840  s32 findLastCharNotInList(const B* const c, u32 count=1) const
841  {
842  if (!c || !count)
843  return -1;
844 
845  for (s32 i=(s32)(used-2); i>=0; --i)
846  {
847  u32 j;
848  for (j=0; j<count; ++j)
849  if (array[i] == c[j])
850  break;
851 
852  if (j==count)
853  return i;
854  }
855 
856  return -1;
857  }
858 
860 
864  s32 findNext(T c, u32 startPos) const
865  {
866  for (u32 i=startPos; i<used-1; ++i)
867  if (array[i] == c)
868  return i;
869 
870  return -1;
871  }
872 
873 
875 
879  s32 findLast(T c, s32 start = -1) const
880  {
881  start = core::clamp ( start < 0 ? (s32)(used) - 2 : start, 0, (s32)(used) - 2 );
882  for (s32 i=start; i>=0; --i)
883  if (array[i] == c)
884  return i;
885 
886  return -1;
887  }
888 
890 
896  s32 findLastChar(const T* const c, u32 count=1) const
897  {
898  if (!c || !count)
899  return -1;
900 
901  for (s32 i=(s32)used-2; i>=0; --i)
902  for (u32 j=0; j<count; ++j)
903  if (array[i] == c[j])
904  return i;
905 
906  return -1;
907  }
908 
909 
911 
915  template <class B>
916  s32 find(const B* const str, const u32 start = 0) const
917  {
918  if (str && *str)
919  {
920  u32 len = 0;
921 
922  while (str[len])
923  ++len;
924 
925  if (len > used-1)
926  return -1;
927 
928  for (u32 i=start; i<used-len; ++i)
929  {
930  u32 j=0;
931 
932  while(str[j] && array[i+j] == str[j])
933  ++j;
934 
935  if (!str[j])
936  return i;
937  }
938  }
939 
940  return -1;
941  }
942 
943 
945 
948  string<T> subString(u32 begin, s32 length, bool make_lower = false ) const
949  {
950  // if start after string
951  // or no proper substring length
952  if ((length <= 0) || (begin>=size()))
953  return string<T>("");
954  // clamp length to maximal value
955  if ((length+begin) > size())
956  length = size()-begin;
957 
958  string<T> o;
959  o.reserve(length+1);
960 
961  s32 i;
962  if ( !make_lower )
963  {
964  for (i=0; i<length; ++i)
965  o.array[i] = array[i+begin];
966  }
967  else
968  {
969  for (i=0; i<length; ++i)
970  o.array[i] = locale_lower ( array[i+begin] );
971  }
972 
973  o.array[length] = 0;
974  o.used = length + 1;
975 
976  return o;
977  }
978 
979 
981 
983  {
984  append(c);
985  return *this;
986  }
987 
988 
990 
991  string<T,TAlloc>& operator += (const T* const c)
992  {
993  append(c);
994  return *this;
995  }
996 
997 
999 
1001  {
1002  append(other);
1003  return *this;
1004  }
1005 
1006 
1008 
1010  {
1012  return *this;
1013  }
1014 
1015 
1017 
1018  string<T,TAlloc>& operator += (const unsigned int i)
1019  {
1021  return *this;
1022  }
1023 
1024 
1026 
1028  {
1030  return *this;
1031  }
1032 
1033 
1035 
1036  string<T,TAlloc>& operator += (const unsigned long i)
1037  {
1039  return *this;
1040  }
1041 
1042 
1044 
1046  {
1048  return *this;
1049  }
1050 
1051 
1053 
1055  {
1057  return *this;
1058  }
1059 
1060 
1062 
1064  string<T,TAlloc>& replace(T toReplace, T replaceWith)
1065  {
1066  for (u32 i=0; i<used-1; ++i)
1067  if (array[i] == toReplace)
1068  array[i] = replaceWith;
1069  return *this;
1070  }
1071 
1072 
1074 
1076  string<T,TAlloc>& replace(const string<T,TAlloc>& toReplace, const string<T,TAlloc>& replaceWith)
1077  {
1078  if (toReplace.size() == 0)
1079  return *this;
1080 
1081  const T* other = toReplace.c_str();
1082  const T* replace = replaceWith.c_str();
1083  const u32 other_size = toReplace.size();
1084  const u32 replace_size = replaceWith.size();
1085 
1086  // Determine the delta. The algorithm will change depending on the delta.
1087  s32 delta = replace_size - other_size;
1088 
1089  // A character for character replace. The string will not shrink or grow.
1090  if (delta == 0)
1091  {
1092  s32 pos = 0;
1093  while ((pos = find(other, pos)) != -1)
1094  {
1095  for (u32 i = 0; i < replace_size; ++i)
1096  array[pos + i] = replace[i];
1097  ++pos;
1098  }
1099  return *this;
1100  }
1101 
1102  // We are going to be removing some characters. The string will shrink.
1103  if (delta < 0)
1104  {
1105  u32 i = 0;
1106  for (u32 pos = 0; pos < used; ++i, ++pos)
1107  {
1108  // Is this potentially a match?
1109  if (array[pos] == *other)
1110  {
1111  // Check to see if we have a match.
1112  u32 j;
1113  for (j = 0; j < other_size; ++j)
1114  {
1115  if (array[pos + j] != other[j])
1116  break;
1117  }
1118 
1119  // If we have a match, replace characters.
1120  if (j == other_size)
1121  {
1122  for (j = 0; j < replace_size; ++j)
1123  array[i + j] = replace[j];
1124  i += replace_size - 1;
1125  pos += other_size - 1;
1126  continue;
1127  }
1128  }
1129 
1130  // No match found, just copy characters.
1131  array[i] = array[pos];
1132  }
1133  array[i-1] = 0;
1134  used = i;
1135 
1136  return *this;
1137  }
1138 
1139  // We are going to be adding characters, so the string size will increase.
1140  // Count the number of times toReplace exists in the string so we can allocate the new size.
1141  u32 find_count = 0;
1142  s32 pos = 0;
1143  while ((pos = find(other, pos)) != -1)
1144  {
1145  ++find_count;
1146  ++pos;
1147  }
1148 
1149  // Re-allocate the string now, if needed.
1150  u32 len = delta * find_count;
1151  if (used + len > allocated)
1152  reallocate(used + len);
1153 
1154  // Start replacing.
1155  pos = 0;
1156  while ((pos = find(other, pos)) != -1)
1157  {
1158  T* start = array + pos + other_size - 1;
1159  T* ptr = array + used - 1;
1160  T* end = array + delta + used -1;
1161 
1162  // Shift characters to make room for the string.
1163  while (ptr != start)
1164  {
1165  *end = *ptr;
1166  --ptr;
1167  --end;
1168  }
1169 
1170  // Add the new string now.
1171  for (u32 i = 0; i < replace_size; ++i)
1172  array[pos + i] = replace[i];
1173 
1174  pos += replace_size;
1175  used += delta;
1176  }
1177 
1178  return *this;
1179  }
1180 
1181 
1183 
1185  {
1186  u32 pos = 0;
1187  u32 found = 0;
1188  for (u32 i=0; i<used-1; ++i)
1189  {
1190  if (array[i] == c)
1191  {
1192  ++found;
1193  continue;
1194  }
1195 
1196  array[pos++] = array[i];
1197  }
1198  used -= found;
1199  array[used-1] = 0;
1200  return *this;
1201  }
1202 
1203 
1205 
1207  {
1208  u32 size = toRemove.size();
1209  if ( size == 0 )
1210  return *this;
1211  u32 pos = 0;
1212  u32 found = 0;
1213  for (u32 i=0; i<used-1; ++i)
1214  {
1215  u32 j = 0;
1216  while (j < size)
1217  {
1218  if (array[i + j] != toRemove[j])
1219  break;
1220  ++j;
1221  }
1222  if (j == size)
1223  {
1224  found += size;
1225  i += size - 1;
1226  continue;
1227  }
1228 
1229  array[pos++] = array[i];
1230  }
1231  used -= found;
1232  array[used-1] = 0;
1233  return *this;
1234  }
1235 
1236 
1238 
1240  {
1241  if (characters.size() == 0)
1242  return *this;
1243 
1244  u32 pos = 0;
1245  u32 found = 0;
1246  for (u32 i=0; i<used-1; ++i)
1247  {
1248  // Don't use characters.findFirst as it finds the \0,
1249  // causing used to become incorrect.
1250  bool docontinue = false;
1251  for (u32 j=0; j<characters.size(); ++j)
1252  {
1253  if (characters[j] == array[i])
1254  {
1255  ++found;
1256  docontinue = true;
1257  break;
1258  }
1259  }
1260  if (docontinue)
1261  continue;
1262 
1263  array[pos++] = array[i];
1264  }
1265  used -= found;
1266  array[used-1] = 0;
1267 
1268  return *this;
1269  }
1270 
1271 
1273 
1275  string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
1276  {
1277  // find start and end of the substring without the specified characters
1278  const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
1279  if (begin == -1)
1280  return (*this="");
1281 
1282  const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
1283 
1284  return (*this = subString(begin, (end +1) - begin));
1285  }
1286 
1288 
1297  {
1298  s32 i=findLastCharNotInList("0", 1);
1299  if ( i > 0 && (u32)i < used-2 ) // non 0 must be found and not last char (also used is at least 2 when i > 0)
1300  {
1301  u32 eraseStart=i+1;
1302  u32 dot=0;
1303  if( core::isdigit(array[i]) )
1304  {
1305  while( --i>0 && core::isdigit(array[i]) );
1306  if ( array[i] == decimalPoint )
1307  dot = i;
1308  }
1309  else if ( array[i] == decimalPoint )
1310  {
1311  dot = i;
1312  eraseStart = i;
1313  }
1314  if ( dot > 0 && core::isdigit(array[dot-1]) )
1315  {
1316  array[eraseStart] = 0;
1317  used = eraseStart+1;
1318  }
1319  }
1320  return *this;
1321  }
1322 
1324 
1328  {
1329  _IRR_DEBUG_BREAK_IF(index>=used) // access violation
1330 
1331  for (u32 i=index+1; i<used; ++i)
1332  array[i-1] = array[i];
1333 
1334  --used;
1335  return *this;
1336  }
1337 
1340  {
1341  // terminate on existing null
1342  for (u32 i=0; i<allocated; ++i)
1343  {
1344  if (array[i] == 0)
1345  {
1346  used = i + 1;
1347  return *this;
1348  }
1349  }
1350 
1351  // terminate
1352  if ( allocated > 0 )
1353  {
1354  used = allocated;
1355  array[used-1] = 0;
1356  }
1357  else
1358  {
1359  used = 0;
1360  }
1361 
1362  return *this;
1363  }
1364 
1366  T lastChar() const
1367  {
1368  return used > 1 ? array[used-2] : 0;
1369  }
1370 
1372 
1389  template<class container>
1390  u32 split(container& ret, const T* const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
1391  {
1392  if (!delimiter)
1393  return 0;
1394 
1395  const u32 oldSize=ret.size();
1396 
1397  u32 tokenStartIdx = 0;
1398  for (u32 i=0; i<used; ++i)
1399  {
1400  for (u32 j=0; j<countDelimiters; ++j)
1401  {
1402  if (array[i] == delimiter[j])
1403  {
1404  if ( keepSeparators )
1405  {
1406  ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], i+1 - tokenStartIdx));
1407  }
1408  else
1409  {
1410  if (i - tokenStartIdx > 0)
1411  ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], i - tokenStartIdx));
1412  else if ( !ignoreEmptyTokens )
1413  ret.push_back(string<T,TAlloc>());
1414  }
1415  tokenStartIdx = i+1;
1416  break;
1417  }
1418  }
1419  }
1420  if ((used - 1) > tokenStartIdx)
1421  ret.push_back(string<T,TAlloc>(&array[tokenStartIdx], (used - 1) - tokenStartIdx));
1422 
1423  return ret.size()-oldSize;
1424  }
1425 
1426  friend size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize);
1427 
1428 private:
1429 
1431  void reallocate(u32 new_size)
1432  {
1433  T* old_array = array;
1434 
1435  array = allocator.allocate(new_size); //new T[new_size];
1436  allocated = new_size;
1437 
1438  u32 amount = used < new_size ? used : new_size;
1439  for (u32 i=0; i<amount; ++i)
1440  array[i] = old_array[i];
1441 
1442  if (allocated < used)
1443  used = allocated;
1444 
1445  allocator.deallocate(old_array); // delete [] old_array;
1446  }
1447 
1448  //--- member variables
1449 
1450  T* array;
1451  u32 allocated;
1452  u32 used;
1453  TAlloc allocator;
1454 };
1455 
1456 
1459 
1462 
1464 
1469 static inline size_t multibyteToWString(string<wchar_t>& destination, const core::string<c8>& source)
1470 {
1471  return multibyteToWString(destination, source.c_str(), (u32)source.size());
1472 }
1473 
1475 
1480 static inline size_t multibyteToWString(string<wchar_t>& destination, const char* source)
1481 {
1482  u32 s = source ? (u32)strlen(source) : 0;
1483  return multibyteToWString(destination, source, s);
1484 }
1485 
1487 static size_t multibyteToWString(string<wchar_t>& destination, const char* source, u32 sourceSize)
1488 {
1489  if ( sourceSize )
1490  {
1491  destination.reserve(sourceSize+1);
1492 #if defined(_MSC_VER)
1493 #pragma warning(push)
1494 #pragma warning(disable: 4996) // 'mbstowcs': This function or variable may be unsafe. Consider using mbstowcs_s instead.
1495 #endif
1496  size_t written = mbstowcs(destination.array, source, (size_t)sourceSize);
1497 #if defined(_MSC_VER)
1498 #pragma warning(pop)
1499 #endif
1500  if ( written != (size_t)-1 )
1501  {
1502  destination.used = (u32)written+1;
1503  destination.array[destination.used-1] = 0;
1504  }
1505  else
1506  {
1507  // Likely character which got converted until the invalid character was encountered are in destination now.
1508  // And it seems even 0-terminated, but I found no documentation anywhere that this (the 0-termination) is guaranteed :-(
1509  destination.clear();
1510  }
1511  return written;
1512  }
1513  else
1514  {
1515  destination.clear();
1516  return 0;
1517  }
1518 }
1519 
1520 
1521 } // end namespace core
1522 } // end namespace irr
1523 
1524 #endif
1525 
string(long number)
Constructs a string from a long.
Definition: irrString.h:215
bool empty() const
Definition: irrString.h:509
s32 findFirstCharNotInList(const B *const c, u32 count=1) const
Finds first position of a character not in a given list.
Definition: irrString.h:813
unsigned long long u64
64 bit unsigned variable.
Definition: irrTypes.h:86
IRRLICHT_API void utf8ToWchar(const char *in, wchar_t *out, const u64 len)
Convert this utf-8-encoded string to the platform's wchar.
u32 split(container &ret, const T *const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
Split string into parts (tokens).
Definition: irrString.h:1390
T & operator [](const u32 index)
Direct access operator.
Definition: irrString.h:430
u32 size() const
Returns length of the string's content.
Definition: irrString.h:502
string< T, TAlloc > & append(T character)
Appends a character to this string.
Definition: irrString.h:634
string< T, TAlloc > & remove(T c)
Removes characters from a string.
Definition: irrString.h:1184
bool equals_substring_ignore_case(const string< T, TAlloc > &other, const s32 sourcePos=0) const
Compares the strings ignoring case.
Definition: irrString.h:566
s32 findLast(T c, s32 start=-1) const
finds last occurrence of character in string
Definition: irrString.h:879
string(const B *const c)
Constructor for Unicode and ASCII strings.
Definition: irrString.h:317
string< T, TAlloc > operator+(const B *const c) const
Append operator for strings, ASCII and Unicode.
Definition: irrString.h:420
char c8
8 bit character variable.
Definition: irrTypes.h:35
string(const double number)
Constructs a string from a float.
Definition: irrString.h:126
s32 find(const B *const str, const u32 start=0) const
finds another string in this string
Definition: irrString.h:916
#define IRRLICHT_API
Set FPU settings.
~string()
Destructor.
Definition: irrString.h:325
s32 isdigit(s32 c)
some standard function ( to remove dependencies )
Definition: coreutil.h:199
string< T, TAlloc > & operator=(const string< B, A > &other)
Assignment operator for other string types.
Definition: irrString.h:354
const T & operator [](const u32 index) const
Direct access operator.
Definition: irrString.h:438
Everything in the Irrlicht Engine can be found in this namespace.
Definition: aabbox3d.h:12
Very simple string class with some useful features.
Definition: irrString.h:37
string< T, TAlloc > & operator=(const string< T, TAlloc > &other)
Assignment operator.
Definition: irrString.h:332
bool operator==(const string< T, TAlloc > &other) const
Equality operator.
Definition: irrString.h:461
bool operator!=(const T *const str) const
Inequality operator.
Definition: irrString.h:486
void reserve(u32 count)
Reserves some memory.
Definition: irrString.h:762
string< T, TAlloc > & eraseTrailingFloatZeros(char decimalPoint='.')
Erase 0's at the end when a string ends with a floating point number.
Definition: irrString.h:1296
string< T, TAlloc > & trim(const string< T, TAlloc > &whitespace=" \t\n\r")
Trims the string.
Definition: irrString.h:1275
s32 findLastChar(const T *const c, u32 count=1) const
finds last occurrence of a character of a list in string
Definition: irrString.h:896
s32 findFirst(T c) const
finds first occurrence of character in string
Definition: irrString.h:775
string< T, TAlloc > & make_upper()
Makes the string upper case.
Definition: irrString.h:542
string(unsigned int number)
Constructs a string from an unsigned int.
Definition: irrString.h:184
s32 findLastCharNotInList(const B *const c, u32 count=1) const
Finds last position of a character not in a given list.
Definition: irrString.h:840
signed int s32
32 bit signed variable.
Definition: irrTypes.h:70
string< T, TAlloc > & append(const string< T, TAlloc > &other, u32 length)
Appends a string of the length l to this string.
Definition: irrString.h:706
string< T, TAlloc > & replace(const string< T, TAlloc > &toReplace, const string< T, TAlloc > &replaceWith)
Replaces all instances of a string with another one.
Definition: irrString.h:1076
void clear(bool releaseMemory=true)
Definition: irrString.h:514
const T * c_str() const
Returns character string.
Definition: irrString.h:526
unsigned int u32
32 bit unsigned variable.
Definition: irrTypes.h:62
string(unsigned long number)
Constructs a string from an unsigned long.
Definition: irrString.h:263
IRRLICHT_API void wcharToUtf8(const wchar_t *in, char *out, const u64 len)
Convert this wchar string to utf-8.
bool operator==(const T *const str) const
Equality operator.
Definition: irrString.h:446
string< T, TAlloc > & make_lower()
Makes the string lower case.
Definition: irrString.h:533
T lastChar() const
gets the last char of a string or null
Definition: irrString.h:1366
string< T, TAlloc > & operator=(const B *const c)
Assignment operator for strings, ASCII and Unicode.
Definition: irrString.h:363
string< T, TAlloc > & removeChars(const string< T, TAlloc > &characters)
Removes characters from a string.
Definition: irrString.h:1239
#define _IRR_DEBUG_BREAK_IF(_CONDITION_)
define a break macro for debugging.
Definition: irrTypes.h:185
string< c8 > stringc
Typedef for character strings.
Definition: irrString.h:1458
string< T, TAlloc > & remove(const string< T, TAlloc > &toRemove)
Removes a string from the string.
Definition: irrString.h:1206
bool equalsn(const T *const str, u32 n) const
compares the first n characters of the strings
Definition: irrString.h:617
string< T, TAlloc > & replace(T toReplace, T replaceWith)
Replaces all characters of a special type with another one.
Definition: irrString.h:1064
string()
Default constructor.
Definition: irrString.h:101
string(const string< B, A > &other)
Constructor from other string types.
Definition: irrString.h:118
string< T, TAlloc > & append(const T *const other, u32 length=0xffffffff)
Appends a char string to this string.
Definition: irrString.h:651
bool operator<(const string< T, TAlloc > &other) const
Is smaller comparator.
Definition: irrString.h:472
string< T > subString(u32 begin, s32 length, bool make_lower=false) const
Returns a substring.
Definition: irrString.h:948
string< T, TAlloc > & insert(u32 pos, const char *s, u32 n)
Insert a certain amount of characters into the string before the given index.
Definition: irrString.h:737
#define snprintf_irr
Definition: irrTypes.h:149
Self reallocating template array (like stl vector) with additional features.
Definition: irrArray.h:22
s32 findFirstChar(const T *const c, u32 count=1) const
finds first occurrence of a character of a list in string
Definition: irrString.h:791
string(const string< T, TAlloc > &other)
Constructor.
Definition: irrString.h:110
friend size_t multibyteToWString(string< wchar_t > &destination, const char *source, u32 sourceSize)
Internally used by the other multibyteToWString functions.
Definition: irrString.h:1487
bool equals_ignore_case(const string< T, TAlloc > &other) const
Compares the strings ignoring case.
Definition: irrString.h:553
bool lower_ignore_case(const string< T, TAlloc > &other) const
Compares the strings ignoring case.
Definition: irrString.h:583
bool equalsn(const string< T, TAlloc > &other, u32 n) const
compares the first n characters of the strings
Definition: irrString.h:600
string< T, TAlloc > & operator+=(T c)
Appends a character to this string.
Definition: irrString.h:982
s32 findNext(T c, u32 startPos) const
finds next occurrence of character in string
Definition: irrString.h:864
string< T, TAlloc > & append(const string< T, TAlloc > &other)
Appends a string to this string.
Definition: irrString.h:683
string< T, TAlloc > & validate()
verify the existing string.
Definition: irrString.h:1339
bool operator!=(const string< T, TAlloc > &other) const
Inequality operator.
Definition: irrString.h:493
string(const B *const c, u32 length)
Constructor for copying a string from a pointer with a given length.
Definition: irrString.h:295
string< T, TAlloc > operator+(const string< T, TAlloc > &other) const
Append operator for other strings.
Definition: irrString.h:409
const T clamp(const T &value, const T &low, const T &high)
clamps a value between low and high
Definition: irrMath.h:167
string< T, TAlloc > & erase(u32 index)
Erases a character from the string.
Definition: irrString.h:1327
string(int number)
Constructs a string from an int.
Definition: irrString.h:136
string< wchar_t > stringw
Typedef for wide character strings.
Definition: irrString.h:1461