diff options
Diffstat (limited to 'src/list.h')
-rw-r--r-- | src/list.h | 373 |
1 files changed, 209 insertions, 164 deletions
@@ -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; |