diff options
| -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} |
