summaryrefslogtreecommitdiff
path: root/src/heap.h
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2010-10-14 23:26:25 +0000
committerMike Buland <eichlan@xagasoft.com>2010-10-14 23:26:25 +0000
commit867dae89929a11a421ec21af71d494ad0ecc1963 (patch)
tree85d4330d5cdc0567194f1bfb2f9b1bda4e95b444 /src/heap.h
parent13fa07280dd9ed2c62ad2be0848f88b0d85fe322 (diff)
downloadlibbu++-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.h298
1 files changed, 201 insertions, 97 deletions
diff --git a/src/heap.h b/src/heap.h
index 9df4121..1dac69b 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -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
17namespace Bu 18namespace 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