Line data Source code
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 :
20 : //! Very simple string class with some useful features.
21 : /** string<c8> and string<wchar_t> both accept Unicode AND ASCII/Latin-1,
22 : so 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 :
25 : However, note that the conversation between both is not done using any encoding.
26 : This means that c8 strings are treated as ASCII/Latin-1, not UTF-8, and
27 : are simply expanded to the equivalent wchar_t, while Unicode/wchar_t
28 : characters are truncated to 8-bit ASCII/Latin-1 characters, discarding all
29 : other information in the wchar_t.
30 : */
31 :
32 : enum eLocaleID
33 : {
34 : IRR_LOCALE_ANSI = 0,
35 : IRR_LOCALE_GERMAN = 1
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 :
44 : //! Returns a character converted to lower case
45 0 : static inline u32 locale_lower ( u32 x )
46 : {
47 0 : switch ( locale_current )
48 : {
49 : case IRR_LOCALE_GERMAN:
50 : case IRR_LOCALE_ANSI:
51 0 : break;
52 : }
53 : // ansi
54 0 : return x >= 'A' && x <= 'Z' ? x + 0x20 : x;
55 : }
56 :
57 : //! Returns a character converted to upper case
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 :
77 : typedef T char_type;
78 :
79 : //! Default constructor
80 1117 : string()
81 1117 : : array(0), allocated(1), used(1)
82 : {
83 1117 : array = allocator.allocate(1); // new T[1];
84 1117 : array[0] = 0;
85 1117 : }
86 :
87 :
88 : //! Constructor
89 20266 : string(const string<T,TAlloc>& other)
90 20266 : : array(0), allocated(0), used(0)
91 : {
92 20266 : *this = other;
93 20266 : }
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 0 : explicit string(int number)
116 0 : : array(0), allocated(0), used(0)
117 : {
118 : // store if negative and make positive
119 :
120 0 : bool negative = false;
121 0 : if (number < 0)
122 : {
123 0 : number *= -1;
124 0 : negative = true;
125 : }
126 :
127 : // temporary buffer for 16 numbers
128 :
129 0 : c8 tmpbuf[16]={0};
130 0 : u32 idx = 15;
131 :
132 : // special case '0'
133 :
134 0 : if (!number)
135 : {
136 0 : tmpbuf[14] = '0';
137 0 : *this = &tmpbuf[14];
138 0 : return;
139 : }
140 :
141 : // add numbers
142 :
143 0 : while(number && idx)
144 : {
145 0 : --idx;
146 0 : tmpbuf[idx] = (c8)('0' + (number % 10));
147 0 : number /= 10;
148 : }
149 :
150 : // add sign
151 :
152 0 : if (negative)
153 : {
154 0 : --idx;
155 0 : tmpbuf[idx] = '-';
156 : }
157 :
158 0 : *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 13203 : string(const B* const c)
297 13203 : : array(0), allocated(0), used(0)
298 : {
299 13203 : *this = c;
300 13203 : }
301 :
302 :
303 : //! Destructor
304 19345 : ~string()
305 : {
306 19345 : allocator.deallocate(array); // delete [] array;
307 19345 : }
308 :
309 :
310 : //! Assignment operator
311 21737 : string<T,TAlloc>& operator=(const string<T,TAlloc>& other)
312 : {
313 21737 : if (this == &other)
314 0 : return *this;
315 :
316 21737 : used = other.size()+1;
317 21737 : if (used>allocated)
318 : {
319 21422 : allocator.deallocate(array); // delete [] array;
320 21422 : allocated = used;
321 21422 : array = allocator.allocate(used); //new T[used];
322 : }
323 :
324 21737 : const T* p = other.c_str();
325 1214181 : for (u32 i=0; i<used; ++i, ++p)
326 1192444 : array[i] = *p;
327 :
328 21737 : 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 13371 : string<T,TAlloc>& operator=(const B* const c)
343 : {
344 13371 : if (!c)
345 : {
346 0 : if (!array)
347 : {
348 0 : array = allocator.allocate(1); //new T[1];
349 0 : allocated = 1;
350 : }
351 0 : used = 1;
352 0 : array[0] = 0x0;
353 0 : return *this;
354 : }
355 :
356 13371 : if ((void*)c == (void*)array)
357 0 : return *this;
358 :
359 13371 : u32 len = 0;
360 13371 : const B* p = c;
361 392780 : do
362 : {
363 392780 : ++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 13371 : T* oldArray = array;
369 :
370 13371 : used = len;
371 13371 : if (used>allocated)
372 : {
373 13365 : allocated = used;
374 13365 : array = allocator.allocate(used); //new T[used];
375 : }
376 :
377 406151 : for (u32 l = 0; l<len; ++l)
378 392780 : array[l] = (T)c[l];
379 :
380 13371 : if (oldArray != array)
381 13365 : allocator.deallocate(oldArray); // delete [] oldArray;
382 :
383 13371 : 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 0 : string<T,TAlloc> operator+(const B* const c) const
400 : {
401 0 : string<T,TAlloc> str(*this);
402 0 : str.append(c);
403 :
404 0 : return str;
405 : }
406 :
407 :
408 : //! Direct access operator
409 273 : T& operator [](const u32 index)
410 : {
411 : _IRR_DEBUG_BREAK_IF(index>=used) // bad index
412 273 : return array[index];
413 : }
414 :
415 :
416 : //! Direct access operator
417 0 : const T& operator [](const u32 index) const
418 : {
419 : _IRR_DEBUG_BREAK_IF(index>=used) // bad index
420 0 : 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 0 : bool operator<(const string<T,TAlloc>& other) const
452 : {
453 0 : for (u32 i=0; array[i] && other.array[i]; ++i)
454 : {
455 0 : const s32 diff = array[i] - other.array[i];
456 0 : if (diff)
457 0 : return (diff < 0);
458 : }
459 :
460 0 : 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 22574 : u32 size() const
482 : {
483 22574 : 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 23392 : const T* c_str() const
496 : {
497 23392 : 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 0 : bool equals_ignore_case(const string<T,TAlloc>& other) const
523 : {
524 0 : for(u32 i=0; array[i] && other[i]; ++i)
525 0 : if (locale_lower( array[i]) != locale_lower(other[i]))
526 0 : return false;
527 :
528 0 : 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 0 : string<T,TAlloc>& append(T character)
604 : {
605 0 : if (used + 1 > allocated)
606 0 : reallocate(used + 1);
607 :
608 0 : ++used;
609 :
610 0 : array[used-2] = character;
611 0 : array[used-1] = 0;
612 :
613 0 : 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 10 : string<T,TAlloc>& append(const T* const other, u32 length=0xffffffff)
621 : {
622 10 : if (!other)
623 0 : return *this;
624 :
625 10 : u32 len = 0;
626 10 : const T* p = other;
627 106 : while(*p)
628 : {
629 48 : ++len;
630 48 : ++p;
631 : }
632 10 : if (len > length)
633 0 : len = length;
634 :
635 10 : if (used + len > allocated)
636 10 : reallocate(used + len);
637 :
638 10 : --used;
639 10 : ++len;
640 :
641 68 : for (u32 l=0; l<len; ++l)
642 58 : array[l+used] = *(other+l);
643 :
644 10 : used += len;
645 :
646 10 : return *this;
647 : }
648 :
649 :
650 : //! Appends a string to this string
651 : /** \param other: String to append. */
652 0 : string<T,TAlloc>& append(const string<T,TAlloc>& other)
653 : {
654 0 : if (other.size() == 0)
655 0 : return *this;
656 :
657 0 : --used;
658 0 : u32 len = other.size()+1;
659 :
660 0 : if (used + len > allocated)
661 0 : reallocate(used + len);
662 :
663 0 : for (u32 l=0; l<len; ++l)
664 0 : array[used+l] = other[l];
665 :
666 0 : used += len;
667 :
668 0 : 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 279 : void reserve(u32 count)
706 : {
707 279 : if (count < allocated)
708 0 : return;
709 :
710 279 : 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 285 : 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 285 : if ((length <= 0) || (begin>=size()))
896 6 : return string<T>("");
897 : // clamp length to maximal value
898 279 : if ((length+begin) > size())
899 0 : length = size()-begin;
900 :
901 558 : string<T> o;
902 279 : o.reserve(length+1);
903 :
904 : s32 i;
905 279 : if ( !make_lower )
906 : {
907 2511 : for (i=0; i<length; ++i)
908 2232 : o.array[i] = array[i+begin];
909 : }
910 : else
911 : {
912 0 : for (i=0; i<length; ++i)
913 0 : o.array[i] = locale_lower ( array[i+begin] );
914 : }
915 :
916 279 : o.array[length] = 0;
917 279 : o.used = length + 1;
918 :
919 279 : return o;
920 : }
921 :
922 :
923 : //! Appends a character to this string
924 : /** \param c Character to append. */
925 0 : string<T,TAlloc>& operator += (T c)
926 : {
927 0 : append(c);
928 0 : 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 0 : string<T,TAlloc>& operator += (const string<T,TAlloc>& other)
944 : {
945 0 : append(other);
946 0 : 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 0 : string<T,TAlloc>& erase(u32 index)
1236 : {
1237 : _IRR_DEBUG_BREAK_IF(index>=used) // access violation
1238 :
1239 0 : for (u32 i=index+1; i<used; ++i)
1240 0 : array[i-1] = array[i];
1241 :
1242 0 : --used;
1243 0 : 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 :
1328 : private:
1329 :
1330 : //! Reallocate the array, make it bigger or smaller
1331 289 : void reallocate(u32 new_size)
1332 : {
1333 289 : T* old_array = array;
1334 :
1335 289 : array = allocator.allocate(new_size); //new T[new_size];
1336 289 : allocated = new_size;
1337 :
1338 289 : u32 amount = used < new_size ? used : new_size;
1339 896 : for (u32 i=0; i<amount; ++i)
1340 607 : array[i] = old_array[i];
1341 :
1342 289 : if (allocated < used)
1343 0 : used = allocated;
1344 :
1345 289 : allocator.deallocate(old_array); // delete [] old_array;
1346 289 : }
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
1358 : typedef string<c8> stringc;
1359 :
1360 : //! Typedef for wide character strings
1361 : typedef string<wchar_t> stringw;
1362 :
1363 :
1364 : } // end namespace core
1365 : } // end namespace irr
1366 :
1367 : #endif
1368 :
|