summaryrefslogtreecommitdiff
path: root/src/string.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-01-20 02:14:08 +0000
committerMike Buland <eichlan@xagasoft.com>2011-01-20 02:14:08 +0000
commitf5aca1a1b402bd7ebc944dc6e6fe65828d863365 (patch)
tree4a0fdd8e166d5c4b03543279d332b9a858ef62df /src/string.h
parent10c557562e1d67c55314c212371ea9cb7f802863 (diff)
downloadlibbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.gz
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.bz2
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.tar.xz
libbu++-f5aca1a1b402bd7ebc944dc6e6fe65828d863365.zip
Bu::FString is now String, and there's a shell script to fix any other programs
that were using fstring, I hope.
Diffstat (limited to 'src/string.h')
-rw-r--r--src/string.h2129
1 files changed, 2129 insertions, 0 deletions
diff --git a/src/string.h b/src/string.h
new file mode 100644
index 0000000..5a0c471
--- /dev/null
+++ b/src/string.h
@@ -0,0 +1,2129 @@
1/*
2 * Copyright (C) 2007-2010 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_STRING_H
9#define BU_STRING_H
10
11#include <stdint.h>
12#include <memory>
13
14#ifndef WIN32
15#include <wordexp.h>
16#endif
17
18#include "bu/util.h"
19#include "bu/sharedcore.h"
20#include "bu/exceptionbase.h"
21#include "bu/archivebase.h"
22#include "bu/list.h"
23
24#include <string.h>
25
26namespace Bu
27{
28 /** @cond DEVEL */
29 template< typename chr >
30 struct StringChunk
31 {
32 long nLength;
33 chr *pData;
34 StringChunk *pNext;
35 };
36
37 template< typename chr, int nMinSize, typename chralloc,
38 typename chunkalloc> class BasicString;
39
40 template<typename chr>
41 size_t strlen( const chr *pData )
42 {
43 for( size_t tLen = 0;; ++tLen )
44 {
45 if( pData[tLen] == (chr)0 )
46 return tLen;
47 }
48 return -1;
49 }
50
51 template<char>
52 size_t strlen( const char *pData )
53 {
54 return ::strlen( pData );
55 }
56
57 template<typename chr>
58 int strncmp( const chr *a, const chr *b, size_t iLen )
59 {
60 for( size_t iPos = 0; iPos < iLen; iPos++ )
61 {
62 if( a[iPos] != b[iPos] )
63 {
64 return a[iPos]-b[iPos];
65 }
66 }
67 return 0;
68 }
69
70 template<char>
71 int strncmp( const char *a, const char *b, size_t iLen )
72 {
73 return ::strncmp( a, b, iLen );
74 }
75
76 template<typename chr, int nMinSize, typename chralloc, typename chunkalloc>
77 struct StringCore
78 {
79 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>;
80 friend class SharedCore<
81 BasicString<chr, nMinSize, chralloc, chunkalloc>,
82 StringCore<chr, nMinSize, chralloc, chunkalloc>
83 >;
84 private:
85 typedef struct StringCore<chr, nMinSize, chralloc, chunkalloc> MyType;
86 typedef struct StringChunk<chr> Chunk;
87 StringCore() :
88 nLength( 0 ),
89 pFirst( NULL ),
90 pLast( NULL )
91 {
92 }
93
94 StringCore( const MyType &rSrc ) :
95 nLength( rSrc.nLength ),
96 pFirst( NULL ),
97 pLast( NULL ),
98 aChr( rSrc.aChr ),
99 aChunk( rSrc.aChunk )
100 {
101 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
102 {
103 pFirst = pLast = NULL;
104 }
105 else
106 {
107 pFirst = pLast = newChunk( nLength );
108 Chunk *pLink = rSrc.pFirst;
109 int iPos = 0;
110 while( pLink != NULL )
111 {
112 memcpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
113 iPos += pLink->nLength;
114 pLink = pLink->pNext;
115 }
116 }
117 }
118
119 virtual ~StringCore()
120 {
121 clear();
122 }
123
124 mutable long nLength;
125 mutable Chunk *pFirst;
126 mutable Chunk *pLast;
127
128 mutable chralloc aChr;
129 mutable chunkalloc aChunk;
130
131 void clear() const
132 {
133 if( pFirst == NULL )
134 return;
135
136 Chunk *i = pFirst;
137 for(;;)
138 {
139 Chunk *n = i->pNext;
140 aChr.deallocate( i->pData, i->nLength+1 );
141 aChunk.deallocate( i, 1 );
142 if( n == NULL )
143 break;
144 i = n;
145 }
146 pFirst = pLast = NULL;
147 nLength = 0;
148 }
149
150 Chunk *newChunk() const
151 {
152 Chunk *pNew = aChunk.allocate( 1 );
153 pNew->pNext = NULL;
154 return pNew;
155 }
156
157 Chunk *newChunk( long nLen ) const
158 {
159 Chunk *pNew = aChunk.allocate( 1 );
160 pNew->pNext = NULL;
161 pNew->nLength = nLen;
162 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
163 pNew->pData[nLen] = (chr)0;
164 return pNew;
165 }
166
167 Chunk *copyChunk( Chunk *pSrc ) const
168 {
169 Chunk *pNew = aChunk.allocate( 1 );
170 pNew->pNext = pSrc->pNext;
171 pNew->nLength = pSrc->nLength;
172 pNew->pData = aChr.allocate( pSrc->nLength+1 );
173 memcpy( pNew->pData, pSrc->pData, pSrc->nLength );
174 pNew->pData[pNew->nLength] = (chr)0;
175 return pNew;
176 }
177
178 void appendChunk( Chunk *pNewChunk )
179 {
180 if( pFirst == NULL )
181 pLast = pFirst = pNewChunk;
182 else
183 {
184 pLast->pNext = pNewChunk;
185 pLast = pNewChunk;
186 }
187
188 nLength += pNewChunk->nLength;
189 }
190
191 void prependChunk( Chunk *pNewChunk )
192 {
193 if( pFirst == NULL )
194 pLast = pFirst = pNewChunk;
195 else
196 {
197 pNewChunk->pNext = pFirst;
198 pFirst = pNewChunk;
199 }
200
201 nLength += pNewChunk->nLength;
202 }
203 };
204 /** @endcond */
205
206 /**
207 * Flexible String class. This class was designed with string passing and
208 * generation in mind. Like the standard string class you can specify what
209 * datatype to use for each character. Unlike the standard string class,
210 * collection of appended and prepended terms is done lazily, making long
211 * operations that involve many appends very inexpensive. In addition
212 * internal ref-counting means that if you pass strings around between
213 * functions there's almost no overhead in time or memory since a reference
214 * is created and no data is actually copied. This also means that you
215 * never need to put any BasicString into a ref-counting container class.
216 *
217 *@param chr (typename) Type of character (i.e. char)
218 *@param nMinSize (int) Chunk size (default: 256)
219 *@param chralloc (typename) Memory Allocator for chr
220 *@param chunkalloc (typename) Memory Allocator for chr chunks
221 */
222 template< typename chr, int nMinSize=256,
223 typename chralloc=std::allocator<chr>,
224 typename chunkalloc=std::allocator<struct StringChunk<chr> > >
225 class BasicString : public SharedCore<
226 BasicString<chr, nMinSize, chralloc, chunkalloc>,
227 StringCore<chr, nMinSize, chralloc, chunkalloc> >
228 {
229 protected:
230 typedef struct StringChunk<chr> Chunk;
231 typedef struct BasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
232 typedef struct StringCore<chr, nMinSize, chralloc, chunkalloc> Core;
233
234 using SharedCore<MyType, Core >::core;
235 using SharedCore<MyType, Core >::_hardCopy;
236
237 public: // Iterators
238 struct iterator;
239 typedef struct const_iterator
240 {
241 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>;
242 friend struct iterator;
243 private:
244 const_iterator( Chunk *pChunk, int iPos ) :
245 pChunk( pChunk ),
246 iPos( iPos )
247 {
248 }
249
250 Chunk *pChunk;
251 int iPos;
252
253 public:
254 const_iterator( const const_iterator &i ) :
255 pChunk( i.pChunk ),
256 iPos( i.iPos )
257 {
258 }
259
260 const_iterator( const struct iterator &i ) :
261 pChunk( i.pChunk ),
262 iPos( i.iPos )
263 {
264 }
265
266 const_iterator() :
267 pChunk( NULL ),
268 iPos( 0 )
269 {
270 }
271
272 bool operator==( const const_iterator &i ) const
273 {
274 return pChunk == i.pChunk && iPos == i.iPos;
275 }
276
277 bool operator!=( const const_iterator &i ) const
278 {
279 return !(*this == i);
280 }
281
282 const_iterator &operator=( const const_iterator &i )
283 {
284 pChunk = i.pChunk;
285 iPos = i.iPos;
286 return *this;
287 }
288
289 const_iterator &operator++()
290 {
291 if( !pChunk ) return *this;
292 iPos++;
293 if( iPos >= pChunk->nLength )
294 {
295 iPos = 0;
296 pChunk = pChunk->pNext;
297 }
298 return *this;
299 }
300
301 const_iterator &operator++( int )
302 {
303 if( !pChunk ) return *this;
304 iPos++;
305 if( iPos >= pChunk->nLength )
306 {
307 iPos = 0;
308 pChunk = pChunk->pNext;
309 }
310 return *this;
311 }
312
313 const_iterator &operator+=( int iAmnt )
314 {
315 if( !pChunk ) return *this;
316 iPos += iAmnt;
317 while( iPos >= pChunk->nLength )
318 {
319 iPos -= pChunk->nLength;
320 pChunk = pChunk->pNext;
321 if( pChunk == NULL )
322 break;
323 }
324 return *this;
325 }
326
327 const_iterator operator+( int iAmnt ) const
328 {
329 if( !pChunk ) return *this;
330 const_iterator ret( *this );
331 ret += iAmnt;
332 return ret;
333 }
334
335 const chr &operator *() const
336 {
337 if( !pChunk ) throw Bu::ExceptionBase("Not a valid const_iterator.");
338 return pChunk->pData[iPos];
339 }
340
341 bool operator==( const chr &c ) const
342 {
343 if( !pChunk ) return false;
344 return pChunk->pData[iPos] == c;
345 }
346
347 bool operator!=( const chr &c ) const
348 {
349 if( !pChunk ) return false;
350 return pChunk->pData[iPos] != c;
351 }
352
353 operator bool() const
354 {
355 return pChunk != NULL;
356 }
357
358 bool isValid() const
359 {
360 return pChunk != NULL;
361 }
362
363 bool compare( const const_iterator &c ) const
364 {
365 const_iterator a = *this;
366 const_iterator b = c;
367 if( a == b )
368 return true;
369 for(; a && b; a++, b++ )
370 {
371 if( *a != *b )
372 return false;
373 }
374 return true;
375 }
376
377 bool compare( const const_iterator &c, int nLen ) const
378 {
379 const_iterator a = *this;
380 const_iterator b = c;
381 if( a == b )
382 return true;
383 for(int j = 0; a && b && j < nLen; a++, b++, j++ )
384 {
385 if( *a != *b )
386 return false;
387 }
388 return true;
389 }
390
391 bool compare( const chr *c ) const
392 {
393 if( !pChunk ) return false;
394 const_iterator a = *this;
395 for(; a && *c; a++, c++ )
396 {
397 if( *a != *c )
398 return false;
399 }
400 if( a.isValid() != (*c!=(chr)0) )
401 return false;
402 return true;
403 }
404
405 bool compare( const chr *c, int nLen ) const
406 {
407 if( !pChunk ) return false;
408 const_iterator a = *this;
409 int j = 0;
410 for(; a && j < nLen; a++, c++, j++ )
411 {
412 if( *a != *c )
413 return false;
414 }
415 if( j < nLen )
416 return false;
417 return true;
418 }
419
420 bool compare( const MyType &s ) const
421 {
422 if( !pChunk ) return false;
423 return compare( s.begin() );
424 }
425
426 bool compare( const MyType &s, int nLen ) const
427 {
428 if( !pChunk ) return false;
429 return compare( s.begin(), nLen );
430 }
431
432 const_iterator find( const chr c ) const
433 {
434 for( const_iterator i = *this; i; i++ )
435 {
436 if( *i == c )
437 return i;
438 }
439 return const_iterator( NULL, 0 );
440 }
441
442 const_iterator find( const chr *pStr, int nLen ) const
443 {
444 for( const_iterator i = *this; i; i++ )
445 {
446 if( i.compare( pStr, nLen ) )
447 return i;
448 }
449 return const_iterator( NULL, 0 );
450 }
451
452 const_iterator find( const MyType &s ) const
453 {
454 for( const_iterator i = *this; i; i++ )
455 {
456 if( i.compare( s ) )
457 return i;
458 }
459 return const_iterator( NULL, 0 );
460 }
461
462 const_iterator find( const MyType &s, int nLen ) const
463 {
464 for( const_iterator i = *this; i; i++ )
465 {
466 if( i.compare( s, nLen ) )
467 return i;
468 }
469 return const_iterator( NULL, 0 );
470 }
471 } const_iterator;
472
473 typedef struct iterator
474 {
475 friend class BasicString<chr, nMinSize, chralloc, chunkalloc>;
476 friend struct const_iterator;
477 private:
478 iterator( Chunk *pChunk, int iPos ) :
479 pChunk( pChunk ),
480 iPos( iPos )
481 {
482 }
483
484 Chunk *pChunk;
485 int iPos;
486
487 public:
488 iterator( const iterator &i ) :
489 pChunk( i.pChunk ),
490 iPos( i.iPos )
491 {
492 }
493
494 iterator() :
495 pChunk( NULL ),
496 iPos( 0 )
497 {
498 }
499
500 operator const_iterator() const
501 {
502 return const_iterator( pChunk, iPos );
503 }
504
505 bool operator==( const iterator &i ) const
506 {
507 return pChunk == i.pChunk && iPos == i.iPos;
508 }
509
510 bool operator!=( const iterator &i ) const
511 {
512 return !(*this == i);
513 }
514
515 iterator &operator=( const iterator &i )
516 {
517 pChunk = i.pChunk;
518 iPos = i.iPos;
519 return *this;
520 }
521
522 iterator &operator++()
523 {
524 if( !pChunk ) return *this;
525 iPos++;
526 if( iPos >= pChunk->nLength )
527 {
528 iPos = 0;
529 pChunk = pChunk->pNext;
530 }
531 return *this;
532 }
533
534 iterator &operator++( int )
535 {
536 if( !pChunk ) return *this;
537 iPos++;
538 if( iPos >= pChunk->nLength )
539 {
540 iPos = 0;
541 pChunk = pChunk->pNext;
542 }
543 return *this;
544 }
545
546 iterator &operator+=( int iAmnt )
547 {
548 if( !pChunk ) return *this;
549 iPos += iAmnt;
550 while( iPos >= pChunk->nLength )
551 {
552 iPos -= pChunk->nLength;
553 pChunk = pChunk->pNext;
554 if( pChunk == NULL )
555 break;
556 }
557 return *this;
558 }
559
560 iterator operator+( int iAmnt ) const
561 {
562 if( !pChunk ) return *this;
563 iterator ret( *this );
564 ret += iAmnt;
565 return ret;
566 }
567
568 chr &operator*()
569 {
570 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
571 return pChunk->pData[iPos];
572 }
573
574 const chr &operator*() const
575 {
576 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
577 return pChunk->pData[iPos];
578 }
579
580 bool operator==( const chr &c ) const
581 {
582 if( !pChunk ) return false;
583 return pChunk->pData[iPos] == c;
584 }
585
586 bool operator!=( const chr &c ) const
587 {
588 if( !pChunk ) return false;
589 return pChunk->pData[iPos] != c;
590 }
591
592 iterator &operator=( const chr &c )
593 {
594 if( !pChunk ) throw Bu::ExceptionBase("Not a valid iterator.");
595 pChunk->pData[iPos] = c;
596 return *this;
597 }
598
599 operator bool() const
600 {
601 return pChunk != NULL;
602 }
603
604 bool isValid() const
605 {
606 return pChunk != NULL;
607 }
608
609 bool compare( const iterator &c ) const
610 {
611 iterator a = *this;
612 iterator b = c;
613 if( a == b )
614 return true;
615 for(; a && b; a++, b++ )
616 {
617 if( *a != *b )
618 return false;
619 }
620 return true;
621 }
622
623 bool compare( const iterator &c, int nLen ) const
624 {
625 iterator a = *this;
626 iterator b = c;
627 if( a == b )
628 return true;
629 for(int j = 0; a && b && j < nLen; a++, b++, j++ )
630 {
631 if( *a != *b )
632 return false;
633 }
634 return true;
635 }
636
637 bool compare( const chr *c ) const
638 {
639 if( !pChunk ) return false;
640 iterator a = *this;
641 for(; a && *c; a++, c++ )
642 {
643 if( *a != *c )
644 return false;
645 }
646 if( a.isValid() != (*c!=(chr)0) )
647 return false;
648 return true;
649 }
650
651 bool compare( const chr *c, int nLen ) const
652 {
653 if( !pChunk ) return false;
654 iterator a = *this;
655 int j = 0;
656 for(; a && j < nLen; a++, c++, j++ )
657 {
658 if( *a != *c )
659 return false;
660 }
661 if( j < nLen )
662 return false;
663 return true;
664 }
665
666 bool compare( const MyType &s ) const
667 {
668 if( !pChunk ) return false;
669 return compare( s.begin() );
670 }
671
672 bool compare( const MyType &s, int nLen ) const
673 {
674 if( !pChunk ) return false;
675 return compare( s.begin(), nLen );
676 }
677
678 iterator find( const chr c ) const
679 {
680 for( iterator i = *this; i; i++ )
681 {
682 if( *i == c )
683 return i;
684 }
685 return iterator( NULL, 0 );
686 }
687
688 iterator find( const chr *pStr, int nLen ) const
689 {
690 for( iterator i = *this; i; i++ )
691 {
692 if( i.compare( pStr, nLen ) )
693 return i;
694 }
695 return iterator( NULL, 0 );
696 }
697
698 iterator find( const MyType &s ) const
699 {
700 for( iterator i = *this; i; i++ )
701 {
702 if( i.compare( s ) )
703 return i;
704 }
705 return iterator( NULL, 0 );
706 }
707
708 iterator find( const MyType &s, int nLen ) const
709 {
710 for( iterator i = *this; i; i++ )
711 {
712 if( i.compare( s, nLen ) )
713 return i;
714 }
715 return iterator( NULL, 0 );
716 }
717 } iterator;
718
719 public:
720 BasicString()
721 {
722 }
723
724 BasicString( const chr *pData )
725 {
726 append( pData );
727 }
728
729 BasicString( const chr *pData, long nLength )
730 {
731 append( pData, nLength );
732 }
733
734 BasicString( const MyType &rSrc ) :
735 SharedCore<MyType, Core>( rSrc )
736 {
737 }
738
739 BasicString( const MyType &rSrc, long nLength )
740 {
741 append( rSrc, nLength );
742 }
743
744 BasicString( const MyType &rSrc, long nStart, long nLength )
745 {
746 append( rSrc, nStart, nLength );
747 }
748
749 BasicString( long nSize )
750 {
751 core->pFirst = core->pLast = core->newChunk( nSize );
752 core->nLength = nSize;
753 }
754
755 BasicString( const const_iterator &s )
756 {
757 append( s );
758 }
759
760 BasicString( const const_iterator &s, const const_iterator &e )
761 {
762 append( s, e );
763 }
764
765 virtual ~BasicString()
766 {
767 }
768
769 /**
770 * Append data to your string.
771 *@param pData (const chr *) The data to append.
772 */
773 void append( const chr *pData )
774 {
775 if( !pData ) return;
776 long nLen;
777 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
778
779 append( pData, 0, nLen );
780 }
781
782 /**
783 * Append data to your string.
784 *@param pData (const chr *) The data to append.
785 *@param nLen (long) The length of the data to append.
786 */
787 void append( const chr *pData, long nLen )
788 {
789 append( pData, 0, nLen );
790 }
791
792 /**
793 * Append data to your string.
794 *@param pData (const chr *) The data to append.
795 *@param nStart (long) The start position to copy from.
796 *@param nLen (long) The length of the data to append.
797 */
798 void append( const chr *pData, long nStart, long nLen )
799 {
800 if( !pData ) return;
801 if( nLen <= 0 )
802 return;
803
804 pData += nStart;
805
806 _hardCopy();
807
808 if( core->pLast && core->pLast->nLength < nMinSize )
809 {
810 int nAmnt = nMinSize - core->pLast->nLength;
811 if( nAmnt > nLen )
812 nAmnt = nLen;
813 memcpy(
814 core->pLast->pData+core->pLast->nLength,
815 pData,
816 nAmnt
817 );
818 pData += nAmnt;
819 core->pLast->nLength += nAmnt;
820 nLen -= nAmnt;
821 core->nLength += nAmnt;
822 }
823
824 if( nLen > 0 )
825 {
826 Chunk *pNew = core->newChunk( nLen );
827 memcpy( pNew->pData, pData, nLen );
828 core->appendChunk( pNew );
829// core->nLength += nLen;
830 }
831 }
832
833 /**
834 * Append a single chr to your string.
835 *@param cData (const chr &) The character to append.
836 */
837 void append( const chr &cData )
838 {
839 if( core->pLast && core->pLast->nLength < nMinSize )
840 {
841 _hardCopy();
842 core->pLast->pData[core->pLast->nLength] = cData;
843 ++core->pLast->nLength; ++core->nLength;
844 // pLast->pData[pLast->nLength] = (chr)0;
845 }
846 else
847 {
848 append( &cData, 1 );
849 }
850 }
851
852 /**
853 * Append another String to this one.
854 *@param sData (MyType &) The String to append.
855 *@todo This function can be made much faster by not using getStr()
856 */
857 void append( const MyType & sData )
858 {
859 append( sData.getStr(), 0, sData.getSize() );
860 }
861
862 /**
863 * Append another String to this one.
864 *@param sData (MyType &) The String to append.
865 *@param nLen How much data to append.
866 *@todo This function can be made much faster by not using getStr()
867 */
868 void append( const MyType & sData, long nLen )
869 {
870 append( sData.getStr(), 0, nLen );
871 }
872
873 /**
874 * Append another String to this one.
875 *@param sData (MyType &) The String to append.
876 *@param nStart Start position in sData to start copying from.
877 *@param nLen How much data to append.
878 *@todo This function can be made much faster by not using getStr()
879 */
880 void append( const MyType & sData, long nStart, long nLen )
881 {
882 if( nLen < 0 )
883 nLen = sData.getSize() - nStart;
884 append( sData.getStr(), nStart, nLen );
885 }
886
887 /**
888 * Append data to this String using the passed in iterator as a base.
889 * The iterator is const, it is not changed.
890 *@param s Iterator from any compatible BasicString to copy data from.
891 */
892 void append( const const_iterator &s )
893 {
894 if( !s.isValid() )
895 return;
896 Chunk *pSrc = s.pChunk;
897
898 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
899 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
900
901 _hardCopy();
902 core->appendChunk( pNew );
903
904 while( (pSrc = pSrc->pNext) )
905 {
906 core->appendChunk( core->copyChunk( pSrc ) );
907 }
908 }
909
910 /**
911 * Append data to this String using the passed in iterator as a base.
912 * The iterator is const, it is not changed.
913 *@param s Iterator from any compatible BasicString to copy data from.
914 */
915 void append( const iterator &s ) // I get complaints without this one
916 {
917 append( const_iterator( s ) );
918 }
919
920 /**
921 * Append data to this String using the passed in iterator as a base,
922 * and copy data until the ending iterator is reached. The character
923 * at the ending iterator is not copied.
924 * The iterators are const, they are not changed.
925 *@param s Iterator from any compatible BasicString to copy data from.
926 *@param e Iterator to stop copying at.
927 */
928 void append( const const_iterator &s, const const_iterator &e )
929 {
930 if( !s.isValid() )
931 return;
932 if( !e.isValid() )
933 {
934 append( s );
935 return;
936 }
937 _hardCopy();
938 if( s.pChunk == e.pChunk )
939 {
940 // Simple case, they're the same chunk
941 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
942 memcpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
943 core->appendChunk( pNew );
944 }
945 else
946 {
947 // A little trickier, scan the blocks...
948 Chunk *pSrc = s.pChunk;
949 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
950 memcpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
951 core->appendChunk( pNew );
952
953 while( (pSrc = pSrc->pNext) != e.pChunk )
954 {
955 core->appendChunk( core->copyChunk( pSrc ) );
956 }
957
958 pNew = core->newChunk( e.iPos );
959 memcpy( pNew->pData, pSrc->pData, e.iPos );
960 core->appendChunk( pNew );
961 }
962 }
963
964 /**
965 * Prepend another String to this one.
966 *@param sData (MyType &) The String to prepend.
967 *@todo This function can be made much faster by not using getStr()
968 */
969 void prepend( const MyType & sData )
970 {
971 prepend( sData.getStr(), sData.getSize() );
972 }
973
974 /**
975 * Prepend data to your string.
976 *@param pData (const chr *) The data to prepend.
977 */
978 void prepend( const chr *pData )
979 {
980 if( pData == NULL )
981 return;
982
983 _hardCopy();
984 long nLen;
985 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
986
987 Chunk *pNew = core->newChunk( nLen );
988 memcpy( pNew->pData, pData, nLen );
989
990 core->prependChunk( pNew );
991 }
992
993 /**
994 * Prepend data to your string.
995 *@param pData (const chr *) The data to prepend.
996 *@param nLen (long) The length of the data to prepend.
997 */
998 void prepend( const chr *pData, long nLen )
999 {
1000 Chunk *pNew = core->newChunk( nLen );
1001
1002 memcpy( pNew->pData, pData, nLen );
1003
1004 _hardCopy();
1005 core->prependChunk( pNew );
1006 }
1007
1008 void prepend( const chr c )
1009 {
1010 prepend( &c, 1 );
1011 }
1012
1013 /**
1014 * Insert pData before byte nPos, that is, the first byte of pData will
1015 * start at nPos. This could probably be made faster by avoiding
1016 * flattening.
1017 */
1018 void insert( long nPos, const chr *pData, long nLen )
1019 {
1020 if( nLen <= 0 )
1021 return;
1022 if( nPos <= 0 )
1023 {
1024 prepend( pData, nLen );
1025 }
1026 else if( nPos >= core->nLength )
1027 {
1028 append( pData, nLen );
1029 }
1030 else
1031 {
1032 // If we're going to flatten anyway, might as well for everyone
1033 flatten();
1034 _hardCopy();
1035 Chunk *p1 = core->newChunk( nPos );
1036 Chunk *p2 = core->newChunk( nLen );
1037 Chunk *p3 = core->newChunk( core->nLength-nPos );
1038 memcpy( p1->pData, core->pFirst->pData, nPos );
1039 memcpy( p2->pData, pData, nLen );
1040 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1041 core->clear();
1042 core->appendChunk( p1 );
1043 core->appendChunk( p2 );
1044 core->appendChunk( p3 );
1045 }
1046 }
1047
1048 void insert( long nPos, const MyType &str )
1049 {
1050 if( nPos <= 0 )
1051 {
1052 prepend( str );
1053 }
1054 else if( nPos >= core->nLength )
1055 {
1056 append( str );
1057 }
1058 else
1059 {
1060 flatten();
1061 _hardCopy();
1062 Chunk *p1 = core->newChunk( nPos );
1063 Chunk *p3 = core->newChunk( core->nLength-nPos );
1064 memcpy( p1->pData, core->pFirst->pData, nPos );
1065 memcpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
1066 core->clear();
1067 core->appendChunk( p1 );
1068 for( Chunk *pChnk = str.core->pFirst; pChnk;
1069 pChnk = pChnk->pNext )
1070 {
1071 core->appendChunk( core->copyChunk( pChnk ) );
1072 }
1073
1074 core->appendChunk( p3 );
1075 }
1076 }
1077
1078 /**
1079 *@todo This function shouldn't use strlen, we should add our own to
1080 * this class, one that can be overridden in a specific implementation.
1081 */
1082 void insert( long nPos, const chr *pData )
1083 {
1084 insert( nPos, pData, Bu::strlen( pData ) );
1085 }
1086
1087 void remove( long nPos, long nLen )
1088 {
1089 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
1090 return;
1091 if( nLen > core->nLength-nPos )
1092 nLen = core->nLength-nPos;
1093 flatten();
1094 _hardCopy();
1095 memmove( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
1096 core->nLength -= nLen;
1097 core->pFirst->nLength -= nLen;
1098 }
1099
1100 /**
1101 * Clear all data from the string.
1102 */
1103 void clear()
1104 {
1105 _hardCopy();
1106 core->clear();
1107 }
1108
1109 MyType replace( const MyType &fnd, const MyType &rep ) const
1110 {
1111 MyType out;
1112 const_iterator o = begin();
1113 while( true )
1114 {
1115 const_iterator i = o.find( fnd );
1116 if( !i )
1117 {
1118 out.append( o );
1119 return out;
1120 }
1121 else
1122 {
1123 out.append( o, i );
1124 out.append( rep );
1125 o = i;
1126 o += fnd.getSize();
1127 }
1128 }
1129 }
1130
1131 /**
1132 * Force the string to resize
1133 *@param nNewSize (long) The new size of the string.
1134 */
1135 void resize( long nNewSize )
1136 {
1137 if( core->nLength == nNewSize )
1138 return;
1139 if( nNewSize < 0 )
1140 nNewSize = 0;
1141
1142 flatten();
1143 _hardCopy();
1144
1145 Chunk *pNew = core->newChunk( nNewSize );
1146 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
1147 if( core->nLength > 0 )
1148 {
1149 memcpy( pNew->pData, core->pFirst->pData, nNewLen );
1150 core->aChr.deallocate( core->pFirst->pData, core->pFirst->nLength+1 );
1151 core->aChunk.deallocate( core->pFirst, 1 );
1152 }
1153 pNew->pData[nNewLen] = (chr)0;
1154 core->pFirst = core->pLast = pNew;
1155 core->nLength = nNewSize;
1156 }
1157
1158 /**
1159 * Get the current size of the string.
1160 *@returns (long) The current size of the string.
1161 */
1162 long getSize() const
1163 {
1164 return core->nLength;
1165 }
1166
1167 /**
1168 * Get a pointer to the string array.
1169 *@returns (chr *) The string data.
1170 */
1171 chr *getStr()
1172 {
1173 if( core->pFirst == NULL || core->nLength == 0 )
1174 return (chr *)"";
1175
1176 flatten();
1177 _hardCopy();
1178 core->pFirst->pData[core->nLength] = (chr)0;
1179 return core->pFirst->pData;
1180 }
1181
1182 /**
1183 * Get a const pointer to the string array.
1184 *@returns (const chr *) The string data.
1185 */
1186 const chr *getStr() const
1187 {
1188 if( core->pFirst == NULL || core->nLength == 0 )
1189 return (chr *)"";
1190
1191 flatten();
1192 core->pFirst->pData[core->nLength] = (chr)0;
1193 return core->pFirst->pData;
1194 }
1195
1196 /**
1197 * A convinience function, this one won't cause as much work as the
1198 * non-const getStr, so if you're not changing the data, consider it.
1199 */
1200 const chr *getConstStr() const
1201 {
1202 return getStr();
1203 }
1204
1205 MyType getSubStrIdx( long iStart, long iSize=-1 ) const
1206 {
1207 if( iStart < 0 )
1208 iStart = 0;
1209 if( iStart >= core->nLength )
1210 return (const chr[]){(chr)0};
1211 if( iSize < 0 )
1212 iSize = core->nLength;
1213 if( iStart+iSize > core->nLength )
1214 iSize = core->nLength-iStart;
1215 if( iSize == 0 )
1216 return (const chr[]){(chr)0};
1217
1218 flatten();
1219 MyType ret( core->pFirst->pData+iStart, iSize );
1220 return ret;
1221 }
1222
1223 MyType getSubStr( const_iterator iBegin,
1224 const_iterator iEnd=typename MyType::const_iterator() ) const
1225 {
1226 if( !iBegin.isValid() )
1227 return MyType();
1228 if( iBegin.pChunk == iEnd.pChunk )
1229 {
1230 return MyType( iBegin.pChunk->pData+iBegin.iPos,
1231 iEnd.iPos-iBegin.iPos );
1232 }
1233 else if( !iEnd.isValid() )
1234 {
1235 MyType ret;
1236 ret.append(
1237 iBegin.pChunk->pData+iBegin.iPos,
1238 iBegin.pChunk->nLength-iBegin.iPos
1239 );
1240 for( Chunk *pCur = iBegin.pChunk->pNext;
1241 pCur; pCur = pCur->pNext )
1242 {
1243 ret.append( pCur->pData, pCur->nLength );
1244 }
1245 return ret;
1246 }
1247 else
1248 {
1249 MyType ret;
1250 ret.append(
1251 iBegin.pChunk->pData+iBegin.iPos,
1252 iBegin.pChunk->nLength-iBegin.iPos
1253 );
1254 for( Chunk *pCur = iBegin.pChunk->pNext;
1255 pCur != iEnd.pChunk; pCur = pCur->pNext )
1256 {
1257 ret.append( pCur->pData, pCur->nLength );
1258 }
1259 ret.append(
1260 iEnd.pChunk->pData,
1261 iEnd.iPos
1262 );
1263 return ret;
1264 }
1265 }
1266
1267 Bu::List<MyType> split( const chr c ) const
1268 {
1269 Bu::List<MyType> ret;
1270 const_iterator l, r;
1271 l = begin();
1272 for(r=l; l;)
1273 {
1274 for( r = l; r && r != c; r++ ) { }
1275 ret.append( MyType( l, r ) );
1276 l = r;
1277 l++;
1278 }
1279 return ret;
1280 }
1281
1282 /**
1283 * Plus equals operator for String.
1284 *@param pData (const chr *) The data to append to your String.
1285 */
1286 MyType &operator+=( const chr *pData )
1287 {
1288 append( pData );
1289
1290 return (*this);
1291 }
1292
1293 /**
1294 * Plus equals operator for String.
1295 *@param rSrc (const MyType &) The String to append to your String.
1296 */
1297 MyType &operator+=( const MyType &rSrc )
1298 {
1299 append( rSrc );
1300
1301 return (*this);
1302 }
1303
1304 MyType &operator+=( const MyType::const_iterator &i )
1305 {
1306 append( i, i+1 );
1307
1308 return (*this);
1309 }
1310
1311 /**
1312 * Plus equals operator for String.
1313 *@param cData (const chr) The character to append to your String.
1314 */
1315 MyType &operator+=( const chr cData )
1316 {
1317 if( core->pLast && core->pLast->nLength < nMinSize )
1318 {
1319 _hardCopy();
1320 core->pLast->pData[core->pLast->nLength] = cData;
1321 ++core->pLast->nLength; ++core->nLength;
1322 // pLast->pData[pLast->nLength] = (chr)0;
1323 }
1324 else
1325 {
1326 append( &cData, 1 );
1327 }
1328 //append( pData );
1329
1330 return (*this);
1331 }
1332
1333 /**
1334 * Assignment operator.
1335 *@param pData (const chr *) The character array to append to your
1336 * String.
1337 */
1338 MyType &operator=( const chr *pData )
1339 {
1340 set( pData );
1341
1342 return (*this);
1343 }
1344
1345 MyType operator+( const MyType &rRight ) const
1346 {
1347 MyType ret( *this );
1348 ret.append( rRight );
1349 return ret;
1350 }
1351
1352 MyType operator+( const chr *pRight ) const
1353 {
1354 MyType ret( *this );
1355 ret.append( pRight );
1356 return ret;
1357 }
1358
1359 MyType operator+( chr *pRight ) const
1360 {
1361 MyType ret( *this );
1362 ret.append( pRight );
1363 return ret;
1364 }
1365
1366 /**
1367 * Reset your String to this character array.
1368 *@param pData (const chr *) The character array to set your String to.
1369 */
1370 void set( const chr *pData )
1371 {
1372 clear();
1373 append( pData );
1374 }
1375
1376 /**
1377 * Reset your String to this character array.
1378 *@param pData (const chr *) The character array to set your String to.
1379 *@param nSize (long) The length of the inputted character array.
1380 */
1381 void set( const chr *pData, long nSize )
1382 {
1383 clear();
1384 append( pData, nSize );
1385 }
1386
1387 void set( const chr *pData, long nStart, long nSize )
1388 {
1389 clear();
1390 append( pData, nStart, nSize );
1391 }
1392
1393 void set( const MyType &rData )
1394 {
1395 clear();
1396 append( rData );
1397 }
1398
1399 void set( const MyType &rData, long nSize )
1400 {
1401 clear();
1402 append( rData, nSize );
1403 }
1404
1405 void set( const MyType &rData, long nStart, long nSize )
1406 {
1407 clear();
1408 append( rData, nStart, nSize );
1409 }
1410
1411 void set( const_iterator s )
1412 {
1413 clear();
1414 append( s );
1415 }
1416
1417 void set( const_iterator s, const_iterator e )
1418 {
1419 clear();
1420 append( s, e );
1421 }
1422
1423 /**
1424 * Resize the string, possibly to make room for a copy. At the moment
1425 * this operation *is* destructive. What was in the string will in no
1426 * way be preserved. This is, however, very fast. If you want to
1427 * keep your data check out resize.
1428 *@param iSize the new size in bytes. The string is guranteed to have
1429 * at least this much contiguous space available when done.
1430 */
1431 void setSize( long iSize )
1432 {
1433 _hardCopy();
1434 core->clear();
1435 core->appendChunk( core->newChunk( iSize ) );
1436 }
1437
1438 void expand()
1439 {
1440#ifndef WIN32
1441 flatten();
1442 _hardCopy();
1443
1444 wordexp_t result;
1445
1446 /* Expand the string for the program to run. */
1447 switch (wordexp ((char *)core->pFirst->pData, &result, 0))
1448 {
1449 case 0: /* Successful. */
1450 {
1451 set( (chr *)result.we_wordv[0] );
1452 wordfree( &result );
1453 return;
1454 }
1455 break;
1456 case WRDE_NOSPACE:
1457 /* If the error was `WRDE_NOSPACE',
1458 then perhaps part of the result was allocated. */
1459 wordfree (&result);
1460 default: /* Some other error. */
1461 return;
1462 }
1463#endif
1464 }
1465
1466 /**
1467 * Assignment operator.
1468 *@param rSrc (const MyType &) The String to set your String to.
1469 */
1470 /* MyType &operator=( const MyType &rSrc )
1471 {
1472 set( rSrc );
1473
1474 return (*this);
1475 } */
1476
1477 /**
1478 * Equals comparison operator.
1479 *@param pData (const chr *) The character array to compare your String
1480 * to.
1481 */
1482 bool operator==( const chr *pData ) const
1483 {
1484 if( core->pFirst == NULL || core->nLength == 0 ) {
1485 if( pData == NULL )
1486 return true;
1487 if( pData[0] == (chr)0 )
1488 return true;
1489 return false;
1490 }
1491
1492 flatten();
1493 core->pFirst->pData[core->nLength] = (chr)0;
1494 const chr *a = pData;
1495 chr *b = core->pFirst->pData;
1496 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
1497 {
1498 if( *a != *b )
1499 return false;
1500 if( *a == (chr)0 && j < core->nLength )
1501 return false;
1502 }
1503
1504 return true;
1505 }
1506
1507 /**
1508 * Equals comparison operator.
1509 *@param pData (const MyType &) The String to compare your String to.
1510 */
1511 bool operator==( const MyType &pData ) const
1512 {
1513 if( core == pData.core )
1514 return true;
1515 if( core->pFirst == pData.core->pFirst )
1516 return true;
1517 if( (core->nLength == 0 && pData.core->nLength == 0) )
1518 return true;
1519 if( core->nLength != pData.core->nLength )
1520 return false;
1521 if( pData.core->pFirst == NULL || core->pFirst == NULL )
1522 return false;
1523
1524 flatten();
1525 pData.flatten();
1526 const chr *a = pData.core->pFirst->pData;
1527 chr *b = core->pFirst->pData;
1528 for( long j = 0; j < core->nLength; j++, a++, b++ )
1529 {
1530 if( *a != *b )
1531 return false;
1532 }
1533
1534 return true;
1535 }
1536
1537 /**
1538 * Not equals comparison operator.
1539 *@param pData (const chr *) The character array to compare your String
1540 * to.
1541 */
1542 bool operator!=(const chr *pData ) const
1543 {
1544 return !(*this == pData);
1545 }
1546
1547 /**
1548 * Not equals comparison operator.
1549 *@param pData (const MyType &) The String to compare your String to.
1550 */
1551 bool operator!=(const MyType &pData ) const
1552 {
1553 return !(*this == pData);
1554 }
1555
1556 bool operator<(const MyType &pData ) const
1557 {
1558 flatten();
1559 pData.flatten();
1560
1561 const chr *a = core->pFirst->pData;
1562 chr *b = pData.core->pFirst->pData;
1563 for( long j = 0; j < core->nLength; j++, a++, b++ )
1564 {
1565 if( *a != *b )
1566 return *a < *b;
1567 }
1568
1569 return false;
1570 }
1571
1572 bool operator<=(const MyType &pData ) const
1573 {
1574 flatten();
1575 pData.flatten();
1576
1577 const chr *a = core->pFirst->pData;
1578 chr *b = pData.core->pFirst->pData;
1579 for( long j = 0; j < core->nLength; j++, a++, b++ )
1580 {
1581 if( *a != *b )
1582 return *a < *b;
1583 }
1584
1585 return true;
1586 }
1587
1588 bool operator>(const MyType &pData ) const
1589 {
1590 flatten();
1591 pData.flatten();
1592
1593 const chr *a = core->pFirst->pData;
1594 chr *b = pData.core->pFirst->pData;
1595 for( long j = 0; j < core->nLength; j++, a++, b++ )
1596 {
1597 if( *a != *b )
1598 return *a > *b;
1599 }
1600
1601 return false;
1602 }
1603
1604 bool operator>=(const MyType &pData ) const
1605 {
1606 flatten();
1607 pData.flatten();
1608
1609 const chr *a = core->pFirst->pData;
1610 chr *b = pData.core->pFirst->pData;
1611 for( long j = 0; j < core->nLength; j++, a++, b++ )
1612 {
1613 if( *a != *b )
1614 return *a > *b;
1615 }
1616
1617 return true;
1618 }
1619
1620 /**
1621 * Indexing operator
1622 *@param nIndex (long) The index of the character you want.
1623 *@returns (chr &) The character at position (nIndex).
1624 */
1625 chr &operator[]( long nIndex )
1626 {
1627 if( nIndex < 0 || nIndex >= core->nLength )
1628 throw Bu::ExceptionBase("Index out of range.");
1629 flatten();
1630 _hardCopy();
1631
1632 return core->pFirst->pData[nIndex];
1633 }
1634
1635 /**
1636 * Const indexing operator
1637 *@param nIndex (long) The index of the character you want.
1638 *@returns (const chr &) The character at position (nIndex).
1639 */
1640 const chr &operator[]( long nIndex ) const
1641 {
1642 if( nIndex < 0 || nIndex >= core->nLength )
1643 throw Bu::ExceptionBase("Index out of range.");
1644 flatten();
1645
1646 return core->pFirst->pData[nIndex];
1647 }
1648/*
1649 operator const chr *() const
1650 {
1651 if( !pFirst ) return NULL;
1652 flatten();
1653 return pFirst->pData;
1654 }
1655 */
1656 /*
1657 operator bool() const
1658 {
1659 return (core->pFirst != NULL);
1660 }
1661 */
1662
1663 bool isSet() const
1664 {
1665 return (core->pFirst != NULL);
1666 }
1667
1668 bool compareSub( const chr *pData, long nIndex, long nLen ) const
1669 {
1670 if( core->pFirst == NULL || core->nLength == 0 ) {
1671 if( pData == NULL )
1672 return true;
1673 if( nLen == 0 )
1674 return true;
1675 if( pData[0] == (chr)0 )
1676 return true;
1677 return false;
1678 }
1679 if( nIndex+nLen > core->nLength )
1680 return false;
1681
1682 flatten();
1683 core->pFirst->pData[core->nLength] = (chr)0;
1684 const chr *a = pData;
1685 chr *b = core->pFirst->pData+nIndex;
1686 for( long j = 0; j < nLen; j++, a++, b++ )
1687 {
1688 if( *a != *b )
1689 return false;
1690 if( *a == (chr)0 && j < core->nLength )
1691 return false;
1692 }
1693
1694 return true;
1695 }
1696
1697 bool compareSub( const MyType &rData, long nIndex, long nLen ) const
1698 {
1699 if( core->pFirst == NULL || core->nLength == 0 || rData.core->pFirst == NULL || rData.core->nLength == 0 )
1700 return false;
1701 if( nLen < 0 )
1702 nLen = rData.core->nLength;
1703 if( nIndex+nLen > core->nLength )
1704 return false;
1705
1706 flatten();
1707 rData.flatten();
1708 const chr *a = rData.core->pFirst->pData;
1709 chr *b = core->pFirst->pData + nIndex;
1710 for( long j = 0; j < nLen; j++, a++, b++ )
1711 {
1712 if( *a != *b )
1713 return false;
1714 }
1715
1716 return true;
1717 }
1718
1719 /**
1720 * Is the character at index (nIndex) white space?
1721 *@param nIndex (long) The index of the character you want to check.
1722 *@returns (bool) Is it white space?
1723 */
1724 bool isWS( long nIndex ) const
1725 {
1726 flatten();
1727
1728 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
1729 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
1730 }
1731
1732 /**
1733 * Is the character at index (nIndex) a letter?
1734 *@param nIndex (long) The index of the character you want to check.
1735 *@returns (bool) Is it a letter?
1736 */
1737 bool isAlpha( long nIndex ) const
1738 {
1739 flatten();
1740
1741 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
1742 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
1743 }
1744
1745 /**
1746 * Convert your alpha characters to lower case.
1747 */
1748 void toLower()
1749 {
1750 flatten();
1751 _hardCopy();
1752
1753 for( long j = 0; j < core->nLength; j++ )
1754 {
1755 if( core->pFirst->pData[j] >= 'A' && core->pFirst->pData[j] <= 'Z' )
1756 core->pFirst->pData[j] -= 'A'-'a';
1757 }
1758 }
1759
1760 /**
1761 * Convert your alpha characters to upper case.
1762 */
1763 void toUpper()
1764 {
1765 flatten();
1766 _hardCopy();
1767
1768 for( long j = 0; j < core->nLength; j++ )
1769 {
1770 if( core->pFirst->pData[j] >= 'a' && core->pFirst->pData[j] <= 'z' )
1771 core->pFirst->pData[j] += 'A'-'a';
1772 }
1773 }
1774
1775// template<typename out>
1776// void to( out &dst );
1777/* {
1778 flatten();
1779
1780 dst = strtol( pFirst->pData, NULL, 0 );
1781 } */
1782
1783 const_iterator find( const chr cChar,
1784 const_iterator iStart=typename MyType::const_iterator() ) const
1785 {
1786 if( !iStart ) iStart = begin();
1787 for( ; iStart; iStart++ )
1788 {
1789 if( cChar == *iStart )
1790 return iStart;
1791 }
1792 return end();
1793 }
1794
1795 const_iterator find( const chr *sText, int nLen,
1796 const_iterator iStart=typename MyType::const_iterator() ) const
1797 {
1798 if( !iStart ) iStart = begin();
1799 for( ; iStart; iStart++ )
1800 {
1801 if( iStart.compare( sText, nLen ) )
1802 return iStart;
1803 }
1804 return end();
1805 }
1806
1807 const_iterator find( const MyType &rStr,
1808 const_iterator iStart=typename MyType::const_iterator() ) const
1809 {
1810 if( !iStart ) iStart = begin();
1811 for( ; iStart; iStart++ )
1812 {
1813 if( iStart.compare( rStr ) )
1814 return iStart;
1815 }
1816 return end();
1817 }
1818
1819 const_iterator find( const MyType &rStr, int nLen,
1820 const_iterator iStart=typename MyType::const_iterator() ) const
1821 {
1822 if( !iStart ) iStart = begin();
1823 for( ; iStart; iStart++ )
1824 {
1825 if( iStart.compare( rStr, nLen ) )
1826 return iStart;
1827 }
1828 return end();
1829 }
1830
1831 iterator find( const chr cChar,
1832 const_iterator iStart=typename MyType::const_iterator() )
1833 {
1834 if( !iStart ) iStart = begin();
1835 for( ; iStart; iStart++ )
1836 {
1837 if( cChar == *iStart )
1838 return iterator( iStart.pChunk, iStart.iPos );
1839 }
1840 return end();
1841 }
1842
1843 iterator find( const chr *sText, int nLen,
1844 const_iterator iStart=typename MyType::const_iterator() )
1845 {
1846 if( !iStart ) iStart = begin();
1847 for( ; iStart; iStart++ )
1848 {
1849 if( iStart.compare( sText, nLen ) )
1850 return iterator( iStart.pChunk, iStart.iPos );
1851 }
1852 return end();
1853 }
1854
1855 iterator find( const MyType &rStr,
1856 const_iterator iStart=typename MyType::const_iterator() )
1857 {
1858 if( !iStart ) iStart = begin();
1859 for( ; iStart; iStart++ )
1860 {
1861 if( iStart.compare( rStr ) )
1862 return iterator( iStart.pChunk, iStart.iPos );
1863 }
1864 return end();
1865 }
1866
1867 iterator find( const MyType &rStr, int nLen,
1868 const_iterator iStart=typename MyType::const_iterator() )
1869 {
1870 if( !iStart ) iStart = begin();
1871 for( ; iStart; iStart++ )
1872 {
1873 if( iStart.compare( rStr, nLen ) )
1874 return iterator( iStart.pChunk, iStart.iPos );
1875 }
1876 return end();
1877 }
1878
1879 /**
1880 * Find the index of the first occurrance of cChar
1881 *@param cChar The character to search for.
1882 *@param iStart The position in the string to start searching from.
1883 *@returns (long) The index of the first occurrance. -1 for not found.
1884 */
1885 long findIdx( const chr cChar, long iStart=0 ) const
1886 {
1887 flatten();
1888 for( long j = iStart; j < core->pFirst->nLength; j++ )
1889 {
1890 if( core->pFirst->pData[j] == cChar )
1891 return j;
1892 }
1893 return -1;
1894 }
1895
1896 /**
1897 * Find the index of the first occurrance of sText
1898 *@param sText The null-terminated string to search for.
1899 *@param iStart The position in the string to start searching from.
1900 *@returns The index of the first occurrance. -1 for not found.
1901 */
1902 long findIdx( const chr *sText, long iStart=0 ) const
1903 {
1904 long nTLen = strlen( sText );
1905 flatten();
1906 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1907 {
1908 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1909 return j;
1910 }
1911 return -1;
1912 }
1913
1914 /**
1915 * Do a reverse search for (sText)
1916 *@param sText (const chr *) The string to search for.
1917 *@returns (long) The index of the last occurrance. -1 for not found.
1918 */
1919 long rfindIdx( const chr *sText ) const
1920 {
1921 long nTLen = strlen( sText );
1922 flatten();
1923 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1924 {
1925 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1926 return j;
1927 }
1928 return -1;
1929 }
1930
1931 /**
1932 * Remove nAmnt bytes from the front of the string. This function
1933 * operates in O(n) time and should be used sparingly.
1934 */
1935 void trimFront( long nAmnt )
1936 {
1937 long nNewLen = core->nLength - nAmnt;
1938 flatten();
1939 Chunk *pNew = core->newChunk( nNewLen );
1940 memcpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1941 _hardCopy();
1942 core->clear();
1943 core->appendChunk( pNew );
1944 }
1945
1946 void trimBack( chr c )
1947 {
1948 if( core->pFirst == NULL || core->nLength == 0 )
1949 return;
1950 flatten();
1951 for( ; core->pFirst->nLength > 0 && core->pFirst->pData[core->pFirst->nLength-1] == c; core->pFirst->nLength--, core->nLength-- ) { }
1952 }
1953
1954 MyType &format( const char *sFrmt, ...)
1955 {
1956 _hardCopy();
1957 clear();
1958
1959 va_list ap;
1960 va_start( ap, sFrmt );
1961
1962 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1963
1964 Chunk *pNew = core->newChunk( iLen );
1965 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
1966 core->appendChunk( pNew );
1967
1968 va_end( ap );
1969
1970 return *this;
1971 }
1972
1973 MyType &formatAppend( const char *sFrmt, ...)
1974 {
1975 _hardCopy();
1976 va_list ap;
1977 va_start( ap, sFrmt );
1978
1979 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1980
1981 Chunk *pNew = core->newChunk( iLen );
1982 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
1983 core->appendChunk( pNew );
1984
1985 va_end( ap );
1986
1987 return *this;
1988 }
1989
1990 MyType &formatPrepend( const char *sFrmt, ...)
1991 {
1992 _hardCopy();
1993 va_list ap;
1994 va_start( ap, sFrmt );
1995
1996 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1997
1998 Chunk *pNew = core->newChunk( iLen );
1999 vsnprintf( (char *)pNew->pData, iLen+1, sFrmt, ap );
2000 core->prependChunk( pNew );
2001
2002 va_end( ap );
2003
2004 return *this;
2005 }
2006
2007 iterator begin()
2008 {
2009 if( core->nLength == 0 )
2010 return iterator( NULL, 0 );
2011 return iterator( core->pFirst, 0 );
2012 }
2013
2014 const_iterator begin() const
2015 {
2016 if( core->nLength == 0 )
2017 return const_iterator( NULL, 0 );
2018 return iterator( core->pFirst, 0 );
2019 }
2020
2021 iterator end()
2022 {
2023 return iterator( NULL, 0 );
2024 }
2025
2026 const_iterator end() const
2027 {
2028 return const_iterator( NULL, 0 );
2029 }
2030
2031 bool isEmpty() const
2032 {
2033 if( core->nLength == 0 )
2034 return true;
2035 return false;
2036 }
2037
2038 private:
2039 void flatten() const
2040 {
2041 if( isFlat() )
2042 return;
2043
2044 if( core->pFirst == NULL || core->nLength == 0 )
2045 return;
2046
2047 Chunk *pNew = core->newChunk( core->nLength );
2048 chr *pos = pNew->pData;
2049 Chunk *i = core->pFirst;
2050 for(;;)
2051 {
2052 memcpy( pos, i->pData, i->nLength );
2053 pos += i->nLength;
2054 i = i->pNext;
2055 if( i == NULL )
2056 break;
2057 }
2058 core->clear();
2059
2060 core->pLast = core->pFirst = pNew;
2061 core->nLength = pNew->nLength;
2062 }
2063
2064 bool isFlat() const
2065 {
2066 return (core->pFirst == core->pLast);
2067 }
2068 };
2069
2070 template<class T> BasicString<T> operator+( const T *pLeft, const BasicString<T> &rRight )
2071 {
2072 Bu::BasicString<T> ret( pLeft );
2073 ret.append( rRight );
2074 return ret;
2075 }
2076
2077 template<class chr, int b, class c, class d>
2078 ArchiveBase &operator<<( ArchiveBase &ar, const BasicString<chr, b, c, d> &s )
2079 {
2080 long n = s.getSize();
2081 ar << n;
2082 ar.write( s.getConstStr(), n );
2083 return ar;
2084 }
2085
2086 template<class chr, int b, class c, class d>
2087 ArchiveBase &operator>>( ArchiveBase &ar, BasicString<chr, b, c, d> &s )
2088 {
2089 long n;
2090 ar >> n;
2091 s.setSize( n );
2092 ar.read( s.getStr(), n );
2093 return ar;
2094 }
2095
2096 typedef BasicString<char> String;
2097
2098 template<typename T>
2099 uint32_t __calcHashCode( const T &k );
2100
2101 template<typename T>
2102 bool __cmpHashKeys( const T &a, const T &b );
2103
2104 template<> uint32_t __calcHashCode<String>( const String &k );
2105 template<> bool __cmpHashKeys<String>(
2106 const String &a, const String &b );
2107
2108 template<typename t> void __tracer_format( const t &v );
2109 template<> void __tracer_format<String>( const String &v );
2110
2111 bool &operator<<( bool &dst, const String &sIn );
2112 uint8_t &operator<<( uint8_t &dst, const String &sIn );
2113 int8_t &operator<<( int8_t &dst, const String &sIn );
2114 char &operator<<( char &dst, const String &sIn );
2115 uint16_t &operator<<( uint16_t &dst, const String &sIn );
2116 int16_t &operator<<( int16_t &dst, const String &sIn );
2117 uint32_t &operator<<( uint32_t &dst, const String &sIn );
2118 int32_t &operator<<( int32_t &dst, const String &sIn );
2119 uint64_t &operator<<( uint64_t &dst, const String &sIn );
2120 int64_t &operator<<( int64_t &dst, const String &sIn );
2121 float &operator<<( float &dst, const String &sIn );
2122 double &operator<<( double &dst, const String &sIn );
2123 long double &operator<<( long double &dst, const String &sIn );
2124 Bu::String &operator<<( Bu::String &dst, const String &sIn );
2125
2126 typedef Bu::List<String> StringList;
2127};
2128
2129#endif