diff options
author | Mike Buland <eichlan@xagasoft.com> | 2010-10-14 23:26:25 +0000 |
---|---|---|
committer | Mike Buland <eichlan@xagasoft.com> | 2010-10-14 23:26:25 +0000 |
commit | 867dae89929a11a421ec21af71d494ad0ecc1963 (patch) | |
tree | 85d4330d5cdc0567194f1bfb2f9b1bda4e95b444 /src/heap.h | |
parent | 13fa07280dd9ed2c62ad2be0848f88b0d85fe322 (diff) | |
download | libbu++-867dae89929a11a421ec21af71d494ad0ecc1963.tar.gz libbu++-867dae89929a11a421ec21af71d494ad0ecc1963.tar.bz2 libbu++-867dae89929a11a421ec21af71d494ad0ecc1963.tar.xz libbu++-867dae89929a11a421ec21af71d494ad0ecc1963.zip |
SharedCore has more features now, which is cool, including a test to see if
another object of the parent type has the same core, and another to clone the
parent object. That one is pretty cool, it means you can now get a real copy
when you want to, great for multi-threaded stuff.
Also, two more classes are now SharedCore: Hash and Heap!
Diffstat (limited to 'src/heap.h')
-rw-r--r-- | src/heap.h | 298 |
1 files changed, 201 insertions, 97 deletions
@@ -13,76 +13,92 @@ | |||
13 | #include "bu/exceptionbase.h" | 13 | #include "bu/exceptionbase.h" |
14 | #include "bu/util.h" | 14 | #include "bu/util.h" |
15 | #include "bu/queue.h" | 15 | #include "bu/queue.h" |
16 | #include "bu/sharedcore.h" | ||
16 | 17 | ||
17 | namespace Bu | 18 | namespace Bu |
18 | { | 19 | { |
19 | subExceptionDecl( HeapException ); | 20 | subExceptionDecl( HeapException ); |
20 | 21 | ||
21 | /** | 22 | template<typename item, typename cmpfunc, typename itemalloc> |
22 | * A priority queue that allows for an unlimited number of priorities. All | 23 | class Heap; |
23 | * objects enqueued must support less-than-comparison. Then every time an | 24 | |
24 | * item is dequeued it is always the least item in the heap. The heap | 25 | template<typename item, typename cmpfunc, typename itemalloc> |
25 | * operates using a binary tree for storage, which allows most operations | 26 | class HeapCore |
26 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | ||
27 | * whereas peeking is constant time. | ||
28 | * | ||
29 | * This heap implementation allows iterating, however please note that any | ||
30 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
31 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
32 | * the items are not stored in memory in order, they are optomized into a | ||
33 | * tree. This means that the items will be in effectively random order | ||
34 | * while iterating through them, and the order cannot be trusted. Also, | ||
35 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
36 | * If you want to change the position of an item in the heap you will have | ||
37 | * to dequeue every item before it, dequeue that item, change it, and | ||
38 | * re-enqueue all of the items removed. | ||
39 | */ | ||
40 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
41 | class Heap : public Queue<item> | ||
42 | { | 27 | { |
43 | public: | 28 | friend class Heap<item, cmpfunc, itemalloc>; |
44 | Heap() : | 29 | friend class SharedCore< |
45 | iSize( 7 ), | 30 | Heap<item, cmpfunc, itemalloc>, HeapCore<item, cmpfunc, itemalloc> |
31 | >; | ||
32 | private: | ||
33 | HeapCore() : | ||
34 | iSize( 0 ), | ||
46 | iFill( 0 ), | 35 | iFill( 0 ), |
47 | aItem( ia.allocate( iSize ) ) | 36 | aItem( NULL ) |
48 | { | 37 | { |
49 | } | 38 | } |
50 | 39 | ||
51 | Heap( cmpfunc cmpin ) : | 40 | virtual ~HeapCore() |
52 | iSize( 7 ), | ||
53 | iFill( 0 ), | ||
54 | aItem( ia.allocate( iSize ) ), | ||
55 | cmp( cmpin ) | ||
56 | { | 41 | { |
42 | clear(); | ||
57 | } | 43 | } |
58 | 44 | ||
59 | Heap( int iInitialCapacity ) : | 45 | void init() |
60 | iSize( 0 ), | ||
61 | iFill( 0 ), | ||
62 | aItem( NULL ) | ||
63 | { | 46 | { |
64 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 47 | if( iSize > 0 ) |
48 | return; | ||
49 | |||
50 | iSize = 7; | ||
51 | iFill = 0; | ||
65 | aItem = ia.allocate( iSize ); | 52 | aItem = ia.allocate( iSize ); |
66 | } | 53 | } |
67 | 54 | ||
68 | Heap( cmpfunc cmpin, int iInitialCapacity ) : | 55 | void init( int iCap ) |
69 | iSize( 0 ), | ||
70 | iFill( 0 ), | ||
71 | aItem( NULL ), | ||
72 | cmp( cmpin ) | ||
73 | { | 56 | { |
74 | for( iSize = 1; iSize < iInitialCapacity; iSize=iSize*2+1 ) { } | 57 | if( iSize > 0 ) |
58 | return; | ||
59 | |||
60 | for( iSize = 1; iSize < iCap; iSize=iSize*2+1 ) { } | ||
61 | iFill = 0; | ||
75 | aItem = ia.allocate( iSize ); | 62 | aItem = ia.allocate( iSize ); |
76 | } | 63 | } |
77 | 64 | ||
78 | virtual ~Heap() | 65 | void clear() |
79 | { | 66 | { |
67 | if( iSize == 0 ) | ||
68 | return; | ||
69 | |||
80 | for( int j = 0; j < iFill; j++ ) | 70 | for( int j = 0; j < iFill; j++ ) |
81 | ia.destroy( &aItem[j] ); | 71 | ia.destroy( &aItem[j] ); |
82 | ia.deallocate( aItem, iSize ); | 72 | ia.deallocate( aItem, iSize ); |
83 | aItem = NULL; | 73 | aItem = NULL; |
74 | iSize = 0; | ||
75 | iFill = 0; | ||
84 | } | 76 | } |
77 | |||
78 | void upSize() | ||
79 | { | ||
80 | if( iSize == 0 ) | ||
81 | { | ||
82 | init(); | ||
83 | return; | ||
84 | } | ||
85 | 85 | ||
86 | item *aNewItems = ia.allocate( iSize*2+1 ); | ||
87 | // | ||
88 | // We cannot use a memcopy here because we don't know what kind | ||
89 | // of datastructures are being used, we have to copy them one at | ||
90 | // a time. | ||
91 | // | ||
92 | for( int j = 0; j < iFill; j++ ) | ||
93 | { | ||
94 | ia.construct( &aNewItems[j], aItem[j] ); | ||
95 | ia.destroy( &aItem[j] ); | ||
96 | } | ||
97 | ia.deallocate( aItem, iSize ); | ||
98 | aItem = aNewItems; | ||
99 | iSize = iSize*2+1; | ||
100 | } | ||
101 | |||
86 | virtual void enqueue( const item &it ) | 102 | virtual void enqueue( const item &it ) |
87 | { | 103 | { |
88 | item i = it; // TODO: This is a silly workaround, put the i item | 104 | item i = it; // TODO: This is a silly workaround, put the i item |
@@ -126,20 +142,6 @@ namespace Bu | |||
126 | iFill++; | 142 | iFill++; |
127 | } | 143 | } |
128 | 144 | ||
129 | virtual item &peek() | ||
130 | { | ||
131 | if( iFill == 0 ) | ||
132 | throw HeapException("Heap empty."); | ||
133 | return aItem[0]; | ||
134 | } | ||
135 | |||
136 | virtual const item &peek() const | ||
137 | { | ||
138 | if( iFill == 0 ) | ||
139 | throw HeapException("Heap empty."); | ||
140 | return aItem[0]; | ||
141 | } | ||
142 | |||
143 | virtual item dequeue() | 145 | virtual item dequeue() |
144 | { | 146 | { |
145 | if( iFill == 0 ) | 147 | if( iFill == 0 ) |
@@ -174,14 +176,117 @@ namespace Bu | |||
174 | return iRet; | 176 | return iRet; |
175 | } | 177 | } |
176 | 178 | ||
179 | private: | ||
180 | int iSize; | ||
181 | int iFill; | ||
182 | item *aItem; | ||
183 | cmpfunc cmp; | ||
184 | itemalloc ia; | ||
185 | }; | ||
186 | |||
187 | /** | ||
188 | * A priority queue that allows for an unlimited number of priorities. All | ||
189 | * objects enqueued must support less-than-comparison. Then every time an | ||
190 | * item is dequeued it is always the least item in the heap. The heap | ||
191 | * operates using a binary tree for storage, which allows most operations | ||
192 | * to be very fast. Enqueueing and dequeueing are both O(log(N)) operatoins | ||
193 | * whereas peeking is constant time. | ||
194 | * | ||
195 | * This heap implementation allows iterating, however please note that any | ||
196 | * enqueue or dequeue operation will invalidate the iterator and make it | ||
197 | * unusable (if it still works, you shouldn't trust the results). Also, | ||
198 | * the items are not stored in memory in order, they are optomized into a | ||
199 | * tree. This means that the items will be in effectively random order | ||
200 | * while iterating through them, and the order cannot be trusted. Also, | ||
201 | * modifying an item in the heap will not cause that item to be re-sorted. | ||
202 | * If you want to change the position of an item in the heap you will have | ||
203 | * to dequeue every item before it, dequeue that item, change it, and | ||
204 | * re-enqueue all of the items removed. | ||
205 | */ | ||
206 | template<typename item, typename cmpfunc=__basicLTCmp<item>, typename itemalloc=std::allocator<item> > | ||
207 | class Heap : public Queue<item>, public SharedCore< | ||
208 | Heap<item, cmpfunc, itemalloc>, | ||
209 | HeapCore<item, cmpfunc, itemalloc> | ||
210 | > | ||
211 | { | ||
212 | private: | ||
213 | typedef class Heap<item,cmpfunc,itemalloc> MyType; | ||
214 | typedef class HeapCore<item,cmpfunc,itemalloc> Core; | ||
215 | |||
216 | protected: | ||
217 | using SharedCore<MyType, Core>::core; | ||
218 | using SharedCore<MyType, Core>::_hardCopy; | ||
219 | using SharedCore<MyType, Core>::_resetCore; | ||
220 | using SharedCore<MyType, Core>::_allocateCore; | ||
221 | |||
222 | public: | ||
223 | Heap() | ||
224 | { | ||
225 | } | ||
226 | |||
227 | Heap( cmpfunc cmpin ) | ||
228 | { | ||
229 | core->cmp = cmpin; | ||
230 | } | ||
231 | |||
232 | Heap( int iInitialCapacity ) | ||
233 | { | ||
234 | core->init( iInitialCapacity ); | ||
235 | } | ||
236 | |||
237 | Heap( cmpfunc cmpin, int iInitialCapacity ) | ||
238 | { | ||
239 | core->cmp = cmpin; | ||
240 | core->init( iInitialCapacity ); | ||
241 | } | ||
242 | |||
243 | Heap( const MyType &rSrc ) : | ||
244 | SharedCore<MyType, Core>( rSrc ) | ||
245 | { | ||
246 | } | ||
247 | |||
248 | virtual ~Heap() | ||
249 | { | ||
250 | } | ||
251 | |||
252 | virtual void enqueue( const item &it ) | ||
253 | { | ||
254 | _hardCopy(); | ||
255 | |||
256 | core->enqueue( it ); | ||
257 | } | ||
258 | |||
259 | virtual item &peek() | ||
260 | { | ||
261 | _hardCopy(); | ||
262 | |||
263 | if( core->iFill == 0 ) | ||
264 | throw HeapException("Heap empty."); | ||
265 | return core->aItem[0]; | ||
266 | } | ||
267 | |||
268 | virtual const item &peek() const | ||
269 | { | ||
270 | if( core->iFill == 0 ) | ||
271 | throw HeapException("Heap empty."); | ||
272 | return core->aItem[0]; | ||
273 | } | ||
274 | |||
275 | virtual item dequeue() | ||
276 | { | ||
277 | _hardCopy(); | ||
278 | |||
279 | return core->dequeue(); | ||
280 | } | ||
281 | |||
177 | virtual bool isEmpty() const | 282 | virtual bool isEmpty() const |
178 | { | 283 | { |
179 | return (iFill==0); | 284 | return (core->iFill==0); |
180 | } | 285 | } |
181 | 286 | ||
182 | virtual int getSize() const | 287 | virtual int getSize() const |
183 | { | 288 | { |
184 | return iFill; | 289 | return core->iFill; |
185 | } | 290 | } |
186 | 291 | ||
187 | class iterator | 292 | class iterator |
@@ -201,7 +306,7 @@ namespace Bu | |||
201 | { | 306 | { |
202 | if( pHeap == NULL ) | 307 | if( pHeap == NULL ) |
203 | throw Bu::ExceptionBase("Iterator not initialized."); | 308 | throw Bu::ExceptionBase("Iterator not initialized."); |
204 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 309 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
205 | throw Bu::ExceptionBase("Iterator out of bounds."); | 310 | throw Bu::ExceptionBase("Iterator out of bounds."); |
206 | } | 311 | } |
207 | 312 | ||
@@ -230,12 +335,16 @@ namespace Bu | |||
230 | 335 | ||
231 | item &operator*() | 336 | item &operator*() |
232 | { | 337 | { |
233 | return pHeap->aItem[iIndex]; | 338 | pHeap->_hardCopy(); |
339 | |||
340 | return pHeap->core->aItem[iIndex]; | ||
234 | } | 341 | } |
235 | 342 | ||
236 | item *operator->() | 343 | item *operator->() |
237 | { | 344 | { |
238 | return &(pHeap->aItem[iIndex]); | 345 | pHeap->_hardCopy(); |
346 | |||
347 | return &(pHeap->core->aItem[iIndex]); | ||
239 | } | 348 | } |
240 | 349 | ||
241 | iterator &operator++() | 350 | iterator &operator++() |
@@ -260,7 +369,7 @@ namespace Bu | |||
260 | { | 369 | { |
261 | checkValid(); | 370 | checkValid(); |
262 | iIndex++; | 371 | iIndex++; |
263 | if( iIndex >= pHeap->iFill ) | 372 | if( iIndex >= pHeap->core->iFill ) |
264 | iIndex = -1; | 373 | iIndex = -1; |
265 | 374 | ||
266 | return *this; | 375 | return *this; |
@@ -279,7 +388,7 @@ namespace Bu | |||
279 | checkValid(); | 388 | checkValid(); |
280 | iterator ret( *this ); | 389 | iterator ret( *this ); |
281 | ret.iIndex += iDelta; | 390 | ret.iIndex += iDelta; |
282 | if( ret.iIndex >= pHeap->iFill ) | 391 | if( ret.iIndex >= pHeap->core->iFill ) |
283 | ret.iIndex = -1; | 392 | ret.iIndex = -1; |
284 | return ret; | 393 | return ret; |
285 | } | 394 | } |
@@ -294,12 +403,12 @@ namespace Bu | |||
294 | return ret; | 403 | return ret; |
295 | } | 404 | } |
296 | 405 | ||
297 | operator bool() | 406 | operator bool() const |
298 | { | 407 | { |
299 | return iIndex != -1; | 408 | return iIndex != -1; |
300 | } | 409 | } |
301 | 410 | ||
302 | bool isValid() | 411 | bool isValid() const |
303 | { | 412 | { |
304 | return iIndex != -1; | 413 | return iIndex != -1; |
305 | } | 414 | } |
@@ -328,7 +437,7 @@ namespace Bu | |||
328 | { | 437 | { |
329 | if( pHeap == NULL ) | 438 | if( pHeap == NULL ) |
330 | throw Bu::ExceptionBase("Iterator not initialized."); | 439 | throw Bu::ExceptionBase("Iterator not initialized."); |
331 | if( iIndex < 0 || iIndex >= pHeap->iFill ) | 440 | if( iIndex < 0 || iIndex >= pHeap->core->iFill ) |
332 | throw Bu::ExceptionBase("Iterator out of bounds."); | 441 | throw Bu::ExceptionBase("Iterator out of bounds."); |
333 | } | 442 | } |
334 | 443 | ||
@@ -363,19 +472,23 @@ namespace Bu | |||
363 | 472 | ||
364 | const item &operator*() | 473 | const item &operator*() |
365 | { | 474 | { |
366 | return pHeap->aItem[iIndex]; | 475 | pHeap->_hardCopy(); |
476 | |||
477 | return pHeap->core->aItem[iIndex]; | ||
367 | } | 478 | } |
368 | 479 | ||
369 | const item *operator->() | 480 | const item *operator->() |
370 | { | 481 | { |
371 | return &(pHeap->aItem[iIndex]); | 482 | pHeap->_hardCopy(); |
483 | |||
484 | return &(pHeap->core->aItem[iIndex]); | ||
372 | } | 485 | } |
373 | 486 | ||
374 | const_iterator &operator++() | 487 | const_iterator &operator++() |
375 | { | 488 | { |
376 | checkValid(); | 489 | checkValid(); |
377 | iIndex++; | 490 | iIndex++; |
378 | if( iIndex >= pHeap->iFill ) | 491 | if( iIndex >= pHeap->core->iFill ) |
379 | iIndex = -1; | 492 | iIndex = -1; |
380 | 493 | ||
381 | return *this; | 494 | return *this; |
@@ -393,7 +506,7 @@ namespace Bu | |||
393 | { | 506 | { |
394 | checkValid(); | 507 | checkValid(); |
395 | iIndex++; | 508 | iIndex++; |
396 | if( iIndex >= pHeap->iFill ) | 509 | if( iIndex >= pHeap->core->iFill ) |
397 | iIndex = -1; | 510 | iIndex = -1; |
398 | 511 | ||
399 | return *this; | 512 | return *this; |
@@ -427,12 +540,12 @@ namespace Bu | |||
427 | return ret; | 540 | return ret; |
428 | } | 541 | } |
429 | 542 | ||
430 | operator bool() | 543 | operator bool() const |
431 | { | 544 | { |
432 | return iIndex != -1; | 545 | return iIndex != -1; |
433 | } | 546 | } |
434 | 547 | ||
435 | bool isValid() | 548 | bool isValid() const |
436 | { | 549 | { |
437 | return iIndex != -1; | 550 | return iIndex != -1; |
438 | } | 551 | } |
@@ -452,14 +565,14 @@ namespace Bu | |||
452 | 565 | ||
453 | iterator begin() | 566 | iterator begin() |
454 | { | 567 | { |
455 | if( iFill == 0 ) | 568 | if( core->iFill == 0 ) |
456 | return end(); | 569 | return end(); |
457 | return iterator( this, 0 ); | 570 | return iterator( this, 0 ); |
458 | } | 571 | } |
459 | 572 | ||
460 | const_iterator begin() const | 573 | const_iterator begin() const |
461 | { | 574 | { |
462 | if( iFill == 0 ) | 575 | if( core->iFill == 0 ) |
463 | return end(); | 576 | return end(); |
464 | return const_iterator( this, 0 ); | 577 | return const_iterator( this, 0 ); |
465 | } | 578 | } |
@@ -475,31 +588,22 @@ namespace Bu | |||
475 | } | 588 | } |
476 | 589 | ||
477 | 590 | ||
478 | private: | 591 | protected: |
479 | void upSize() | 592 | virtual Core *_copyCore( Core *src ) |
480 | { | 593 | { |
481 | item *aNewItems = ia.allocate( iSize*2+1 ); | 594 | Core *pRet = _allocateCore(); |
482 | // | 595 | |
483 | // We cannot use a memcopy here because we don't know what kind | 596 | pRet->iSize = src->iSize; |
484 | // of datastructures are being used, we have to copy them one at | 597 | pRet->iFill = src->iFill; |
485 | // a time. | 598 | pRet->cmp = src->cmp; |
486 | // | 599 | pRet->aItem = pRet->ia.allocate( pRet->iSize ); |
487 | for( int j = 0; j < iFill; j++ ) | 600 | for( int j = 0; j < pRet->iFill; j++ ) |
488 | { | 601 | { |
489 | ia.construct( &aNewItems[j], aItem[j] ); | 602 | pRet->ia.construct( &pRet->aItem[j], src->aItem[j] ); |
490 | ia.destroy( &aItem[j] ); | ||
491 | } | 603 | } |
492 | ia.deallocate( aItem, iSize ); | ||
493 | aItem = aNewItems; | ||
494 | iSize = iSize*2+1; | ||
495 | } | ||
496 | 604 | ||
497 | private: | 605 | return pRet; |
498 | int iSize; | 606 | } |
499 | int iFill; | ||
500 | item *aItem; | ||
501 | cmpfunc cmp; | ||
502 | itemalloc ia; | ||
503 | }; | 607 | }; |
504 | }; | 608 | }; |
505 | 609 | ||