diff options
Diffstat (limited to 'src/fbasicstring.h')
-rw-r--r-- | src/fbasicstring.h | 718 |
1 files changed, 372 insertions, 346 deletions
diff --git a/src/fbasicstring.h b/src/fbasicstring.h index 33a82cb..cf7a786 100644 --- a/src/fbasicstring.h +++ b/src/fbasicstring.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "bu/archival.h" | 18 | #include "bu/archival.h" |
19 | #include "bu/archive.h" | 19 | #include "bu/archive.h" |
20 | #include "bu/util.h" | 20 | #include "bu/util.h" |
21 | #include "bu/sharedcore.h" | ||
21 | 22 | ||
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 ) |