aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--src/fbasicstring.h718
-rw-r--r--src/list.cpp1
-rw-r--r--src/list.h373
-rw-r--r--src/sharedcore.h48
-rw-r--r--src/tests/sharedcore.cpp24
-rw-r--r--src/tests/speed.cpp5
-rw-r--r--src/unit/fstring.unit6
7 files changed, 629 insertions, 546 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 )
diff --git a/src/list.cpp b/src/list.cpp
index bc7c2eb..3f77b5c 100644
--- a/src/list.cpp
+++ b/src/list.cpp
@@ -7,3 +7,4 @@
7 7
8#include "bu/list.h" 8#include "bu/list.h"
9 9
10template class Bu::List<int>;
diff --git a/src/list.h b/src/list.h
index 934766b..d711a2e 100644
--- a/src/list.h
+++ b/src/list.h
@@ -10,7 +10,8 @@
10 10
11#include <memory> 11#include <memory>
12#include "bu/exceptionbase.h" 12#include "bu/exceptionbase.h"
13#include "bu/util.h" 13#include "bu/sharedcore.h"
14//#include "bu/util.h"
14 15
15namespace Bu 16namespace Bu
16{ 17{
@@ -22,6 +23,153 @@ namespace Bu
22 ListLink *pPrev; 23 ListLink *pPrev;
23 }; 24 };
24 25
26 template<typename value, typename cmpfunc, typename valuealloc,
27 typename linkalloc>
28 struct ListCore
29 {
30 typedef struct ListLink<value> Link;
31 ListCore() :
32 pFirst( NULL ),
33 pLast( NULL ),
34 nSize( 0 )
35 { }
36 Link *pFirst;
37 Link *pLast;
38 long nSize;
39 cmpfunc cmp;
40 linkalloc la;
41 valuealloc va;
42
43 /**
44 * Append a value to the list.
45 *@param v (const value_type &) The value to append.
46 */
47 void append( const value &v )
48 {
49 Link *pNew = la.allocate( 1 );
50 pNew->pValue = va.allocate( 1 );
51 va.construct( pNew->pValue, v );
52 nSize++;
53 if( pFirst == NULL )
54 {
55 // Empty list
56 pFirst = pLast = pNew;
57 pNew->pNext = pNew->pPrev = NULL;
58 }
59 else
60 {
61 pNew->pNext = NULL;
62 pNew->pPrev = pLast;
63 pLast->pNext = pNew;
64 pLast = pNew;
65 }
66 }
67
68 /**
69 * Prepend a value to the list.
70 *@param v (const value_type &) The value to prepend.
71 */
72 void prepend( const value &v )
73 {
74 Link *pNew = la.allocate( 1 );
75 pNew->pValue = va.allocate( 1 );
76 va.construct( pNew->pValue, v );
77 nSize++;
78 if( pFirst == NULL )
79 {
80 // Empty list
81 pFirst = pLast = pNew;
82 pNew->pNext = pNew->pPrev = NULL;
83 }
84 else
85 {
86 pNew->pNext = pFirst;
87 pNew->pPrev = NULL;
88 pFirst->pPrev = pNew;
89 pFirst = pNew;
90 }
91 }
92
93 void clear()
94 {
95 Link *pCur = pFirst;
96 for(;;)
97 {
98 if( pCur == NULL ) break;
99 va.destroy( pCur->pValue );
100 va.deallocate( pCur->pValue, 1 );
101 Link *pTmp = pCur->pNext;
102 la.destroy( pCur );
103 la.deallocate( pCur, 1 );
104 pCur = pTmp;
105 }
106 pFirst = pLast = NULL;
107 nSize = 0;
108 }
109
110 void insert( Link *pLink, const value &v )
111 {
112 Link *pAfter = pLink;
113 if( pAfter == NULL )
114 {
115 append( v );
116 return;
117 }
118 Link *pPrev = pAfter->pPrev;
119 if( pPrev == NULL )
120 {
121 prepend( v );
122 return;
123 }
124
125 Link *pNew = la.allocate( 1 );
126 pNew->pValue = va.allocate( 1 );
127 va.construct( pNew->pValue, v );
128 nSize++;
129
130 pNew->pNext = pAfter;
131 pNew->pPrev = pPrev;
132 pAfter->pPrev = pNew;
133 pPrev->pNext = pNew;
134 }
135
136 /**
137 * Erase an item from the list.
138 *@param i (iterator) The item to erase.
139 */
140 void erase( Link *pLink )
141 {
142 Link *pCur = pLink;
143 if( pCur == NULL ) return;
144 Link *pPrev = pCur->pPrev;
145 if( pPrev == NULL )
146 {
147 va.destroy( pCur->pValue );
148 va.deallocate( pCur->pValue, 1 );
149 pFirst = pCur->pNext;
150 la.destroy( pCur );
151 la.deallocate( pCur, 1 );
152 if( pFirst == NULL )
153 pLast = NULL;
154 else
155 pFirst->pPrev = NULL;
156 nSize--;
157 }
158 else
159 {
160 va.destroy( pCur->pValue );
161 va.deallocate( pCur->pValue, 1 );
162 Link *pTmp = pCur->pNext;
163 la.destroy( pCur );
164 la.deallocate( pCur, 1 );
165 pPrev->pNext = pTmp;
166 if( pTmp != NULL )
167 pTmp->pPrev = pPrev;
168 nSize--;
169 }
170 }
171 };
172
25 /** 173 /**
26 * Linked list template container. This class is similar to the stl list 174 * Linked list template container. This class is similar to the stl list
27 * class except for a few minor changes. First, it doesn't mimic a stack or 175 * class except for a few minor changes. First, it doesn't mimic a stack or
@@ -38,61 +186,46 @@ namespace Bu
38 template<typename value, typename cmpfunc=__basicGTCmp<value>, 186 template<typename value, typename cmpfunc=__basicGTCmp<value>,
39 typename valuealloc=std::allocator<value>, 187 typename valuealloc=std::allocator<value>,
40 typename linkalloc=std::allocator<struct ListLink<value> > > 188 typename linkalloc=std::allocator<struct ListLink<value> > >
41 class List 189 class List : public SharedCore< struct ListCore<value, cmpfunc, valuealloc,
190 linkalloc> >
42 { 191 {
43 private: 192 private:
44 typedef struct ListLink<value> Link; 193 typedef struct ListLink<value> Link;
45 typedef class List<value, cmpfunc, valuealloc, linkalloc> MyType; 194 typedef class List<value, cmpfunc, valuealloc, linkalloc> MyType;
195 typedef struct ListCore<value, cmpfunc, valuealloc, linkalloc> Core;
196
197 protected:
198 using SharedCore< Core >::core;
199 using SharedCore< Core >::_hardCopy;
200 using SharedCore< Core >::_allocateCore;
46 201
47 public: 202 public:
48 struct const_iterator; 203 struct const_iterator;
49 struct iterator; 204 struct iterator;
50 205
51 List() : 206 List()
52 pFirst( NULL ),
53 pLast( NULL ),
54 nSize( 0 )
55 { 207 {
56 } 208 }
57 209
58 List( const MyType &src ) : 210 List( const MyType &src ) :
59 pFirst( NULL ), 211 SharedCore< Core >( src )
60 pLast( NULL ),
61 nSize( 0 )
62 { 212 {
63 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
64 {
65 append( *pCur->pValue );
66 }
67 } 213 }
68 214
69 ~List() 215 ~List()
70 { 216 {
71 clear();
72 }
73
74 /**
75 * Assignment operator.
76 *@param src (const MyType &) The list to assign to your list.
77 */
78 MyType &operator=( const MyType &src )
79 {
80 clear();
81 for( Link *pCur = src.pFirst; pCur; pCur = pCur->pNext )
82 {
83 append( *pCur->pValue );
84 }
85 return *this;
86 } 217 }
87 218
88 MyType &operator+=( const value &v ) 219 MyType &operator+=( const value &v )
89 { 220 {
221 _hardCopy();
90 append( v ); 222 append( v );
91 return *this; 223 return *this;
92 } 224 }
93 225
94 MyType &operator+=( const MyType &src ) 226 MyType &operator+=( const MyType &src )
95 { 227 {
228 _hardCopy();
96 append( src ); 229 append( src );
97 return *this; 230 return *this;
98 } 231 }
@@ -102,67 +235,43 @@ namespace Bu
102 */ 235 */
103 void clear() 236 void clear()
104 { 237 {
105 Link *pCur = pFirst; 238 _hardCopy();
106 for(;;) 239 core->clear();
107 {
108 if( pCur == NULL ) break;
109 va.destroy( pCur->pValue );
110 va.deallocate( pCur->pValue, 1 );
111 Link *pTmp = pCur->pNext;
112 la.destroy( pCur );
113 la.deallocate( pCur, 1 );
114 pCur = pTmp;
115 }
116 pFirst = pLast = NULL;
117 nSize = 0;
118 } 240 }
119 241
120 void enqueue( const value &v ) 242 void enqueue( const value &v )
121 { 243 {
244 _hardCopy();
122 append( v ); 245 append( v );
123 } 246 }
124 247
125 value dequeue() 248 value dequeue()
126 { 249 {
127 value v = *pFirst->pValue; 250 // _hardCopy(); erase will call this for me
251 value v = *core->pFirst->pValue;
128 252
129 erase( begin() ); 253 erase( begin() );
130 254
131 return v; 255 return v;
132 } 256 }
133 257
134
135 /** 258 /**
136 * Append a value to the list. 259 * Append a value to the list.
137 *@param v (const value_type &) The value to append. 260 *@param v (const value_type &) The value to append.
138 */ 261 */
139 void append( const value &v ) 262 void append( const value &v )
140 { 263 {
141 Link *pNew = la.allocate( 1 ); 264 _hardCopy();
142 pNew->pValue = va.allocate( 1 ); 265 core->append( v );
143 va.construct( pNew->pValue, v );
144 nSize++;
145 if( pFirst == NULL )
146 {
147 // Empty list
148 pFirst = pLast = pNew;
149 pNew->pNext = pNew->pPrev = NULL;
150 }
151 else
152 {
153 pNew->pNext = NULL;
154 pNew->pPrev = pLast;
155 pLast->pNext = pNew;
156 pLast = pNew;
157 }
158 } 266 }
159 267
160 void append( const MyType &rSrc ) 268 void append( const MyType &rSrc )
161 { 269 {
270 _hardCopy();
162 for( typename MyType::const_iterator i = rSrc.begin(); 271 for( typename MyType::const_iterator i = rSrc.begin();
163 i != rSrc.end(); i++ ) 272 i != rSrc.end(); i++ )
164 { 273 {
165 append( *i ); 274 core->append( *i );
166 } 275 }
167 } 276 }
168 277
@@ -172,23 +281,8 @@ namespace Bu
172 */ 281 */
173 void prepend( const value &v ) 282 void prepend( const value &v )
174 { 283 {
175 Link *pNew = la.allocate( 1 ); 284 _hardCopy();
176 pNew->pValue = va.allocate( 1 ); 285 core->prepend( v );
177 va.construct( pNew->pValue, v );
178 nSize++;
179 if( pFirst == NULL )
180 {
181 // Empty list
182 pFirst = pLast = pNew;
183 pNew->pNext = pNew->pPrev = NULL;
184 }
185 else
186 {
187 pNew->pNext = pFirst;
188 pNew->pPrev = NULL;
189 pFirst->pPrev = pNew;
190 pFirst = pNew;
191 }
192 } 286 }
193 287
194 /** 288 /**
@@ -197,37 +291,19 @@ namespace Bu
197 */ 291 */
198 void prepend( const MyType &rSrc ) 292 void prepend( const MyType &rSrc )
199 { 293 {
294 _hardCopy();
200 for( typename MyType::const_iterator i = rSrc.begin(); 295 for( typename MyType::const_iterator i = rSrc.begin();
201 i != rSrc.end(); i++ ) 296 i != rSrc.end(); i++ )
202 { 297 {
203 prepend( *i ); 298 core->prepend( *i );
204 } 299 }
205 } 300 }
206 301
207 void insert( MyType::iterator &i, const value &v ) 302 void insert( MyType::iterator &i, const value &v )
208 { 303 {
209 Link *pAfter = i.pLink; 304 _hardCopy();
210 if( pAfter == NULL )
211 {
212 append( v );
213 return;
214 }
215 Link *pPrev = pAfter->pPrev;
216 if( pPrev == NULL )
217 {
218 prepend( v );
219 return;
220 }
221 305
222 Link *pNew = la.allocate( 1 ); 306 core->insert( i.pLink, v );
223 pNew->pValue = va.allocate( 1 );
224 va.construct( pNew->pValue, v );
225 nSize++;
226
227 pNew->pNext = pAfter;
228 pNew->pPrev = pPrev;
229 pAfter->pPrev = pNew;
230 pPrev->pNext = pNew;
231 } 307 }
232 308
233 /** 309 /**
@@ -239,40 +315,27 @@ namespace Bu
239 */ 315 */
240 void insertSorted( const value &v ) 316 void insertSorted( const value &v )
241 { 317 {
242 Link *pNew = la.allocate( 1 ); 318 _hardCopy();
243 pNew->pValue = va.allocate( 1 ); 319 if( core->pFirst == NULL )
244 va.construct( pNew->pValue, v );
245 nSize++;
246 if( pFirst == NULL )
247 { 320 {
248 // Empty list 321 // Empty list
249 pFirst = pLast = pNew; 322 core->append( v );
250 pNew->pNext = pNew->pPrev = NULL;
251 return; 323 return;
252 } 324 }
253 else 325 else
254 { 326 {
255 Link *pCur = pFirst; 327 Link *pCur = core->pFirst;
256 for(;;) 328 for(;;)
257 { 329 {
258 if( !cmp( v, *(pCur->pValue)) ) 330 if( !core->cmp( v, *(pCur->pValue)) )
259 { 331 {
260 pNew->pNext = pCur; 332 core->insert( pCur, v );
261 pNew->pPrev = pCur->pPrev;
262 pCur->pPrev = pNew;
263 if( pNew->pPrev == NULL )
264 pFirst = pNew;
265 else
266 pNew->pPrev->pNext = pNew;
267 return; 333 return;
268 } 334 }
269 pCur = pCur->pNext; 335 pCur = pCur->pNext;
270 if( pCur == NULL ) 336 if( pCur == NULL )
271 { 337 {
272 pNew->pNext = NULL; 338 core->append( v );
273 pNew->pPrev = pLast;
274 pLast->pNext = pNew;
275 pLast = pNew;
276 return; 339 return;
277 } 340 }
278 } 341 }
@@ -541,7 +604,8 @@ namespace Bu
541 */ 604 */
542 iterator begin() 605 iterator begin()
543 { 606 {
544 return iterator( pFirst ); 607 _hardCopy();
608 return iterator( core->pFirst );
545 } 609 }
546 610
547 /** 611 /**
@@ -550,7 +614,7 @@ namespace Bu
550 */ 614 */
551 const_iterator begin() const 615 const_iterator begin() const
552 { 616 {
553 return const_iterator( pFirst ); 617 return const_iterator( core->pFirst );
554 } 618 }
555 619
556 /** 620 /**
@@ -579,34 +643,8 @@ namespace Bu
579 */ 643 */
580 void erase( iterator i ) 644 void erase( iterator i )
581 { 645 {
582 Link *pCur = i.pLink; 646 _hardCopy();
583 if( pCur == NULL ) return; 647 core->erase( i.pLink );
584 Link *pPrev = pCur->pPrev;
585 if( pPrev == NULL )
586 {
587 va.destroy( pCur->pValue );
588 va.deallocate( pCur->pValue, 1 );
589 pFirst = pCur->pNext;
590 la.destroy( pCur );
591 la.deallocate( pCur, 1 );
592 if( pFirst == NULL )
593 pLast = NULL;
594 else
595 pFirst->pPrev = NULL;
596 nSize--;
597 }
598 else
599 {
600 va.destroy( pCur->pValue );
601 va.deallocate( pCur->pValue, 1 );
602 Link *pTmp = pCur->pNext;
603 la.destroy( pCur );
604 la.deallocate( pCur, 1 );
605 pPrev->pNext = pTmp;
606 if( pTmp != NULL )
607 pTmp->pPrev = pPrev;
608 nSize--;
609 }
610 } 648 }
611 649
612 /** 650 /**
@@ -615,7 +653,7 @@ namespace Bu
615 */ 653 */
616 void erase( const value &v ) 654 void erase( const value &v )
617 { 655 {
618 for( iterator i = begin(); i != end(); i++ ) 656 for( const_iterator i = begin(); i != end(); i++ )
619 { 657 {
620 if( (*i) == v ) 658 if( (*i) == v )
621 { 659 {
@@ -631,7 +669,7 @@ namespace Bu
631 */ 669 */
632 long getSize() const 670 long getSize() const
633 { 671 {
634 return nSize; 672 return core->nSize;
635 } 673 }
636 674
637 /** 675 /**
@@ -640,7 +678,8 @@ namespace Bu
640 */ 678 */
641 value &first() 679 value &first()
642 { 680 {
643 return *pFirst->pValue; 681 _hardCopy();
682 return *core->pFirst->pValue;
644 } 683 }
645 684
646 /** 685 /**
@@ -649,7 +688,7 @@ namespace Bu
649 */ 688 */
650 const value &first() const 689 const value &first() const
651 { 690 {
652 return *pFirst->pValue; 691 return *core->pFirst->pValue;
653 } 692 }
654 693
655 /** 694 /**
@@ -658,7 +697,8 @@ namespace Bu
658 */ 697 */
659 value &last() 698 value &last()
660 { 699 {
661 return *pLast->pValue; 700 _hardCopy();
701 return *core->pLast->pValue;
662 } 702 }
663 703
664 /** 704 /**
@@ -667,21 +707,26 @@ namespace Bu
667 */ 707 */
668 const value &last() const 708 const value &last() const
669 { 709 {
670 return *pLast->pValue; 710 return *core->pLast->pValue;
671 } 711 }
672 712
673 bool isEmpty() const 713 bool isEmpty() const
674 { 714 {
675 return (nSize == 0); 715 return (core->nSize == 0);
676 } 716 }
677 717
718 protected:
719 virtual Core *_copyCore( Core *src )
720 {
721 Core *pRet = _allocateCore();
722 for( Link *pCur = src->pFirst; pCur; pCur = pCur->pNext )
723 {
724 pRet->append( *pCur->pValue );
725 }
726 return pRet;
727 }
728
678 private: 729 private:
679 Link *pFirst;
680 Link *pLast;
681 linkalloc la;
682 valuealloc va;
683 long nSize;
684 cmpfunc cmp;
685 }; 730 };
686 731
687 class Formatter; 732 class Formatter;
diff --git a/src/sharedcore.h b/src/sharedcore.h
index 9f42345..3b60c42 100644
--- a/src/sharedcore.h
+++ b/src/sharedcore.h
@@ -9,7 +9,6 @@
9#define BU_SHARED_CORE_H 9#define BU_SHARED_CORE_H
10 10
11#include "bu/util.h" 11#include "bu/util.h"
12#include "bu/sio.h"
13 12
14namespace Bu 13namespace Bu
15{ 14{
@@ -19,13 +18,13 @@ namespace Bu
19 typedef class SharedCore<Core> _SharedType; 18 typedef class SharedCore<Core> _SharedType;
20 public: 19 public:
21 SharedCore() : 20 SharedCore() :
22 data( new Core ), 21 core( _allocateCore() ),
23 iRefCount( new int(1) ) 22 iRefCount( new int(1) )
24 { 23 {
25 } 24 }
26 25
27 SharedCore( const _SharedType &rSrc ) : 26 SharedCore( const _SharedType &rSrc ) :
28 data( NULL ), 27 core( NULL ),
29 iRefCount( NULL ) 28 iRefCount( NULL )
30 { 29 {
31 _softCopy( rSrc ); 30 _softCopy( rSrc );
@@ -48,48 +47,57 @@ namespace Bu
48 } 47 }
49 48
50 protected: 49 protected:
51 Core *data; 50 Core *core;
52 void _hardCopy() 51 void _hardCopy()
53 { 52 {
54 if( !data || !iRefCount ) 53 if( !core || !iRefCount )
55 return; 54 return;
56 sio << "_hardCopy()" << sio.nl; 55 if( (*iRefCount) == 1 )
57 Core *copy = new Core( *data ); 56 return;
57 Core *copy = _copyCore( core );
58 _deref(); 58 _deref();
59 data = copy; 59 core = copy;
60 iRefCount = new int( 1 ); 60 iRefCount = new int( 1 );
61 } 61 }
62 62
63 virtual Core *_allocateCore()
64 {
65 return new Core();
66 }
67
68 virtual Core *_copyCore( Core *pSrc )
69 {
70 return new Core( *pSrc );
71 }
72
73 virtual void _deallocateCore( Core *pSrc )
74 {
75 delete pSrc;
76 }
77
63 private: 78 private:
64 void _deref() 79 void _deref()
65 { 80 {
66 sio << "_deref()" << sio.nl;
67 if( (--(*iRefCount)) == 0 ) 81 if( (--(*iRefCount)) == 0 )
68 { 82 {
69 sio << " --> iRefCount == 0, cleaning up." << sio.nl; 83 _deallocateCore( core );
70 delete data;
71 delete iRefCount; 84 delete iRefCount;
72 } 85 }
73 else 86 core = NULL;
74 sio << " --> iRefCount == " << *iRefCount << sio.nl;
75 data = NULL;
76 iRefCount = NULL; 87 iRefCount = NULL;
77 } 88 }
78 89
79 void _incRefCount() 90 void _incRefCount()
80 { 91 {
81 sio << "_incRefCount()" << sio.nl; 92 if( iRefCount && core )
82 if( iRefCount && data )
83 ++(*iRefCount); 93 ++(*iRefCount);
84 sio << " --> iRefCount == " << *iRefCount << sio.nl;
85 } 94 }
86 95
87 void _softCopy( const _SharedType &rSrc ) 96 void _softCopy( const _SharedType &rSrc )
88 { 97 {
89 sio << "_softCopy()" << sio.nl; 98 if( core )
90 if( data )
91 _deref(); 99 _deref();
92 data = rSrc.data; 100 core = rSrc.core;
93 iRefCount = rSrc.iRefCount; 101 iRefCount = rSrc.iRefCount;
94 _incRefCount(); 102 _incRefCount();
95 } 103 }
diff --git a/src/tests/sharedcore.cpp b/src/tests/sharedcore.cpp
index bdfde4c..9f65ac5 100644
--- a/src/tests/sharedcore.cpp
+++ b/src/tests/sharedcore.cpp
@@ -12,42 +12,42 @@ class Shint : public Bu::SharedCore<struct ShintCore>
12public: 12public:
13 Shint() 13 Shint()
14 { 14 {
15 data->val = 0; 15 core->val = 0;
16 } 16 }
17 17
18 Shint( int val ) 18 Shint( int val )
19 { 19 {
20 data->val = val; 20 core->val = val;
21 } 21 }
22 22
23 int getVal() 23 int getVal() const
24 { 24 {
25 return data->val; 25 return core->val;
26 } 26 }
27 27
28 void setValBad( int val ) 28 void setValBad( int val )
29 { 29 {
30 data->val = val; 30 core->val = val;
31 } 31 }
32 32
33 void setVal( int val ) 33 void setVal( int val )
34 { 34 {
35 _hardCopy(); 35 _hardCopy();
36 data->val = val; 36 core->val = val;
37 } 37 }
38 38
39 bool operator==( const Shint &rhs ) 39 bool operator==( const Shint &rhs )
40 { 40 {
41 if( data == rhs.data ) 41 if( core == rhs.core )
42 { 42 {
43 sio << "Same pointer (" << Fmt::ptr() << data << ")" << sio.nl; 43 sio << "Same pointer (" << Fmt::ptr() << core << ")" << sio.nl;
44 return true; 44 return true;
45 } 45 }
46 if( data->val == rhs.data->val ) 46 if( core->val == rhs.core->val )
47 { 47 {
48 sio << "Same value " << data->val << " (" 48 sio << "Same value " << core->val << " ("
49 << Fmt::ptr() << data << " vs " 49 << Fmt::ptr() << core << " vs "
50 << Fmt::ptr() << rhs.data << ")" 50 << Fmt::ptr() << rhs.core << ")"
51 << sio.nl; 51 << sio.nl;
52 return true; 52 return true;
53 } 53 }
diff --git a/src/tests/speed.cpp b/src/tests/speed.cpp
index b8924d7..5b26dd3 100644
--- a/src/tests/speed.cpp
+++ b/src/tests/speed.cpp
@@ -43,6 +43,9 @@ void fullTest( tst t )
43 43
44int main() 44int main()
45{ 45{
46 fullTest( tstCopy<Bu::FString>("This is a test string.") ); 46 Bu::FString str;
47 for( int j = 0; j < 500; j++ )
48 str.append("Hey, this is a test string. It will be reapeated many, many times. How's that?");
49 fullTest( tstCopy<Bu::FString>( str ) );
47} 50}
48 51
diff --git a/src/unit/fstring.unit b/src/unit/fstring.unit
index 7314095..40b1ce2 100644
--- a/src/unit/fstring.unit
+++ b/src/unit/fstring.unit
@@ -39,11 +39,11 @@
39{ 39{
40 Bu::FString a("Hey there"); 40 Bu::FString a("Hey there");
41 Bu::FString b( a ); 41 Bu::FString b( a );
42 unitTest( a.getStr() == b.getStr() ); 42 unitTest( a.getConstStr() == b.getConstStr() );
43 b += " guy"; 43 b += " guy";
44 unitTest( a.getStr() != b.getStr() ); 44 unitTest( a.getConstStr() != b.getConstStr() );
45 a = b; 45 a = b;
46 unitTest( a.getStr() == b.getStr() ); 46 unitTest( a.getConstStr() == b.getConstStr() );
47} 47}
48 48
49{%insert} 49{%insert}