aboutsummaryrefslogtreecommitdiff
path: root/src/fbasicstring.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-08-14 21:22:03 +0000
committerMike Buland <eichlan@xagasoft.com>2009-08-14 21:22:03 +0000
commitf01674e99a467e9eb99323130a1e1add4c57eda2 (patch)
tree50bfa258b1c5761b2fbbac86d945d981669f27d4 /src/fbasicstring.h
parent42f4f849c683bc30404727f4dccc9d3cfd030adf (diff)
downloadlibbu++-f01674e99a467e9eb99323130a1e1add4c57eda2.tar.gz
libbu++-f01674e99a467e9eb99323130a1e1add4c57eda2.tar.bz2
libbu++-f01674e99a467e9eb99323130a1e1add4c57eda2.tar.xz
libbu++-f01674e99a467e9eb99323130a1e1add4c57eda2.zip
Massive freaking changes!!!
Bu:;SharedCore actually is in and works, it's well tested and there are no known memory leaks or violations as of now. It's been applied to Bu::List and Bu::FBasicString so far. This means that everything using Bu::List and Bu::FBasicString will be much, much faster and use considerably less memory. I still have plans to apply this to Hash and maybe a couple of other core classes.
Diffstat (limited to 'src/fbasicstring.h')
-rw-r--r--src/fbasicstring.h718
1 files changed, 372 insertions, 346 deletions
diff --git a/src/fbasicstring.h b/src/fbasicstring.h
index 33a82cb..cf7a786 100644
--- a/src/fbasicstring.h
+++ b/src/fbasicstring.h
@@ -18,6 +18,7 @@
18#include "bu/archival.h" 18#include "bu/archival.h"
19#include "bu/archive.h" 19#include "bu/archive.h"
20#include "bu/util.h" 20#include "bu/util.h"
21#include "bu/sharedcore.h"
21 22
22namespace Bu 23namespace Bu
23{ 24{
@@ -28,6 +29,140 @@ namespace Bu
28 chr *pData; 29 chr *pData;
29 FStringChunk *pNext; 30 FStringChunk *pNext;
30 }; 31 };
32
33#ifndef VALTEST
34#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
35#endif
36
37#ifdef VALTEST
38 void cpy( chr *dest, const chr *src, long count ) const
39 {
40 for( int j = 0; j < count; j++ )
41 {
42 *dest = *src;
43 dest++;
44 src++;
45 }
46 }
47#endif
48 template<typename chr, int nMinSize, typename chralloc, typename chunkalloc>
49 struct FStringCore
50 {
51 typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> MyType;
52 typedef struct FStringChunk<chr> Chunk;
53 FStringCore() :
54 nLength( 0 ),
55 pFirst( NULL ),
56 pLast( NULL )
57 {
58 }
59
60 FStringCore( const MyType &rSrc ) :
61 nLength( rSrc.nLength ),
62 pFirst( NULL ),
63 pLast( NULL ),
64 aChr( rSrc.aChr ),
65 aChunk( rSrc.aChunk )
66 {
67 if( rSrc.pFirst == NULL || rSrc.nLength == 0 )
68 {
69 pFirst = pLast = NULL;
70 }
71 else
72 {
73 pFirst = pLast = newChunk( nLength );
74 Chunk *pLink = rSrc.pFirst;
75 int iPos = 0;
76 while( pLink != NULL )
77 {
78 cpy( pFirst->pData+iPos, pLink->pData, pLink->nLength );
79 iPos += pLink->nLength;
80 pLink = pLink->pNext;
81 }
82 }
83 }
84
85 mutable long nLength;
86 mutable Chunk *pFirst;
87 mutable Chunk *pLast;
88
89 mutable chralloc aChr;
90 mutable chunkalloc aChunk;
91
92 void clear() const
93 {
94 if( pFirst == NULL )
95 return;
96
97 Chunk *i = pFirst;
98 for(;;)
99 {
100 Chunk *n = i->pNext;
101 aChr.deallocate( i->pData, i->nLength+1 );
102 aChunk.deallocate( i, 1 );
103 if( n == NULL )
104 break;
105 i = n;
106 }
107 pFirst = pLast = NULL;
108 nLength = 0;
109 }
110
111 Chunk *newChunk() const
112 {
113 Chunk *pNew = aChunk.allocate( 1 );
114 pNew->pNext = NULL;
115 return pNew;
116 }
117
118 Chunk *newChunk( long nLen ) const
119 {
120 Chunk *pNew = aChunk.allocate( 1 );
121 pNew->pNext = NULL;
122 pNew->nLength = nLen;
123 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
124 pNew->pData[nLen] = (chr)0;
125 return pNew;
126 }
127
128 Chunk *copyChunk( Chunk *pSrc ) const
129 {
130 Chunk *pNew = aChunk.allocate( 1 );
131 pNew->pNext = pSrc->pNext;
132 pNew->nLength = pSrc->nLength;
133 pNew->pData = aChr.allocate( pSrc->nLength+1 );
134 cpy( pNew->pData, pSrc->pData, pSrc->nLength );
135 pNew->pData[pNew->nLength] = (chr)0;
136 return pNew;
137 }
138
139 void appendChunk( Chunk *pNewChunk )
140 {
141 if( pFirst == NULL )
142 pLast = pFirst = pNewChunk;
143 else
144 {
145 pLast->pNext = pNewChunk;
146 pLast = pNewChunk;
147 }
148
149 nLength += pNewChunk->nLength;
150 }
151
152 void prependChunk( Chunk *pNewChunk )
153 {
154 if( pFirst == NULL )
155 pLast = pFirst = pNewChunk;
156 else
157 {
158 pNewChunk->pNext = pFirst;
159 pFirst = pNewChunk;
160 }
161
162 nLength += pNewChunk->nLength;
163 }
164 };
165
31 /** 166 /**
32 * Flexible String class. This class was designed with string passing and 167 * Flexible String class. This class was designed with string passing and
33 * generation in mind. Like the standard string class you can specify what 168 * generation in mind. Like the standard string class you can specify what
@@ -45,82 +180,51 @@ namespace Bu
45 *@param chunkalloc (typename) Memory Allocator for chr chunks 180 *@param chunkalloc (typename) Memory Allocator for chr chunks
46 */ 181 */
47 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > > 182 template< typename chr, int nMinSize=256, typename chralloc=std::allocator<chr>, typename chunkalloc=std::allocator<struct FStringChunk<chr> > >
48 class FBasicString : public Archival 183 class FBasicString : public SharedCore< FStringCore<chr, nMinSize, chralloc, chunkalloc> >, public Archival
49 { 184 {
50#ifndef VALTEST 185 protected:
51#define cpy( dest, src, size ) memcpy( dest, src, size*sizeof(chr) )
52#endif
53 private:
54 //template< typename chr >
55 /* struct Chunk
56 {
57 long nLength;
58 chr *pData;
59 FChunk *pNext;
60 }; */
61
62 typedef struct FStringChunk<chr> Chunk; 186 typedef struct FStringChunk<chr> Chunk;
63 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType; 187 typedef struct FBasicString<chr, nMinSize, chralloc, chunkalloc> MyType;
188 typedef struct FStringCore<chr, nMinSize, chralloc, chunkalloc> Core;
189
190 using SharedCore< Core >::core;
191 using SharedCore< Core >::_hardCopy;
64 192
65 public: 193 public:
66 FBasicString() : 194 FBasicString()
67 nLength( 0 ),
68 pFirst( NULL ),
69 pLast( NULL )
70 { 195 {
71 } 196 }
72 197
73 FBasicString( const chr *pData ) : 198 FBasicString( const chr *pData )
74 nLength( 0 ),
75 pFirst( NULL ),
76 pLast( NULL )
77 { 199 {
78 append( pData ); 200 append( pData );
79 } 201 }
80 202
81 FBasicString( const chr *pData, long nLength ) : 203 FBasicString( const chr *pData, long nLength )
82 nLength( 0 ),
83 pFirst( NULL ),
84 pLast( NULL )
85 { 204 {
86 append( pData, nLength ); 205 append( pData, nLength );
87 } 206 }
88 207
89 FBasicString( const MyType &rSrc ) : 208 FBasicString( const MyType &rSrc ) :
90 Archival(), 209 SharedCore<Core>( rSrc ),
91 nLength( 0 ), 210 Archival()
92 pFirst( NULL ),
93 pLast( NULL )
94 { 211 {
95 if( rSrc.nLength > 0 )
96 {
97 rSrc.flatten();
98 append( rSrc.pFirst->pData, rSrc.nLength );
99 }
100 } 212 }
101 213
102 FBasicString( const MyType &rSrc, long nLength ) : 214 FBasicString( const MyType &rSrc, long nLength )
103 nLength( 0 ),
104 pFirst( NULL ),
105 pLast( NULL )
106 { 215 {
107 append( rSrc.pFirst->pData, nLength ); 216 append( rSrc, nLength );
108 } 217 }
109 218
110 FBasicString( const MyType &rSrc, long nStart, long nLength ) : 219 FBasicString( const MyType &rSrc, long nStart, long nLength )
111 nLength( 0 ),
112 pFirst( NULL ),
113 pLast( NULL )
114 { 220 {
115 append( rSrc.pFirst->pData+nStart, nLength ); 221 append( rSrc, nStart, nLength );
116 } 222 }
117 223
118 FBasicString( long nSize ) : 224 FBasicString( long nSize )
119 nLength( nSize ),
120 pFirst( NULL ),
121 pLast( NULL )
122 { 225 {
123 pFirst = pLast = newChunk( nSize ); 226 core->pFirst = core->pLast = core->newChunk( nSize );
227 core->nLength = nSize;
124 } 228 }
125 229
126 struct iterator; 230 struct iterator;
@@ -610,25 +714,18 @@ namespace Bu
610// typedef const chr *const_iterator; 714// typedef const chr *const_iterator;
611 // typedef iterator const_iterator; 715 // typedef iterator const_iterator;
612 716
613 FBasicString( const const_iterator &s ) : 717 FBasicString( const const_iterator &s )
614 nLength( 0 ),
615 pFirst( NULL ),
616 pLast( NULL )
617 { 718 {
618 append( s ); 719 append( s );
619 } 720 }
620 721
621 FBasicString( const const_iterator &s, const const_iterator &e ) : 722 FBasicString( const const_iterator &s, const const_iterator &e )
622 nLength( 0 ),
623 pFirst( NULL ),
624 pLast( NULL )
625 { 723 {
626 append( s, e ); 724 append( s, e );
627 } 725 }
628 726
629 virtual ~FBasicString() 727 virtual ~FBasicString()
630 { 728 {
631 clear();
632 } 729 }
633 730
634 /** 731 /**
@@ -643,10 +740,11 @@ namespace Bu
643 if( nLen == 0 ) 740 if( nLen == 0 )
644 return; 741 return;
645 742
646 Chunk *pNew = newChunk( nLen ); 743 Chunk *pNew = core->newChunk( nLen );
647 cpy( pNew->pData, pData, nLen ); 744 cpy( pNew->pData, pData, nLen );
648 745
649 appendChunk( pNew ); 746 _hardCopy();
747 core->appendChunk( pNew );
650 } 748 }
651 749
652 /** 750 /**
@@ -659,11 +757,12 @@ namespace Bu
659 if( nLen == 0 ) 757 if( nLen == 0 )
660 return; 758 return;
661 759
662 Chunk *pNew = newChunk( nLen ); 760 Chunk *pNew = core->newChunk( nLen );
663 761
664 cpy( pNew->pData, pData, nLen ); 762 cpy( pNew->pData, pData, nLen );
665 763
666 appendChunk( pNew ); 764 _hardCopy();
765 core->appendChunk( pNew );
667 } 766 }
668 767
669 /** 768 /**
@@ -672,10 +771,11 @@ namespace Bu
672 */ 771 */
673 void append( const chr &cData ) 772 void append( const chr &cData )
674 { 773 {
675 if( pLast && pLast->nLength < nMinSize ) 774 if( core->pLast && core->pLast->nLength < nMinSize )
676 { 775 {
677 pLast->pData[pLast->nLength] = cData; 776 _hardCopy();
678 ++pLast->nLength; ++nLength; 777 core->pLast->pData[core->pLast->nLength] = cData;
778 ++core->pLast->nLength; ++core->nLength;
679 // pLast->pData[pLast->nLength] = (chr)0; 779 // pLast->pData[pLast->nLength] = (chr)0;
680 } 780 }
681 else 781 else
@@ -687,6 +787,7 @@ namespace Bu
687 /** 787 /**
688 * Append another FString to this one. 788 * Append another FString to this one.
689 *@param sData (MyType &) The FString to append. 789 *@param sData (MyType &) The FString to append.
790 *@todo This function can be made much faster by not using getStr()
690 */ 791 */
691 void append( const MyType & sData ) 792 void append( const MyType & sData )
692 { 793 {
@@ -697,6 +798,7 @@ namespace Bu
697 * Append another FString to this one. 798 * Append another FString to this one.
698 *@param sData (MyType &) The FString to append. 799 *@param sData (MyType &) The FString to append.
699 *@param nLen How much data to append. 800 *@param nLen How much data to append.
801 *@todo This function can be made much faster by not using getStr()
700 */ 802 */
701 void append( const MyType & sData, long nLen ) 803 void append( const MyType & sData, long nLen )
702 { 804 {
@@ -708,6 +810,7 @@ namespace Bu
708 *@param sData (MyType &) The FString to append. 810 *@param sData (MyType &) The FString to append.
709 *@param nStart Start position in sData to start copying from. 811 *@param nStart Start position in sData to start copying from.
710 *@param nLen How much data to append. 812 *@param nLen How much data to append.
813 *@todo This function can be made much faster by not using getStr()
711 */ 814 */
712 void append( const MyType & sData, long nStart, long nLen ) 815 void append( const MyType & sData, long nStart, long nLen )
713 { 816 {
@@ -727,13 +830,15 @@ namespace Bu
727 return; 830 return;
728 Chunk *pSrc = s.pChunk; 831 Chunk *pSrc = s.pChunk;
729 832
730 Chunk *pNew = newChunk( pSrc->nLength-s.iPos ); 833 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
731 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); 834 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
732 appendChunk( pNew ); 835
836 _hardCopy();
837 core->appendChunk( pNew );
733 838
734 while( (pSrc = pSrc->pNext) ) 839 while( (pSrc = pSrc->pNext) )
735 { 840 {
736 appendChunk( copyChunk( pSrc ) ); 841 core->appendChunk( core->copyChunk( pSrc ) );
737 } 842 }
738 } 843 }
739 844
@@ -742,7 +847,7 @@ namespace Bu
742 * The iterator is const, it is not changed. 847 * The iterator is const, it is not changed.
743 *@param s Iterator from any compatible FBasicString to copy data from. 848 *@param s Iterator from any compatible FBasicString to copy data from.
744 */ 849 */
745 void append( const iterator &s ) // I get complainst without this one 850 void append( const iterator &s ) // I get complaints without this one
746 { 851 {
747 append( const_iterator( s ) ); 852 append( const_iterator( s ) );
748 } 853 }
@@ -764,35 +869,37 @@ namespace Bu
764 append( s ); 869 append( s );
765 return; 870 return;
766 } 871 }
872 _hardCopy();
767 if( s.pChunk == e.pChunk ) 873 if( s.pChunk == e.pChunk )
768 { 874 {
769 // Simple case, they're the same chunk 875 // Simple case, they're the same chunk
770 Chunk *pNew = newChunk( e.iPos-s.iPos ); 876 Chunk *pNew = core->newChunk( e.iPos-s.iPos );
771 cpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos ); 877 cpy( pNew->pData, s.pChunk->pData+s.iPos, e.iPos-s.iPos );
772 appendChunk( pNew ); 878 core->appendChunk( pNew );
773 } 879 }
774 else 880 else
775 { 881 {
776 // A little trickier, scan the blocks... 882 // A little trickier, scan the blocks...
777 Chunk *pSrc = s.pChunk; 883 Chunk *pSrc = s.pChunk;
778 Chunk *pNew = newChunk( pSrc->nLength-s.iPos ); 884 Chunk *pNew = core->newChunk( pSrc->nLength-s.iPos );
779 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos ); 885 cpy( pNew->pData, pSrc->pData+s.iPos, pSrc->nLength-s.iPos );
780 appendChunk( pNew ); 886 core->appendChunk( pNew );
781 887
782 while( (pSrc = pSrc->pNext) != e.pChunk ) 888 while( (pSrc = pSrc->pNext) != e.pChunk )
783 { 889 {
784 appendChunk( copyChunk( pSrc ) ); 890 core->appendChunk( core->copyChunk( pSrc ) );
785 } 891 }
786 892
787 pNew = newChunk( e.iPos ); 893 pNew = core->newChunk( e.iPos );
788 cpy( pNew->pData, pSrc->pData, e.iPos ); 894 cpy( pNew->pData, pSrc->pData, e.iPos );
789 appendChunk( pNew ); 895 core->appendChunk( pNew );
790 } 896 }
791 } 897 }
792 898
793 /** 899 /**
794 * Prepend another FString to this one. 900 * Prepend another FString to this one.
795 *@param sData (MyType &) The FString to prepend. 901 *@param sData (MyType &) The FString to prepend.
902 *@todo This function can be made much faster by not using getStr()
796 */ 903 */
797 void prepend( const MyType & sData ) 904 void prepend( const MyType & sData )
798 { 905 {
@@ -810,10 +917,10 @@ namespace Bu
810 long nLen; 917 long nLen;
811 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { } 918 for( nLen = 0; pData[nLen] != (chr)0; nLen++ ) { }
812 919
813 Chunk *pNew = newChunk( nLen ); 920 Chunk *pNew = core->newChunk( nLen );
814 cpy( pNew->pData, pData, nLen ); 921 cpy( pNew->pData, pData, nLen );
815 922
816 prependChunk( pNew ); 923 core->prependChunk( pNew );
817 } 924 }
818 925
819 /** 926 /**
@@ -823,13 +930,18 @@ namespace Bu
823 */ 930 */
824 void prepend( const chr *pData, long nLen ) 931 void prepend( const chr *pData, long nLen )
825 { 932 {
826 Chunk *pNew = newChunk( nLen ); 933 Chunk *pNew = core->newChunk( nLen );
827 934
828 cpy( pNew->pData, pData, nLen ); 935 cpy( pNew->pData, pData, nLen );
829 936
830 prependChunk( pNew ); 937 core->prependChunk( pNew );
831 } 938 }
832 939
940 /**
941 * Insert pData before byte nPos, that is, the first byte of pData will
942 * start at nPos. This could probably be made faster by avoiding
943 * flattening.
944 */
833 void insert( long nPos, const chr *pData, long nLen ) 945 void insert( long nPos, const chr *pData, long nLen )
834 { 946 {
835 if( nLen <= 0 ) 947 if( nLen <= 0 )
@@ -838,23 +950,25 @@ namespace Bu
838 { 950 {
839 prepend( pData, nLen ); 951 prepend( pData, nLen );
840 } 952 }
841 else if( nPos >= nLength ) 953 else if( nPos >= core->nLength )
842 { 954 {
843 append( pData, nLen ); 955 append( pData, nLen );
844 } 956 }
845 else 957 else
846 { 958 {
959 // If we're going to flatten anyway, might as well for everyone
847 flatten(); 960 flatten();
848 Chunk *p1 = newChunk( nPos ); 961 _hardCopy();
849 Chunk *p2 = newChunk( nLen ); 962 Chunk *p1 = core->newChunk( nPos );
850 Chunk *p3 = newChunk( nLength-nPos ); 963 Chunk *p2 = core->newChunk( nLen );
851 cpy( p1->pData, pFirst->pData, nPos ); 964 Chunk *p3 = core->newChunk( core->nLength-nPos );
965 cpy( p1->pData, core->pFirst->pData, nPos );
852 cpy( p2->pData, pData, nLen ); 966 cpy( p2->pData, pData, nLen );
853 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos ); 967 cpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
854 clear(); 968 core->clear();
855 appendChunk( p1 ); 969 core->appendChunk( p1 );
856 appendChunk( p2 ); 970 core->appendChunk( p2 );
857 appendChunk( p3 ); 971 core->appendChunk( p3 );
858 } 972 }
859 } 973 }
860 974
@@ -864,28 +978,34 @@ namespace Bu
864 { 978 {
865 prepend( str ); 979 prepend( str );
866 } 980 }
867 else if( nPos >= nLength ) 981 else if( nPos >= core->nLength )
868 { 982 {
869 append( str ); 983 append( str );
870 } 984 }
871 else 985 else
872 { 986 {
873 flatten(); 987 flatten();
874 Chunk *p1 = newChunk( nPos ); 988 _hardCopy();
875 Chunk *p3 = newChunk( nLength-nPos ); 989 Chunk *p1 = core->newChunk( nPos );
876 cpy( p1->pData, pFirst->pData, nPos ); 990 Chunk *p3 = core->newChunk( core->nLength-nPos );
877 cpy( p3->pData, pFirst->pData+nPos, nLength-nPos ); 991 cpy( p1->pData, core->pFirst->pData, nPos );
878 clear(); 992 cpy( p3->pData, core->pFirst->pData+nPos, core->nLength-nPos );
879 appendChunk( p1 ); 993 core->clear();
880 for( Chunk *pChnk = str.pFirst; pChnk; pChnk = pChnk->pNext ) 994 core->appendChunk( p1 );
995 for( Chunk *pChnk = str.core->pFirst; pChnk;
996 pChnk = pChnk->pNext )
881 { 997 {
882 appendChunk( copyChunk( pChnk ) ); 998 core->appendChunk( core->copyChunk( pChnk ) );
883 } 999 }
884 1000
885 appendChunk( p3 ); 1001 core->appendChunk( p3 );
886 } 1002 }
887 } 1003 }
888 1004
1005 /**
1006 *@todo This function shouldn't use strlen, we should add our own to
1007 * this class, one that can be overridden in a specific implementation.
1008 */
889 void insert( long nPos, const chr *pData ) 1009 void insert( long nPos, const chr *pData )
890 { 1010 {
891 insert( nPos, pData, strlen( pData ) ); 1011 insert( nPos, pData, strlen( pData ) );
@@ -893,14 +1013,15 @@ namespace Bu
893 1013
894 void remove( long nPos, long nLen ) 1014 void remove( long nPos, long nLen )
895 { 1015 {
896 if( nLen <= 0 || nPos < 0 || nPos >= nLength ) 1016 if( nLen <= 0 || nPos < 0 || nPos >= core->nLength )
897 return; 1017 return;
898 if( nLen > nLength-nPos ) 1018 if( nLen > core->nLength-nPos )
899 nLen = nLength-nPos; 1019 nLen = core->nLength-nPos;
900 flatten(); 1020 flatten();
901 cpy( pFirst->pData+nPos, pFirst->pData+nPos+nLen, nLength-nPos-nLen+1 ); 1021 _hardCopy();
902 nLength -= nLen; 1022 cpy( core->pFirst->pData+nPos, core->pFirst->pData+nPos+nLen, core->nLength-nPos-nLen+1 );
903 pFirst->nLength -= nLen; 1023 core->nLength -= nLen;
1024 core->pFirst->nLength -= nLen;
904 } 1025 }
905 1026
906 /** 1027 /**
@@ -908,7 +1029,8 @@ namespace Bu
908 */ 1029 */
909 void clear() 1030 void clear()
910 { 1031 {
911 realClear(); 1032 _hardCopy();
1033 core->clear();
912 } 1034 }
913 1035
914 /** 1036 /**
@@ -917,24 +1039,25 @@ namespace Bu
917 */ 1039 */
918 void resize( long nNewSize ) 1040 void resize( long nNewSize )
919 { 1041 {
920 if( nLength == nNewSize ) 1042 if( core->nLength == nNewSize )
921 return; 1043 return;
922 if( nNewSize < 0 ) 1044 if( nNewSize < 0 )
923 nNewSize = 0; 1045 nNewSize = 0;
924 1046
925 flatten(); 1047 flatten();
1048 _hardCopy();
926 1049
927 Chunk *pNew = newChunk( nNewSize ); 1050 Chunk *pNew = core->newChunk( nNewSize );
928 long nNewLen = (nNewSize<nLength)?(nNewSize):(nLength); 1051 long nNewLen = (nNewSize<core->nLength)?(nNewSize):(core->nLength);
929 if( nLength > 0 ) 1052 if( core->nLength > 0 )
930 { 1053 {
931 cpy( pNew->pData, pFirst->pData, nNewLen ); 1054 cpy( pNew->pData, core->pFirst->pData, nNewLen );
932 aChr.deallocate( pFirst->pData, pFirst->nLength+1 ); 1055 core->aChr.deallocate( core->pFirst->pData, core->pFirst->nLength+1 );
933 aChunk.deallocate( pFirst, 1 ); 1056 core->aChunk.deallocate( core->pFirst, 1 );
934 } 1057 }
935 pNew->pData[nNewLen] = (chr)0; 1058 pNew->pData[nNewLen] = (chr)0;
936 pFirst = pLast = pNew; 1059 core->pFirst = core->pLast = pNew;
937 nLength = nNewSize; 1060 core->nLength = nNewSize;
938 } 1061 }
939 1062
940 /** 1063 /**
@@ -943,7 +1066,7 @@ namespace Bu
943 */ 1066 */
944 long getSize() const 1067 long getSize() const
945 { 1068 {
946 return nLength; 1069 return core->nLength;
947 } 1070 }
948 1071
949 /** 1072 /**
@@ -952,12 +1075,13 @@ namespace Bu
952 */ 1075 */
953 chr *getStr() 1076 chr *getStr()
954 { 1077 {
955 if( pFirst == NULL ) 1078 if( core->pFirst == NULL )
956 return (chr *)""; 1079 return (chr *)"";
957 1080
958 flatten(); 1081 flatten();
959 pFirst->pData[nLength] = (chr)0; 1082 _hardCopy();
960 return pFirst->pData; 1083 core->pFirst->pData[core->nLength] = (chr)0;
1084 return core->pFirst->pData;
961 } 1085 }
962 1086
963 /** 1087 /**
@@ -966,29 +1090,38 @@ namespace Bu
966 */ 1090 */
967 const chr *getStr() const 1091 const chr *getStr() const
968 { 1092 {
969 if( pFirst == NULL ) 1093 if( core->pFirst == NULL )
970 return (chr *)""; 1094 return (chr *)"";
971 1095
972 flatten(); 1096 flatten();
973 pFirst->pData[nLength] = (chr)0; 1097 core->pFirst->pData[core->nLength] = (chr)0;
974 return pFirst->pData; 1098 return core->pFirst->pData;
1099 }
1100
1101 /**
1102 * A convinience function, this one won't cause as much work as the
1103 * non-const getStr, so if you're not changing the data, consider it.
1104 */
1105 const chr *getConstStr() const
1106 {
1107 return getStr();
975 } 1108 }
976 1109
977 MyType getSubStrIdx( long iStart, long iSize=-1 ) const 1110 MyType getSubStrIdx( long iStart, long iSize=-1 ) const
978 { 1111 {
979 if( iStart < 0 ) 1112 if( iStart < 0 )
980 iStart = 0; 1113 iStart = 0;
981 if( iStart >= nLength ) 1114 if( iStart >= core->nLength )
982 return ""; 1115 return "";
983 if( iSize < 0 ) 1116 if( iSize < 0 )
984 iSize = nLength; 1117 iSize = core->nLength;
985 if( iStart+iSize > nLength ) 1118 if( iStart+iSize > core->nLength )
986 iSize = nLength-iStart; 1119 iSize = core->nLength-iStart;
987 if( iSize == 0 ) 1120 if( iSize == 0 )
988 return ""; 1121 return "";
989 1122
990 flatten(); 1123 flatten();
991 MyType ret( pFirst->pData+iStart, iSize ); 1124 MyType ret( core->pFirst->pData+iStart, iSize );
992 return ret; 1125 return ret;
993 } 1126 }
994 1127
@@ -1043,12 +1176,13 @@ namespace Bu
1043 DEPRECATED 1176 DEPRECATED
1044 chr *c_str() 1177 chr *c_str()
1045 { 1178 {
1046 if( pFirst == NULL ) 1179 if( core->pFirst == NULL )
1047 return NULL; 1180 return NULL;
1048 1181
1049 flatten(); 1182 flatten();
1050 pFirst->pData[nLength] = (chr)0; 1183 _hardCopy();
1051 return pFirst->pData; 1184 core->pFirst->pData[core->nLength] = (chr)0;
1185 return core->pFirst->pData;
1052 } 1186 }
1053 1187
1054 /** 1188 /**
@@ -1058,12 +1192,12 @@ namespace Bu
1058 DEPRECATED 1192 DEPRECATED
1059 const chr *c_str() const 1193 const chr *c_str() const
1060 { 1194 {
1061 if( pFirst == NULL ) 1195 if( core->pFirst == NULL )
1062 return NULL; 1196 return NULL;
1063 1197
1064 flatten(); 1198 flatten();
1065 pFirst->pData[nLength] = (chr)0; 1199 core->pFirst->pData[core->nLength] = (chr)0;
1066 return pFirst->pData; 1200 return core->pFirst->pData;
1067 } 1201 }
1068 1202
1069 Bu::List<MyType> split( const chr c ) const 1203 Bu::List<MyType> split( const chr c ) const
@@ -1098,10 +1232,7 @@ namespace Bu
1098 */ 1232 */
1099 MyType &operator+=( const MyType &rSrc ) 1233 MyType &operator+=( const MyType &rSrc )
1100 { 1234 {
1101 if( rSrc.nLength == 0 ) 1235 append( rSrc );
1102 return (*this);
1103 rSrc.flatten();
1104 append( rSrc.pFirst->pData, rSrc.nLength );
1105 1236
1106 return (*this); 1237 return (*this);
1107 } 1238 }
@@ -1112,10 +1243,11 @@ namespace Bu
1112 */ 1243 */
1113 MyType &operator+=( const chr cData ) 1244 MyType &operator+=( const chr cData )
1114 { 1245 {
1115 if( pLast && pLast->nLength < nMinSize ) 1246 if( core->pLast && core->pLast->nLength < nMinSize )
1116 { 1247 {
1117 pLast->pData[pLast->nLength] = cData; 1248 _hardCopy();
1118 ++pLast->nLength; ++nLength; 1249 core->pLast->pData[core->pLast->nLength] = cData;
1250 ++core->pLast->nLength; ++core->nLength;
1119 // pLast->pData[pLast->nLength] = (chr)0; 1251 // pLast->pData[pLast->nLength] = (chr)0;
1120 } 1252 }
1121 else 1253 else
@@ -1134,16 +1266,14 @@ namespace Bu
1134 */ 1266 */
1135 MyType &operator=( const chr *pData ) 1267 MyType &operator=( const chr *pData )
1136 { 1268 {
1137 clear(); 1269 set( pData );
1138 append( pData );
1139 1270
1140 return (*this); 1271 return (*this);
1141 } 1272 }
1142 1273
1143 MyType &operator=( const std::basic_string<chr> &rData ) 1274 MyType &operator=( const std::basic_string<chr> &rData )
1144 { 1275 {
1145 clear(); 1276 set( rData.c_str(), rData.size() );
1146 append( rData.c_str(), rData.size() );
1147 1277
1148 return (*this); 1278 return (*this);
1149 } 1279 }
@@ -1229,25 +1359,28 @@ namespace Bu
1229 /** 1359 /**
1230 * Resize the string, possibly to make room for a copy. At the moment 1360 * Resize the string, possibly to make room for a copy. At the moment
1231 * this operation *is* destructive. What was in the string will in no 1361 * this operation *is* destructive. What was in the string will in no
1232 * way be preserved. 1362 * way be preserved. This is, however, very fast. If you want to
1363 * keep your data check out resize.
1233 *@param iSize the new size in bytes. The string is guranteed to have 1364 *@param iSize the new size in bytes. The string is guranteed to have
1234 * at least this much contiguous space available when done. 1365 * at least this much contiguous space available when done.
1235 */ 1366 */
1236 void setSize( long iSize ) 1367 void setSize( long iSize )
1237 { 1368 {
1238 clear(); 1369 _hardCopy();
1239 appendChunk( newChunk( iSize ) ); 1370 core->clear();
1371 core->appendChunk( core->newChunk( iSize ) );
1240 } 1372 }
1241 1373
1242 void expand() 1374 void expand()
1243 { 1375 {
1376#ifndef WIN32
1244 flatten(); 1377 flatten();
1378 _hardCopy();
1245 1379
1246#ifndef WIN32
1247 wordexp_t result; 1380 wordexp_t result;
1248 1381
1249 /* Expand the string for the program to run. */ 1382 /* Expand the string for the program to run. */
1250 switch (wordexp (pFirst->pData, &result, 0)) 1383 switch (wordexp (core->pFirst->pData, &result, 0))
1251 { 1384 {
1252 case 0: /* Successful. */ 1385 case 0: /* Successful. */
1253 { 1386 {
@@ -1272,7 +1405,7 @@ namespace Bu
1272 */ 1405 */
1273 MyType &operator=( const MyType &rSrc ) 1406 MyType &operator=( const MyType &rSrc )
1274 { 1407 {
1275 copyFrom( rSrc ); 1408 set( rSrc );
1276 1409
1277 return (*this); 1410 return (*this);
1278 } 1411 }
@@ -1284,7 +1417,7 @@ namespace Bu
1284 */ 1417 */
1285 bool operator==( const chr *pData ) const 1418 bool operator==( const chr *pData ) const
1286 { 1419 {
1287 if( pFirst == NULL ) { 1420 if( core->pFirst == NULL ) {
1288 if( pData == NULL ) 1421 if( pData == NULL )
1289 return true; 1422 return true;
1290 if( pData[0] == (chr)0 ) 1423 if( pData[0] == (chr)0 )
@@ -1293,14 +1426,14 @@ namespace Bu
1293 } 1426 }
1294 1427
1295 flatten(); 1428 flatten();
1296 pFirst->pData[nLength] = (chr)0; 1429 core->pFirst->pData[core->nLength] = (chr)0;
1297 const chr *a = pData; 1430 const chr *a = pData;
1298 chr *b = pFirst->pData; 1431 chr *b = core->pFirst->pData;
1299 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ ) 1432 for( long j = 0; *a!=(chr)0 || *b!=(chr)0; j++, a++, b++ )
1300 { 1433 {
1301 if( *a != *b ) 1434 if( *a != *b )
1302 return false; 1435 return false;
1303 if( *a == (chr)0 && j < nLength ) 1436 if( *a == (chr)0 && j < core->nLength )
1304 return false; 1437 return false;
1305 } 1438 }
1306 1439
@@ -1313,18 +1446,20 @@ namespace Bu
1313 */ 1446 */
1314 bool operator==( const MyType &pData ) const 1447 bool operator==( const MyType &pData ) const
1315 { 1448 {
1316 if( pFirst == pData.pFirst ) 1449 if( core == pData.core )
1450 return true;
1451 if( core->pFirst == pData.core->pFirst )
1317 return true; 1452 return true;
1318 if( pFirst == NULL ) 1453 if( core->pFirst == NULL )
1319 return false; 1454 return false;
1320 if( nLength != pData.nLength ) 1455 if( core->nLength != pData.core->nLength )
1321 return false; 1456 return false;
1322 1457
1323 flatten(); 1458 flatten();
1324 pData.flatten(); 1459 pData.flatten();
1325 const chr *a = pData.pFirst->pData; 1460 const chr *a = pData.core->pFirst->pData;
1326 chr *b = pFirst->pData; 1461 chr *b = core->pFirst->pData;
1327 for( long j = 0; j < nLength; j++, a++, b++ ) 1462 for( long j = 0; j < core->nLength; j++, a++, b++ )
1328 { 1463 {
1329 if( *a != *b ) 1464 if( *a != *b )
1330 return false; 1465 return false;
@@ -1357,9 +1492,9 @@ namespace Bu
1357 flatten(); 1492 flatten();
1358 pData.flatten(); 1493 pData.flatten();
1359 1494
1360 const chr *a = pData.pFirst->pData; 1495 const chr *a = pData.core->pFirst->pData;
1361 chr *b = pFirst->pData; 1496 chr *b = core->pFirst->pData;
1362 for( long j = 0; j < nLength; j++, a++, b++ ) 1497 for( long j = 0; j < core->nLength; j++, a++, b++ )
1363 { 1498 {
1364 if( *a != *b ) 1499 if( *a != *b )
1365 return *a < *b; 1500 return *a < *b;
@@ -1373,9 +1508,9 @@ namespace Bu
1373 flatten(); 1508 flatten();
1374 pData.flatten(); 1509 pData.flatten();
1375 1510
1376 const chr *a = pData.pFirst->pData; 1511 const chr *a = pData.core->pFirst->pData;
1377 chr *b = pFirst->pData; 1512 chr *b = core->pFirst->pData;
1378 for( long j = 0; j < nLength; j++, a++, b++ ) 1513 for( long j = 0; j < core->nLength; j++, a++, b++ )
1379 { 1514 {
1380 if( *a != *b ) 1515 if( *a != *b )
1381 return *a > *b; 1516 return *a > *b;
@@ -1391,11 +1526,12 @@ namespace Bu
1391 */ 1526 */
1392 chr &operator[]( long nIndex ) 1527 chr &operator[]( long nIndex )
1393 { 1528 {
1394 if( nIndex < 0 || nIndex >= nLength ) 1529 if( nIndex < 0 || nIndex >= core->nLength )
1395 throw Bu::ExceptionBase("Index out of range."); 1530 throw Bu::ExceptionBase("Index out of range.");
1396 flatten(); 1531 flatten();
1532 _hardCopy();
1397 1533
1398 return pFirst->pData[nIndex]; 1534 return core->pFirst->pData[nIndex];
1399 } 1535 }
1400 1536
1401 /** 1537 /**
@@ -1405,11 +1541,11 @@ namespace Bu
1405 */ 1541 */
1406 const chr &operator[]( long nIndex ) const 1542 const chr &operator[]( long nIndex ) const
1407 { 1543 {
1408 if( nIndex < 0 || nIndex >= nLength ) 1544 if( nIndex < 0 || nIndex >= core->nLength )
1409 throw Bu::ExceptionBase("Index out of range."); 1545 throw Bu::ExceptionBase("Index out of range.");
1410 flatten(); 1546 flatten();
1411 1547
1412 return pFirst->pData[nIndex]; 1548 return core->pFirst->pData[nIndex];
1413 } 1549 }
1414/* 1550/*
1415 operator const chr *() const 1551 operator const chr *() const
@@ -1422,35 +1558,35 @@ namespace Bu
1422 1558
1423 operator bool() const 1559 operator bool() const
1424 { 1560 {
1425 return (pFirst != NULL); 1561 return (core->pFirst != NULL);
1426 } 1562 }
1427 1563
1428 bool isSet() const 1564 bool isSet() const
1429 { 1565 {
1430 return (pFirst != NULL); 1566 return (core->pFirst != NULL);
1431 } 1567 }
1432 1568
1433 bool compareSub( const chr *pData, long nIndex, long nLen ) const 1569 bool compareSub( const chr *pData, long nIndex, long nLen ) const
1434 { 1570 {
1435 if( pFirst == NULL ) { 1571 if( core->pFirst == NULL ) {
1436 if( pData == NULL ) 1572 if( pData == NULL )
1437 return true; 1573 return true;
1438 if( pData[0] == (chr)0 ) 1574 if( pData[0] == (chr)0 )
1439 return true; 1575 return true;
1440 return false; 1576 return false;
1441 } 1577 }
1442 if( nIndex+nLen > nLength ) 1578 if( nIndex+nLen > core->nLength )
1443 return false; 1579 return false;
1444 1580
1445 flatten(); 1581 flatten();
1446 pFirst->pData[nLength] = (chr)0; 1582 core->pFirst->pData[core->nLength] = (chr)0;
1447 const chr *a = pData; 1583 const chr *a = pData;
1448 chr *b = pFirst->pData+nIndex; 1584 chr *b = core->pFirst->pData+nIndex;
1449 for( long j = 0; j < nLen; j++, a++, b++ ) 1585 for( long j = 0; j < nLen; j++, a++, b++ )
1450 { 1586 {
1451 if( *a != *b ) 1587 if( *a != *b )
1452 return false; 1588 return false;
1453 if( *a == (chr)0 && j < nLength ) 1589 if( *a == (chr)0 && j < core->nLength )
1454 return false; 1590 return false;
1455 } 1591 }
1456 1592
@@ -1459,17 +1595,17 @@ namespace Bu
1459 1595
1460 bool compareSub( const MyType &rData, long nIndex, long nLen ) const 1596 bool compareSub( const MyType &rData, long nIndex, long nLen ) const
1461 { 1597 {
1462 if( pFirst == NULL || rData.pFirst == NULL ) 1598 if( core->pFirst == NULL || rData.core->pFirst == NULL )
1463 return false; 1599 return false;
1464 if( nLen < 0 ) 1600 if( nLen < 0 )
1465 nLen = rData.nLength; 1601 nLen = rData.core->nLength;
1466 if( nIndex+nLen > nLength ) 1602 if( nIndex+nLen > core->nLength )
1467 return false; 1603 return false;
1468 1604
1469 flatten(); 1605 flatten();
1470 rData.flatten(); 1606 rData.flatten();
1471 const chr *a = rData.pFirst->pData; 1607 const chr *a = rData.core->pFirst->pData;
1472 chr *b = pFirst->pData + nIndex; 1608 chr *b = core->pFirst->pData + nIndex;
1473 for( long j = 0; j < nLen; j++, a++, b++ ) 1609 for( long j = 0; j < nLen; j++, a++, b++ )
1474 { 1610 {
1475 if( *a != *b ) 1611 if( *a != *b )
@@ -1488,8 +1624,8 @@ namespace Bu
1488 { 1624 {
1489 flatten(); 1625 flatten();
1490 1626
1491 return pFirst->pData[nIndex]==' ' || pFirst->pData[nIndex]=='\t' 1627 return core->pFirst->pData[nIndex]==' ' || core->pFirst->pData[nIndex]=='\t'
1492 || pFirst->pData[nIndex]=='\r' || pFirst->pData[nIndex]=='\n'; 1628 || core->pFirst->pData[nIndex]=='\r' || core->pFirst->pData[nIndex]=='\n';
1493 } 1629 }
1494 1630
1495 /** 1631 /**
@@ -1501,8 +1637,8 @@ namespace Bu
1501 { 1637 {
1502 flatten(); 1638 flatten();
1503 1639
1504 return (pFirst->pData[nIndex] >= 'a' && pFirst->pData[nIndex] <= 'z') 1640 return (core->pFirst->pData[nIndex] >= 'a' && core->pFirst->pData[nIndex] <= 'z')
1505 || (pFirst->pData[nIndex] >= 'A' && pFirst->pData[nIndex] <= 'Z'); 1641 || (core->pFirst->pData[nIndex] >= 'A' && core->pFirst->pData[nIndex] <= 'Z');
1506 } 1642 }
1507 1643
1508 /** 1644 /**
@@ -1511,11 +1647,12 @@ namespace Bu
1511 void toLower() 1647 void toLower()
1512 { 1648 {
1513 flatten(); 1649 flatten();
1650 _hardCopy();
1514 1651
1515 for( long j = 0; j < nLength; j++ ) 1652 for( long j = 0; j < core->nLength; j++ )
1516 { 1653 {
1517 if( pFirst->pData[j] >= 'A' && pFirst->pData[j] <= 'Z' ) 1654 if( core->pFirst->pData[j] >= 'A' && core->pFirst->pData[j] <= 'Z' )
1518 pFirst->pData[j] -= 'A'-'a'; 1655 core->pFirst->pData[j] -= 'A'-'a';
1519 } 1656 }
1520 } 1657 }
1521 1658
@@ -1525,11 +1662,12 @@ namespace Bu
1525 void toUpper() 1662 void toUpper()
1526 { 1663 {
1527 flatten(); 1664 flatten();
1665 _hardCopy();
1528 1666
1529 for( long j = 0; j < nLength; j++ ) 1667 for( long j = 0; j < core->nLength; j++ )
1530 { 1668 {
1531 if( pFirst->pData[j] >= 'a' && pFirst->pData[j] <= 'z' ) 1669 if( core->pFirst->pData[j] >= 'a' && core->pFirst->pData[j] <= 'z' )
1532 pFirst->pData[j] += 'A'-'a'; 1670 core->pFirst->pData[j] += 'A'-'a';
1533 } 1671 }
1534 } 1672 }
1535 1673
@@ -1646,9 +1784,9 @@ namespace Bu
1646 long findIdx( const chr cChar, long iStart=0 ) const 1784 long findIdx( const chr cChar, long iStart=0 ) const
1647 { 1785 {
1648 flatten(); 1786 flatten();
1649 for( long j = iStart; j < pFirst->nLength; j++ ) 1787 for( long j = iStart; j < core->pFirst->nLength; j++ )
1650 { 1788 {
1651 if( pFirst->pData[j] == cChar ) 1789 if( core->pFirst->pData[j] == cChar )
1652 return j; 1790 return j;
1653 } 1791 }
1654 return -1; 1792 return -1;
@@ -1664,9 +1802,9 @@ namespace Bu
1664 { 1802 {
1665 long nTLen = strlen( sText ); 1803 long nTLen = strlen( sText );
1666 flatten(); 1804 flatten();
1667 for( long j = iStart; j < pFirst->nLength-nTLen; j++ ) 1805 for( long j = iStart; j < core->pFirst->nLength-nTLen; j++ )
1668 { 1806 {
1669 if( !strncmp( sText, pFirst->pData+j, nTLen ) ) 1807 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1670 return j; 1808 return j;
1671 } 1809 }
1672 return -1; 1810 return -1;
@@ -1681,9 +1819,9 @@ namespace Bu
1681 { 1819 {
1682 long nTLen = strlen( sText ); 1820 long nTLen = strlen( sText );
1683 flatten(); 1821 flatten();
1684 for( long j = pFirst->nLength-nTLen-1; j >= 0; j-- ) 1822 for( long j = core->pFirst->nLength-nTLen-1; j >= 0; j-- )
1685 { 1823 {
1686 if( !strncmp( sText, pFirst->pData+j, nTLen ) ) 1824 if( !strncmp( sText, core->pFirst->pData+j, nTLen ) )
1687 return j; 1825 return j;
1688 } 1826 }
1689 return -1; 1827 return -1;
@@ -1695,16 +1833,18 @@ namespace Bu
1695 */ 1833 */
1696 void trimFront( long nAmnt ) 1834 void trimFront( long nAmnt )
1697 { 1835 {
1698 long nNewLen = nLength - nAmnt; 1836 long nNewLen = core->nLength - nAmnt;
1699 flatten(); 1837 flatten();
1700 Chunk *pNew = newChunk( nNewLen ); 1838 Chunk *pNew = core->newChunk( nNewLen );
1701 cpy( pNew->pData, pFirst->pData+nAmnt, nNewLen ); 1839 cpy( pNew->pData, core->pFirst->pData+nAmnt, nNewLen );
1702 clear(); 1840 _hardCopy();
1703 appendChunk( pNew ); 1841 core->clear();
1842 core->appendChunk( pNew );
1704 } 1843 }
1705 1844
1706 void format( const char *sFrmt, ...) 1845 void format( const char *sFrmt, ...)
1707 { 1846 {
1847 _hardCopy();
1708 clear(); 1848 clear();
1709 1849
1710 va_list ap; 1850 va_list ap;
@@ -1712,37 +1852,39 @@ namespace Bu
1712 1852
1713 long iLen = vsnprintf( NULL, 0, sFrmt, ap ); 1853 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1714 1854
1715 Chunk *pNew = newChunk( iLen ); 1855 Chunk *pNew = core->newChunk( iLen );
1716 vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); 1856 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
1717 appendChunk( pNew ); 1857 core->appendChunk( pNew );
1718 1858
1719 va_end( ap ); 1859 va_end( ap );
1720 } 1860 }
1721 1861
1722 void formatAppend( const char *sFrmt, ...) 1862 void formatAppend( const char *sFrmt, ...)
1723 { 1863 {
1864 _hardCopy();
1724 va_list ap; 1865 va_list ap;
1725 va_start( ap, sFrmt ); 1866 va_start( ap, sFrmt );
1726 1867
1727 long iLen = vsnprintf( NULL, 0, sFrmt, ap ); 1868 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1728 1869
1729 Chunk *pNew = newChunk( iLen ); 1870 Chunk *pNew = core->newChunk( iLen );
1730 vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); 1871 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
1731 appendChunk( pNew ); 1872 core->appendChunk( pNew );
1732 1873
1733 va_end( ap ); 1874 va_end( ap );
1734 } 1875 }
1735 1876
1736 void formatPrepend( const char *sFrmt, ...) 1877 void formatPrepend( const char *sFrmt, ...)
1737 { 1878 {
1879 _hardCopy();
1738 va_list ap; 1880 va_list ap;
1739 va_start( ap, sFrmt ); 1881 va_start( ap, sFrmt );
1740 1882
1741 long iLen = vsnprintf( NULL, 0, sFrmt, ap ); 1883 long iLen = vsnprintf( NULL, 0, sFrmt, ap );
1742 1884
1743 Chunk *pNew = newChunk( iLen ); 1885 Chunk *pNew = core->newChunk( iLen );
1744 vsnprintf( pNew->pData, iLen+1, sFrmt, ap ); 1886 vsnprintf( pNew->pData, iLen+1, sFrmt, ap );
1745 prependChunk( pNew ); 1887 core->prependChunk( pNew );
1746 1888
1747 va_end( ap ); 1889 va_end( ap );
1748 } 1890 }
@@ -1755,39 +1897,40 @@ namespace Bu
1755 { 1897 {
1756 if( ar.isLoading() ) 1898 if( ar.isLoading() )
1757 { 1899 {
1758 clear(); 1900 _hardCopy();
1901 core->clear();
1759 long nLen; 1902 long nLen;
1760 ar >> nLen; 1903 ar >> nLen;
1761 1904
1762 if( nLen > 0 ) 1905 if( nLen > 0 )
1763 { 1906 {
1764 Chunk *pNew = newChunk( nLen ); 1907 Chunk *pNew = core->newChunk( nLen );
1765 ar.read( pNew->pData, nLen*sizeof(chr) ); 1908 ar.read( pNew->pData, nLen*sizeof(chr) );
1766 appendChunk( pNew ); 1909 core->appendChunk( pNew );
1767 } 1910 }
1768 } 1911 }
1769 else 1912 else
1770 { 1913 {
1771 flatten(); 1914 flatten();
1772 1915
1773 ar << nLength; 1916 ar << core->nLength;
1774 if( nLength ) 1917 if( core->nLength )
1775 ar.write( pFirst->pData, nLength*sizeof(chr) ); 1918 ar.write( core->pFirst->pData, core->nLength*sizeof(chr) );
1776 } 1919 }
1777 } 1920 }
1778 1921
1779 iterator begin() 1922 iterator begin()
1780 { 1923 {
1781 if( nLength == 0 ) 1924 if( core->nLength == 0 )
1782 return iterator( NULL, 0 ); 1925 return iterator( NULL, 0 );
1783 return iterator( pFirst, 0 ); 1926 return iterator( core->pFirst, 0 );
1784 } 1927 }
1785 1928
1786 const_iterator begin() const 1929 const_iterator begin() const
1787 { 1930 {
1788 if( nLength == 0 ) 1931 if( core->nLength == 0 )
1789 return const_iterator( NULL, 0 ); 1932 return const_iterator( NULL, 0 );
1790 return iterator( pFirst, 0 ); 1933 return iterator( core->pFirst, 0 );
1791 } 1934 }
1792 1935
1793 iterator end() 1936 iterator end()
@@ -1802,7 +1945,7 @@ namespace Bu
1802 1945
1803 bool isEmpty() const 1946 bool isEmpty() const
1804 { 1947 {
1805 if( nLength == 0 ) 1948 if( core->nLength == 0 )
1806 return true; 1949 return true;
1807 return false; 1950 return false;
1808 } 1951 }
@@ -1813,12 +1956,12 @@ namespace Bu
1813 if( isFlat() ) 1956 if( isFlat() )
1814 return; 1957 return;
1815 1958
1816 if( pFirst == NULL ) 1959 if( core->pFirst == NULL )
1817 return; 1960 return;
1818 1961
1819 Chunk *pNew = newChunk( nLength ); 1962 Chunk *pNew = core->newChunk( core->nLength );
1820 chr *pos = pNew->pData; 1963 chr *pos = pNew->pData;
1821 Chunk *i = pFirst; 1964 Chunk *i = core->pFirst;
1822 for(;;) 1965 for(;;)
1823 { 1966 {
1824 cpy( pos, i->pData, i->nLength ); 1967 cpy( pos, i->pData, i->nLength );
@@ -1827,133 +1970,16 @@ namespace Bu
1827 if( i == NULL ) 1970 if( i == NULL )
1828 break; 1971 break;
1829 } 1972 }
1830 realClear(); 1973 core->clear();
1831 1974
1832 pLast = pFirst = pNew; 1975 core->pLast = core->pFirst = pNew;
1833 nLength = pNew->nLength; 1976 core->nLength = pNew->nLength;
1834 }
1835
1836 void realClear() const
1837 {
1838 if( pFirst == NULL )
1839 return;
1840
1841 Chunk *i = pFirst;
1842 for(;;)
1843 {
1844 Chunk *n = i->pNext;
1845 aChr.deallocate( i->pData, i->nLength+1 );
1846 aChunk.deallocate( i, 1 );
1847 if( n == NULL )
1848 break;
1849 i = n;
1850 }
1851 pFirst = pLast = NULL;
1852 nLength = 0;
1853 }
1854
1855 void copyFrom( const FBasicString<chr, nMinSize, chralloc, chunkalloc> &rSrc )
1856 {
1857 if( rSrc.pFirst == NULL )
1858 {
1859 clear();
1860 return;
1861 }
1862
1863 Chunk *pNew = newChunk( rSrc.nLength );
1864 chr *pos = pNew->pData;
1865 Chunk *i = rSrc.pFirst;
1866 for(;;)
1867 {
1868 cpy( pos, i->pData, i->nLength );
1869 pos += i->nLength;
1870 i = i->pNext;
1871 if( i == NULL )
1872 break;
1873 }
1874 clear();
1875
1876 appendChunk( pNew );
1877 } 1977 }
1878 1978
1879 bool isFlat() const 1979 bool isFlat() const
1880 { 1980 {
1881 return (pFirst == pLast); 1981 return (core->pFirst == core->pLast);
1882 } 1982 }
1883
1884 Chunk *newChunk() const
1885 {
1886 Chunk *pNew = aChunk.allocate( 1 );
1887 pNew->pNext = NULL;
1888 return pNew;
1889 }
1890
1891 Chunk *newChunk( long nLen ) const
1892 {
1893 Chunk *pNew = aChunk.allocate( 1 );
1894 pNew->pNext = NULL;
1895 pNew->nLength = nLen;
1896 pNew->pData = aChr.allocate( (nLen<nMinSize)?(nMinSize):(nLen)+1 );
1897 pNew->pData[nLen] = (chr)0;
1898 return pNew;
1899 }
1900
1901 Chunk *copyChunk( Chunk *pSrc ) const
1902 {
1903 Chunk *pNew = aChunk.allocate( 1 );
1904 pNew->pNext = pSrc->pNext;
1905 pNew->nLength = pSrc->nLength;
1906 pNew->pData = aChr.allocate( pSrc->nLength+1 );
1907 cpy( pNew->pData, pSrc->pData, pSrc->nLength );
1908 pNew->pData[pNew->nLength] = (chr)0;
1909 return pNew;
1910 }
1911
1912 void appendChunk( Chunk *pNewChunk )
1913 {
1914 if( pFirst == NULL )
1915 pLast = pFirst = pNewChunk;
1916 else
1917 {
1918 pLast->pNext = pNewChunk;
1919 pLast = pNewChunk;
1920 }
1921
1922 nLength += pNewChunk->nLength;
1923 }
1924
1925 void prependChunk( Chunk *pNewChunk )
1926 {
1927 if( pFirst == NULL )
1928 pLast = pFirst = pNewChunk;
1929 else
1930 {
1931 pNewChunk->pNext = pFirst;
1932 pFirst = pNewChunk;
1933 }
1934
1935 nLength += pNewChunk->nLength;
1936 }
1937
1938#ifdef VALTEST
1939 void cpy( chr *dest, const chr *src, long count ) const
1940 {
1941 for( int j = 0; j < count; j++ )
1942 {
1943 *dest = *src;
1944 dest++;
1945 src++;
1946 }
1947 }
1948#endif
1949
1950 private:
1951 mutable long nLength;
1952 mutable Chunk *pFirst;
1953 mutable Chunk *pLast;
1954
1955 mutable chralloc aChr;
1956 mutable chunkalloc aChunk;
1957 }; 1983 };
1958 1984
1959 template<class T> FBasicString<T> operator+( const T *pLeft, const FBasicString<T> &rRight ) 1985 template<class T> FBasicString<T> operator+( const T *pLeft, const FBasicString<T> &rRight )