aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/include/irrString.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/include/irrString.h')
-rw-r--r--src/others/irrlicht-1.8.1/include/irrString.h1368
1 files changed, 1368 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/include/irrString.h b/src/others/irrlicht-1.8.1/include/irrString.h
new file mode 100644
index 0000000..43557cd
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/include/irrString.h
@@ -0,0 +1,1368 @@
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
15namespace irr
16{
17namespace core
18{
19
20//! Very simple string class with some useful features.
21/** string<c8> and string<wchar_t> both accept Unicode AND ASCII/Latin-1,
22so you can assign Unicode to string<c8> and ASCII/Latin-1 to string<wchar_t>
23(and the other way round) if you want to.
24
25However, note that the conversation between both is not done using any encoding.
26This means that c8 strings are treated as ASCII/Latin-1, not UTF-8, and
27are simply expanded to the equivalent wchar_t, while Unicode/wchar_t
28characters are truncated to 8-bit ASCII/Latin-1 characters, discarding all
29other information in the wchar_t.
30*/
31
32enum eLocaleID
33{
34 IRR_LOCALE_ANSI = 0,
35 IRR_LOCALE_GERMAN = 1
36};
37
38static eLocaleID locale_current = IRR_LOCALE_ANSI;
39static inline void locale_set ( eLocaleID id )
40{
41 locale_current = id;
42}
43
44//! Returns a character converted to lower case
45static 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
57//! Returns a character converted to upper case
58static 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
72template <typename T, typename TAlloc = irrAllocator<T> >
73class string
74{
75public:
76
77 typedef T char_type;
78
79 //! Default constructor
80 string()
81 : array(0), allocated(1), used(1)
82 {
83 array = allocator.allocate(1); // new T[1];
84 array[0] = 0;
85 }
86
87
88 //! Constructor
89 string(const string<T,TAlloc>& other)
90 : array(0), allocated(0), used(0)
91 {
92 *this = other;
93 }
94
95 //! Constructor from other string types
96 template <class B, class A>
97 string(const string<B, A>& other)
98 : array(0), allocated(0), used(0)
99 {
100 *this = other;
101 }
102
103
104 //! Constructs a string from a float
105 explicit string(const double number)
106 : array(0), allocated(0), used(0)
107 {
108 c8 tmpbuf[255];
109 snprintf(tmpbuf, 255, "%0.6f", number);
110 *this = tmpbuf;
111 }
112
113
114 //! Constructs a string from an int
115 explicit string(int number)
116 : array(0), allocated(0), used(0)
117 {
118 // store if negative and make positive
119
120 bool negative = false;
121 if (number < 0)
122 {
123 number *= -1;
124 negative = true;
125 }
126
127 // temporary buffer for 16 numbers
128
129 c8 tmpbuf[16]={0};
130 u32 idx = 15;
131
132 // special case '0'
133
134 if (!number)
135 {
136 tmpbuf[14] = '0';
137 *this = &tmpbuf[14];
138 return;
139 }
140
141 // add numbers
142
143 while(number && idx)
144 {
145 --idx;
146 tmpbuf[idx] = (c8)('0' + (number % 10));
147 number /= 10;
148 }
149
150 // add sign
151
152 if (negative)
153 {
154 --idx;
155 tmpbuf[idx] = '-';
156 }
157
158 *this = &tmpbuf[idx];
159 }
160
161
162 //! Constructs a string from an unsigned int
163 explicit string(unsigned int number)
164 : array(0), allocated(0), used(0)
165 {
166 // temporary buffer for 16 numbers
167
168 c8 tmpbuf[16]={0};
169 u32 idx = 15;
170
171 // special case '0'
172
173 if (!number)
174 {
175 tmpbuf[14] = '0';
176 *this = &tmpbuf[14];
177 return;
178 }
179
180 // add numbers
181
182 while(number && idx)
183 {
184 --idx;
185 tmpbuf[idx] = (c8)('0' + (number % 10));
186 number /= 10;
187 }
188
189 *this = &tmpbuf[idx];
190 }
191
192
193 //! Constructs a string from a long
194 explicit string(long number)
195 : array(0), allocated(0), used(0)
196 {
197 // store if negative and make positive
198
199 bool negative = false;
200 if (number < 0)
201 {
202 number *= -1;
203 negative = true;
204 }
205
206 // temporary buffer for 16 numbers
207
208 c8 tmpbuf[16]={0};
209 u32 idx = 15;
210
211 // special case '0'
212
213 if (!number)
214 {
215 tmpbuf[14] = '0';
216 *this = &tmpbuf[14];
217 return;
218 }
219
220 // add numbers
221
222 while(number && idx)
223 {
224 --idx;
225 tmpbuf[idx] = (c8)('0' + (number % 10));
226 number /= 10;
227 }
228
229 // add sign
230
231 if (negative)
232 {
233 --idx;
234 tmpbuf[idx] = '-';
235 }
236
237 *this = &tmpbuf[idx];
238 }
239
240
241 //! Constructs a string from an unsigned long
242 explicit string(unsigned long number)
243 : array(0), allocated(0), used(0)
244 {
245 // temporary buffer for 16 numbers
246
247 c8 tmpbuf[16]={0};
248 u32 idx = 15;
249
250 // special case '0'
251
252 if (!number)
253 {
254 tmpbuf[14] = '0';
255 *this = &tmpbuf[14];
256 return;
257 }
258
259 // add numbers
260
261 while(number && idx)
262 {
263 --idx;
264 tmpbuf[idx] = (c8)('0' + (number % 10));
265 number /= 10;
266 }
267
268 *this = &tmpbuf[idx];
269 }
270
271
272 //! Constructor for copying a string from a pointer with a given length
273 template <class B>
274 string(const B* const c, u32 length)
275 : array(0), allocated(0), used(0)
276 {
277 if (!c)
278 {
279 // correctly init the string to an empty one
280 *this="";
281 return;
282 }
283
284 allocated = used = length+1;
285 array = allocator.allocate(used); // new T[used];
286
287 for (u32 l = 0; l<length; ++l)
288 array[l] = (T)c[l];
289
290 array[length] = 0;
291 }
292
293
294 //! Constructor for unicode and ascii strings
295 template <class B>
296 string(const B* const c)
297 : array(0), allocated(0), used(0)
298 {
299 *this = c;
300 }
301
302
303 //! Destructor
304 ~string()
305 {
306 allocator.deallocate(array); // delete [] array;
307 }
308
309
310 //! Assignment operator
311 string<T,TAlloc>& operator=(const string<T,TAlloc>& other)
312 {
313 if (this == &other)
314 return *this;
315
316 used = other.size()+1;
317 if (used>allocated)
318 {
319 allocator.deallocate(array); // delete [] array;
320 allocated = used;
321 array = allocator.allocate(used); //new T[used];
322 }
323
324 const T* p = other.c_str();
325 for (u32 i=0; i<used; ++i, ++p)
326 array[i] = *p;
327
328 return *this;
329 }
330
331 //! Assignment operator for other string types
332 template <class B, class A>
333 string<T,TAlloc>& operator=(const string<B,A>& other)
334 {
335 *this = other.c_str();
336 return *this;
337 }
338
339
340 //! Assignment operator for strings, ascii and unicode
341 template <class B>
342 string<T,TAlloc>& operator=(const B* const c)
343 {
344 if (!c)
345 {
346 if (!array)
347 {
348 array = allocator.allocate(1); //new T[1];
349 allocated = 1;
350 }
351 used = 1;
352 array[0] = 0x0;
353 return *this;
354 }
355
356 if ((void*)c == (void*)array)
357 return *this;
358
359 u32 len = 0;
360 const B* p = c;
361 do
362 {
363 ++len;
364 } while(*p++);
365
366 // we'll keep the old string for a while, because the new
367 // string could be a part of the current string.
368 T* oldArray = array;
369
370 used = len;
371 if (used>allocated)
372 {
373 allocated = used;
374 array = allocator.allocate(used); //new T[used];
375 }
376
377 for (u32 l = 0; l<len; ++l)
378 array[l] = (T)c[l];
379
380 if (oldArray != array)
381 allocator.deallocate(oldArray); // delete [] oldArray;
382
383 return *this;
384 }
385
386
387 //! Append operator for other strings
388 string<T,TAlloc> operator+(const string<T,TAlloc>& other) const
389 {
390 string<T,TAlloc> str(*this);
391 str.append(other);
392
393 return str;
394 }
395
396
397 //! Append operator for strings, ascii and unicode
398 template <class B>
399 string<T,TAlloc> operator+(const B* const c) const
400 {
401 string<T,TAlloc> str(*this);
402 str.append(c);
403
404 return str;
405 }
406
407
408 //! Direct access operator
409 T& operator [](const u32 index)
410 {
411 _IRR_DEBUG_BREAK_IF(index>=used) // bad index
412 return array[index];
413 }
414
415
416 //! Direct access operator
417 const T& operator [](const u32 index) const
418 {
419 _IRR_DEBUG_BREAK_IF(index>=used) // bad index
420 return array[index];
421 }
422
423
424 //! Equality operator
425 bool operator==(const T* const str) const
426 {
427 if (!str)
428 return false;
429
430 u32 i;
431 for (i=0; array[i] && str[i]; ++i)
432 if (array[i] != str[i])
433 return false;
434
435 return (!array[i] && !str[i]);
436 }
437
438
439 //! Equality operator
440 bool operator==(const string<T,TAlloc>& other) const
441 {
442 for (u32 i=0; array[i] && other.array[i]; ++i)
443 if (array[i] != other.array[i])
444 return false;
445
446 return used == other.used;
447 }
448
449
450 //! Is smaller comparator
451 bool operator<(const string<T,TAlloc>& other) const
452 {
453 for (u32 i=0; array[i] && other.array[i]; ++i)
454 {
455 const s32 diff = array[i] - other.array[i];
456 if (diff)
457 return (diff < 0);
458 }
459
460 return (used < other.used);
461 }
462
463
464 //! Inequality operator
465 bool operator!=(const T* const str) const
466 {
467 return !(*this == str);
468 }
469
470
471 //! Inequality operator
472 bool operator!=(const string<T,TAlloc>& other) const
473 {
474 return !(*this == other);
475 }
476
477
478 //! Returns length of the string's content
479 /** \return Length of the string's content in characters, excluding
480 the trailing NUL. */
481 u32 size() const
482 {
483 return used-1;
484 }
485
486 //! Informs if the string is empty or not.
487 //! \return True if the string is empty, false if not.
488 bool empty() const
489 {
490 return (size() == 0);
491 }
492
493 //! Returns character string
494 /** \return pointer to C-style NUL terminated string. */
495 const T* c_str() const
496 {
497 return array;
498 }
499
500
501 //! Makes the string lower case.
502 string<T,TAlloc>& make_lower()
503 {
504 for (u32 i=0; array[i]; ++i)
505 array[i] = locale_lower ( array[i] );
506 return *this;
507 }
508
509
510 //! Makes the string upper case.
511 string<T,TAlloc>& make_upper()
512 {
513 for (u32 i=0; array[i]; ++i)
514 array[i] = locale_upper ( array[i] );
515 return *this;
516 }
517
518
519 //! Compares the strings ignoring case.
520 /** \param other: Other string to compare.
521 \return True if the strings are equal ignoring case. */
522 bool equals_ignore_case(const string<T,TAlloc>& other) const
523 {
524 for(u32 i=0; array[i] && other[i]; ++i)
525 if (locale_lower( array[i]) != locale_lower(other[i]))
526 return false;
527
528 return used == other.used;
529 }
530
531 //! Compares the strings ignoring case.
532 /** \param other: Other string to compare.
533 \param sourcePos: where to start to compare in the string
534 \return True if the strings are equal ignoring case. */
535 bool equals_substring_ignore_case(const string<T,TAlloc>&other, const s32 sourcePos = 0 ) const
536 {
537 if ( (u32) sourcePos >= used )
538 return false;
539
540 u32 i;
541 for( i=0; array[sourcePos + i] && other[i]; ++i)
542 if (locale_lower( array[sourcePos + i]) != locale_lower(other[i]))
543 return false;
544
545 return array[sourcePos + i] == 0 && other[i] == 0;
546 }
547
548
549 //! Compares the strings ignoring case.
550 /** \param other: Other string to compare.
551 \return True if this string is smaller ignoring case. */
552 bool lower_ignore_case(const string<T,TAlloc>& other) const
553 {
554 for(u32 i=0; array[i] && other.array[i]; ++i)
555 {
556 s32 diff = (s32) locale_lower ( array[i] ) - (s32) locale_lower ( other.array[i] );
557 if ( diff )
558 return diff < 0;
559 }
560
561 return used < other.used;
562 }
563
564
565 //! compares the first n characters of the strings
566 /** \param other Other string to compare.
567 \param n Number of characters to compare
568 \return True if the n first characters of both strings are equal. */
569 bool equalsn(const string<T,TAlloc>& other, u32 n) const
570 {
571 u32 i;
572 for(i=0; array[i] && other[i] && i < n; ++i)
573 if (array[i] != other[i])
574 return false;
575
576 // if one (or both) of the strings was smaller then they
577 // are only equal if they have the same length
578 return (i == n) || (used == other.used);
579 }
580
581
582 //! compares the first n characters of the strings
583 /** \param str Other string to compare.
584 \param n Number of characters to compare
585 \return True if the n first characters of both strings are equal. */
586 bool equalsn(const T* const str, u32 n) const
587 {
588 if (!str)
589 return false;
590 u32 i;
591 for(i=0; array[i] && str[i] && i < n; ++i)
592 if (array[i] != str[i])
593 return false;
594
595 // if one (or both) of the strings was smaller then they
596 // are only equal if they have the same length
597 return (i == n) || (array[i] == 0 && str[i] == 0);
598 }
599
600
601 //! Appends a character to this string
602 /** \param character: Character to append. */
603 string<T,TAlloc>& append(T character)
604 {
605 if (used + 1 > allocated)
606 reallocate(used + 1);
607
608 ++used;
609
610 array[used-2] = character;
611 array[used-1] = 0;
612
613 return *this;
614 }
615
616
617 //! Appends a char string to this string
618 /** \param other: Char string to append. */
619 /** \param length: The length of the string to append. */
620 string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)
621 {
622 if (!other)
623 return *this;
624
625 u32 len = 0;
626 const T* p = other;
627 while(*p)
628 {
629 ++len;
630 ++p;
631 }
632 if (len > length)
633 len = length;
634
635 if (used + len > allocated)
636 reallocate(used + len);
637
638 --used;
639 ++len;
640
641 for (u32 l=0; l<len; ++l)
642 array[l+used] = *(other+l);
643
644 used += len;
645
646 return *this;
647 }
648
649
650 //! Appends a string to this string
651 /** \param other: String to append. */
652 string<T,TAlloc>& append(const string<T,TAlloc>& other)
653 {
654 if (other.size() == 0)
655 return *this;
656
657 --used;
658 u32 len = other.size()+1;
659
660 if (used + len > allocated)
661 reallocate(used + len);
662
663 for (u32 l=0; l<len; ++l)
664 array[used+l] = other[l];
665
666 used += len;
667
668 return *this;
669 }
670
671
672 //! Appends a string of the length l to this string.
673 /** \param other: other String to append to this string.
674 \param length: How much characters of the other string to add to this one. */
675 string<T,TAlloc>& append(const string<T,TAlloc>& other, u32 length)
676 {
677 if (other.size() == 0)
678 return *this;
679
680 if (other.size() < length)
681 {
682 append(other);
683 return *this;
684 }
685
686 if (used + length > allocated)
687 reallocate(used + length);
688
689 --used;
690
691 for (u32 l=0; l<length; ++l)
692 array[l+used] = other[l];
693 used += length;
694
695 // ensure proper termination
696 array[used]=0;
697 ++used;
698
699 return *this;
700 }
701
702
703 //! Reserves some memory.
704 /** \param count: Amount of characters to reserve. */
705 void reserve(u32 count)
706 {
707 if (count < allocated)
708 return;
709
710 reallocate(count);
711 }
712
713
714 //! finds first occurrence of character in string
715 /** \param c: Character to search for.
716 \return Position where the character has been found,
717 or -1 if not found. */
718 s32 findFirst(T c) const
719 {
720 for (u32 i=0; i<used-1; ++i)
721 if (array[i] == c)
722 return i;
723
724 return -1;
725 }
726
727 //! finds first occurrence of a character of a list in string
728 /** \param c: List of characters to find. For example if the method
729 should find the first occurrence of 'a' or 'b', this parameter should be "ab".
730 \param count: Amount of characters in the list. Usually,
731 this should be strlen(c)
732 \return Position where one of the characters has been found,
733 or -1 if not found. */
734 s32 findFirstChar(const T* const c, u32 count=1) const
735 {
736 if (!c || !count)
737 return -1;
738
739 for (u32 i=0; i<used-1; ++i)
740 for (u32 j=0; j<count; ++j)
741 if (array[i] == c[j])
742 return i;
743
744 return -1;
745 }
746
747
748 //! Finds first position of a character not in a given list.
749 /** \param c: List of characters not to find. For example if the method
750 should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
751 \param count: Amount of characters in the list. Usually,
752 this should be strlen(c)
753 \return Position where the character has been found,
754 or -1 if not found. */
755 template <class B>
756 s32 findFirstCharNotInList(const B* const c, u32 count=1) const
757 {
758 if (!c || !count)
759 return -1;
760
761 for (u32 i=0; i<used-1; ++i)
762 {
763 u32 j;
764 for (j=0; j<count; ++j)
765 if (array[i] == c[j])
766 break;
767
768 if (j==count)
769 return i;
770 }
771
772 return -1;
773 }
774
775 //! Finds last position of a character not in a given list.
776 /** \param c: List of characters not to find. For example if the method
777 should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
778 \param count: Amount of characters in the list. Usually,
779 this should be strlen(c)
780 \return Position where the character has been found,
781 or -1 if not found. */
782 template <class B>
783 s32 findLastCharNotInList(const B* const c, u32 count=1) const
784 {
785 if (!c || !count)
786 return -1;
787
788 for (s32 i=(s32)(used-2); i>=0; --i)
789 {
790 u32 j;
791 for (j=0; j<count; ++j)
792 if (array[i] == c[j])
793 break;
794
795 if (j==count)
796 return i;
797 }
798
799 return -1;
800 }
801
802 //! finds next occurrence of character in string
803 /** \param c: Character to search for.
804 \param startPos: Position in string to start searching.
805 \return Position where the character has been found,
806 or -1 if not found. */
807 s32 findNext(T c, u32 startPos) const
808 {
809 for (u32 i=startPos; i<used-1; ++i)
810 if (array[i] == c)
811 return i;
812
813 return -1;
814 }
815
816
817 //! finds last occurrence of character in string
818 /** \param c: Character to search for.
819 \param start: start to search reverse ( default = -1, on end )
820 \return Position where the character has been found,
821 or -1 if not found. */
822 s32 findLast(T c, s32 start = -1) const
823 {
824 start = core::clamp ( start < 0 ? (s32)(used) - 2 : start, 0, (s32)(used) - 2 );
825 for (s32 i=start; i>=0; --i)
826 if (array[i] == c)
827 return i;
828
829 return -1;
830 }
831
832 //! finds last occurrence of a character of a list in string
833 /** \param c: List of strings to find. For example if the method
834 should find the last occurrence of 'a' or 'b', this parameter should be "ab".
835 \param count: Amount of characters in the list. Usually,
836 this should be strlen(c)
837 \return Position where one of the characters has been found,
838 or -1 if not found. */
839 s32 findLastChar(const T* const c, u32 count=1) const
840 {
841 if (!c || !count)
842 return -1;
843
844 for (s32 i=(s32)used-2; i>=0; --i)
845 for (u32 j=0; j<count; ++j)
846 if (array[i] == c[j])
847 return i;
848
849 return -1;
850 }
851
852
853 //! finds another string in this string
854 /** \param str: Another string
855 \param start: Start position of the search
856 \return Positions where the string has been found,
857 or -1 if not found. */
858 template <class B>
859 s32 find(const B* const str, const u32 start = 0) const
860 {
861 if (str && *str)
862 {
863 u32 len = 0;
864
865 while (str[len])
866 ++len;
867
868 if (len > used-1)
869 return -1;
870
871 for (u32 i=start; i<used-len; ++i)
872 {
873 u32 j=0;
874
875 while(str[j] && array[i+j] == str[j])
876 ++j;
877
878 if (!str[j])
879 return i;
880 }
881 }
882
883 return -1;
884 }
885
886
887 //! Returns a substring
888 /** \param begin Start of substring.
889 \param length Length of substring.
890 \param make_lower copy only lower case */
891 string<T> subString(u32 begin, s32 length, bool make_lower = false ) const
892 {
893 // if start after string
894 // or no proper substring length
895 if ((length <= 0) || (begin>=size()))
896 return string<T>("");
897 // clamp length to maximal value
898 if ((length+begin) > size())
899 length = size()-begin;
900
901 string<T> o;
902 o.reserve(length+1);
903
904 s32 i;
905 if ( !make_lower )
906 {
907 for (i=0; i<length; ++i)
908 o.array[i] = array[i+begin];
909 }
910 else
911 {
912 for (i=0; i<length; ++i)
913 o.array[i] = locale_lower ( array[i+begin] );
914 }
915
916 o.array[length] = 0;
917 o.used = length + 1;
918
919 return o;
920 }
921
922
923 //! Appends a character to this string
924 /** \param c Character to append. */
925 string<T,TAlloc>& operator += (T c)
926 {
927 append(c);
928 return *this;
929 }
930
931
932 //! Appends a char string to this string
933 /** \param c Char string to append. */
934 string<T,TAlloc>& operator += (const T* const c)
935 {
936 append(c);
937 return *this;
938 }
939
940
941 //! Appends a string to this string
942 /** \param other String to append. */
943 string<T,TAlloc>& operator += (const string<T,TAlloc>& other)
944 {
945 append(other);
946 return *this;
947 }
948
949
950 //! Appends a string representation of a number to this string
951 /** \param i Number to append. */
952 string<T,TAlloc>& operator += (const int i)
953 {
954 append(string<T,TAlloc>(i));
955 return *this;
956 }
957
958
959 //! Appends a string representation of a number to this string
960 /** \param i Number to append. */
961 string<T,TAlloc>& operator += (const unsigned int i)
962 {
963 append(string<T,TAlloc>(i));
964 return *this;
965 }
966
967
968 //! Appends a string representation of a number to this string
969 /** \param i Number to append. */
970 string<T,TAlloc>& operator += (const long i)
971 {
972 append(string<T,TAlloc>(i));
973 return *this;
974 }
975
976
977 //! Appends a string representation of a number to this string
978 /** \param i Number to append. */
979 string<T,TAlloc>& operator += (const unsigned long i)
980 {
981 append(string<T,TAlloc>(i));
982 return *this;
983 }
984
985
986 //! Appends a string representation of a number to this string
987 /** \param i Number to append. */
988 string<T,TAlloc>& operator += (const double i)
989 {
990 append(string<T,TAlloc>(i));
991 return *this;
992 }
993
994
995 //! Appends a string representation of a number to this string
996 /** \param i Number to append. */
997 string<T,TAlloc>& operator += (const float i)
998 {
999 append(string<T,TAlloc>(i));
1000 return *this;
1001 }
1002
1003
1004 //! Replaces all characters of a special type with another one
1005 /** \param toReplace Character to replace.
1006 \param replaceWith Character replacing the old one. */
1007 string<T,TAlloc>& replace(T toReplace, T replaceWith)
1008 {
1009 for (u32 i=0; i<used-1; ++i)
1010 if (array[i] == toReplace)
1011 array[i] = replaceWith;
1012 return *this;
1013 }
1014
1015
1016 //! Replaces all instances of a string with another one.
1017 /** \param toReplace The string to replace.
1018 \param replaceWith The string replacing the old one. */
1019 string<T,TAlloc>& replace(const string<T,TAlloc>& toReplace, const string<T,TAlloc>& replaceWith)
1020 {
1021 if (toReplace.size() == 0)
1022 return *this;
1023
1024 const T* other = toReplace.c_str();
1025 const T* replace = replaceWith.c_str();
1026 const u32 other_size = toReplace.size();
1027 const u32 replace_size = replaceWith.size();
1028
1029 // Determine the delta. The algorithm will change depending on the delta.
1030 s32 delta = replace_size - other_size;
1031
1032 // A character for character replace. The string will not shrink or grow.
1033 if (delta == 0)
1034 {
1035 s32 pos = 0;
1036 while ((pos = find(other, pos)) != -1)
1037 {
1038 for (u32 i = 0; i < replace_size; ++i)
1039 array[pos + i] = replace[i];
1040 ++pos;
1041 }
1042 return *this;
1043 }
1044
1045 // We are going to be removing some characters. The string will shrink.
1046 if (delta < 0)
1047 {
1048 u32 i = 0;
1049 for (u32 pos = 0; pos < used; ++i, ++pos)
1050 {
1051 // Is this potentially a match?
1052 if (array[pos] == *other)
1053 {
1054 // Check to see if we have a match.
1055 u32 j;
1056 for (j = 0; j < other_size; ++j)
1057 {
1058 if (array[pos + j] != other[j])
1059 break;
1060 }
1061
1062 // If we have a match, replace characters.
1063 if (j == other_size)
1064 {
1065 for (j = 0; j < replace_size; ++j)
1066 array[i + j] = replace[j];
1067 i += replace_size - 1;
1068 pos += other_size - 1;
1069 continue;
1070 }
1071 }
1072
1073 // No match found, just copy characters.
1074 array[i] = array[pos];
1075 }
1076 array[i-1] = 0;
1077 used = i;
1078
1079 return *this;
1080 }
1081
1082 // We are going to be adding characters, so the string size will increase.
1083 // Count the number of times toReplace exists in the string so we can allocate the new size.
1084 u32 find_count = 0;
1085 s32 pos = 0;
1086 while ((pos = find(other, pos)) != -1)
1087 {
1088 ++find_count;
1089 ++pos;
1090 }
1091
1092 // Re-allocate the string now, if needed.
1093 u32 len = delta * find_count;
1094 if (used + len > allocated)
1095 reallocate(used + len);
1096
1097 // Start replacing.
1098 pos = 0;
1099 while ((pos = find(other, pos)) != -1)
1100 {
1101 T* start = array + pos + other_size - 1;
1102 T* ptr = array + used - 1;
1103 T* end = array + delta + used -1;
1104
1105 // Shift characters to make room for the string.
1106 while (ptr != start)
1107 {
1108 *end = *ptr;
1109 --ptr;
1110 --end;
1111 }
1112
1113 // Add the new string now.
1114 for (u32 i = 0; i < replace_size; ++i)
1115 array[pos + i] = replace[i];
1116
1117 pos += replace_size;
1118 used += delta;
1119 }
1120
1121 return *this;
1122 }
1123
1124
1125 //! Removes characters from a string.
1126 /** \param c: Character to remove. */
1127 string<T,TAlloc>& remove(T c)
1128 {
1129 u32 pos = 0;
1130 u32 found = 0;
1131 for (u32 i=0; i<used-1; ++i)
1132 {
1133 if (array[i] == c)
1134 {
1135 ++found;
1136 continue;
1137 }
1138
1139 array[pos++] = array[i];
1140 }
1141 used -= found;
1142 array[used-1] = 0;
1143 return *this;
1144 }
1145
1146
1147 //! Removes a string from the string.
1148 /** \param toRemove: String to remove. */
1149 string<T,TAlloc>& remove(const string<T,TAlloc>& toRemove)
1150 {
1151 u32 size = toRemove.size();
1152 if ( size == 0 )
1153 return *this;
1154 u32 pos = 0;
1155 u32 found = 0;
1156 for (u32 i=0; i<used-1; ++i)
1157 {
1158 u32 j = 0;
1159 while (j < size)
1160 {
1161 if (array[i + j] != toRemove[j])
1162 break;
1163 ++j;
1164 }
1165 if (j == size)
1166 {
1167 found += size;
1168 i += size - 1;
1169 continue;
1170 }
1171
1172 array[pos++] = array[i];
1173 }
1174 used -= found;
1175 array[used-1] = 0;
1176 return *this;
1177 }
1178
1179
1180 //! Removes characters from a string.
1181 /** \param characters: Characters to remove. */
1182 string<T,TAlloc>& removeChars(const string<T,TAlloc> & characters)
1183 {
1184 if (characters.size() == 0)
1185 return *this;
1186
1187 u32 pos = 0;
1188 u32 found = 0;
1189 for (u32 i=0; i<used-1; ++i)
1190 {
1191 // Don't use characters.findFirst as it finds the \0,
1192 // causing used to become incorrect.
1193 bool docontinue = false;
1194 for (u32 j=0; j<characters.size(); ++j)
1195 {
1196 if (characters[j] == array[i])
1197 {
1198 ++found;
1199 docontinue = true;
1200 break;
1201 }
1202 }
1203 if (docontinue)
1204 continue;
1205
1206 array[pos++] = array[i];
1207 }
1208 used -= found;
1209 array[used-1] = 0;
1210
1211 return *this;
1212 }
1213
1214
1215 //! Trims the string.
1216 /** Removes the specified characters (by default, Latin-1 whitespace)
1217 from the begining and the end of the string. */
1218 string<T,TAlloc>& trim(const string<T,TAlloc> & whitespace = " \t\n\r")
1219 {
1220 // find start and end of the substring without the specified characters
1221 const s32 begin = findFirstCharNotInList(whitespace.c_str(), whitespace.used);
1222 if (begin == -1)
1223 return (*this="");
1224
1225 const s32 end = findLastCharNotInList(whitespace.c_str(), whitespace.used);
1226
1227 return (*this = subString(begin, (end +1) - begin));
1228 }
1229
1230
1231 //! Erases a character from the string.
1232 /** May be slow, because all elements
1233 following after the erased element have to be copied.
1234 \param index: Index of element to be erased. */
1235 string<T,TAlloc>& erase(u32 index)
1236 {
1237 _IRR_DEBUG_BREAK_IF(index>=used) // access violation
1238
1239 for (u32 i=index+1; i<used; ++i)
1240 array[i-1] = array[i];
1241
1242 --used;
1243 return *this;
1244 }
1245
1246 //! verify the existing string.
1247 string<T,TAlloc>& validate()
1248 {
1249 // terminate on existing null
1250 for (u32 i=0; i<allocated; ++i)
1251 {
1252 if (array[i] == 0)
1253 {
1254 used = i + 1;
1255 return *this;
1256 }
1257 }
1258
1259 // terminate
1260 if ( allocated > 0 )
1261 {
1262 used = allocated;
1263 array[used-1] = 0;
1264 }
1265 else
1266 {
1267 used = 0;
1268 }
1269
1270 return *this;
1271 }
1272
1273 //! gets the last char of a string or null
1274 T lastChar() const
1275 {
1276 return used > 1 ? array[used-2] : 0;
1277 }
1278
1279 //! split string into parts.
1280 /** This method will split a string at certain delimiter characters
1281 into the container passed in as reference. The type of the container
1282 has to be given as template parameter. It must provide a push_back and
1283 a size method.
1284 \param ret The result container
1285 \param c C-style string of delimiter characters
1286 \param count Number of delimiter characters
1287 \param ignoreEmptyTokens Flag to avoid empty substrings in the result
1288 container. If two delimiters occur without a character in between, an
1289 empty substring would be placed in the result. If this flag is set,
1290 only non-empty strings are stored.
1291 \param keepSeparators Flag which allows to add the separator to the
1292 result string. If this flag is true, the concatenation of the
1293 substrings results in the original string. Otherwise, only the
1294 characters between the delimiters are returned.
1295 \return The number of resulting substrings
1296 */
1297 template<class container>
1298 u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
1299 {
1300 if (!c)
1301 return 0;
1302
1303 const u32 oldSize=ret.size();
1304 u32 lastpos = 0;
1305 bool lastWasSeparator = false;
1306 for (u32 i=0; i<used; ++i)
1307 {
1308 bool foundSeparator = false;
1309 for (u32 j=0; j<count; ++j)
1310 {
1311 if (array[i] == c[j])
1312 {
1313 if ((!ignoreEmptyTokens || i - lastpos != 0) &&
1314 !lastWasSeparator)
1315 ret.push_back(string<T,TAlloc>(&array[lastpos], i - lastpos));
1316 foundSeparator = true;
1317 lastpos = (keepSeparators ? i : i + 1);
1318 break;
1319 }
1320 }
1321 lastWasSeparator = foundSeparator;
1322 }
1323 if ((used - 1) > lastpos)
1324 ret.push_back(string<T,TAlloc>(&array[lastpos], (used - 1) - lastpos));
1325 return ret.size()-oldSize;
1326 }
1327
1328private:
1329
1330 //! Reallocate the array, make it bigger or smaller
1331 void reallocate(u32 new_size)
1332 {
1333 T* old_array = array;
1334
1335 array = allocator.allocate(new_size); //new T[new_size];
1336 allocated = new_size;
1337
1338 u32 amount = used < new_size ? used : new_size;
1339 for (u32 i=0; i<amount; ++i)
1340 array[i] = old_array[i];
1341
1342 if (allocated < used)
1343 used = allocated;
1344
1345 allocator.deallocate(old_array); // delete [] old_array;
1346 }
1347
1348 //--- member variables
1349
1350 T* array;
1351 u32 allocated;
1352 u32 used;
1353 TAlloc allocator;
1354};
1355
1356
1357//! Typedef for character strings
1358typedef string<c8> stringc;
1359
1360//! Typedef for wide character strings
1361typedef string<wchar_t> stringw;
1362
1363
1364} // end namespace core
1365} // end namespace irr
1366
1367#endif
1368