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