diff options
author | Mike Buland <eichlan@xagasoft.com> | 2009-08-14 21:22:03 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2009-08-14 21:22:03 +0000 |
commit | f01674e99a467e9eb99323130a1e1add4c57eda2 (patch) | |
tree | 50bfa258b1c5761b2fbbac86d945d981669f27d4 /src | |
parent | 42f4f849c683bc30404727f4dccc9d3cfd030adf (diff) | |
download | libbu++-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')
-rw-r--r-- | src/fbasicstring.h | 718 | ||||
-rw-r--r-- | src/list.cpp | 1 | ||||
-rw-r--r-- | src/list.h | 373 | ||||
-rw-r--r-- | src/sharedcore.h | 48 | ||||
-rw-r--r-- | src/tests/sharedcore.cpp | 24 | ||||
-rw-r--r-- | src/tests/speed.cpp | 5 | ||||
-rw-r--r-- | src/unit/fstring.unit | 6 |
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 | ||
22 | namespace Bu | 23 | namespace 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 | ||
10 | template class Bu::List<int>; | ||
@@ -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 | ||
15 | namespace Bu | 16 | namespace 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 | ||
14 | namespace Bu | 13 | namespace 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> | |||
12 | public: | 12 | public: |
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 | ||
44 | int main() | 44 | int 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} |