aboutsummaryrefslogtreecommitdiff
path: root/src/string.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2011-01-20 18:09:04 +0000
committerMike Buland <eichlan@xagasoft.com>2011-01-20 18:09:04 +0000
commit393f1b414746a7f1977971dd7659dd2b47092b11 (patch)
tree81d0ca1ee70ab86a7d79c1991abe5c387b655fb2 /src/string.h
parentc259f95bd0e58b247940a339bb9b4b401b4e9438 (diff)
parent7e25a863325dc3e9762397e700030969e093b087 (diff)
downloadlibbu++-393f1b414746a7f1977971dd7659dd2b47092b11.tar.gz
libbu++-393f1b414746a7f1977971dd7659dd2b47092b11.tar.bz2
libbu++-393f1b414746a7f1977971dd7659dd2b47092b11.tar.xz
libbu++-393f1b414746a7f1977971dd7659dd2b47092b11.zip
Wow! Merged the branch, streams are updated, and there's no more FString, run
the fixstrings.sh script in the support directory to (hopefully) automatically update your projects.
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..22db827
--- /dev/null
+++ b/src/string.h
@@ -0,0 +1,2129 @@
1/*
2 * Copyright (C) 2007-2011 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