BucketPQ.h

Go to the documentation of this file.
00001 #ifndef ExponentialBuckets_HEADER
00002 #define ExponentialBuckets_HEADER
00003 
00004 #ifdef HAVE_CONFIG_H
00005 #  include <config.h>
00006 #endif
00007 
00008 #include <math.h>
00009 #include "SmallList.h"
00010 
00011 #if 0
00012 #define dprintf(...) printf(__VA_ARGS__);
00013 #else
00014 #define dprintf(...)
00015 #endif
00016 
00017 namespace hudson {
00018 
00037 template <class Item>
00038 class BucketPQ : public SmallMemoryItem< BucketPQ<Item> > {
00039 
00040   typedef SmallList<Item> Bucket;
00041 
00042   Bucket *buckets_;
00043   unsigned nbuckets_;
00044   int base_;
00045 
00046   // Mutable: To get the runtimes, we need to update the finger even in const
00047   // functions.
00048   mutable unsigned finger_;
00049 
00050   void find_non_empty_bucket() const {
00051     while(finger_ != nbuckets_ && buckets_[finger_].empty()) {
00052       finger_++;
00053     }
00054   }
00055 
00065   void expand_range(int key, bool less_than_base) {
00066     int min, max; // min and max non-empty value after the current insertion
00067 
00068     // If we're expanding downward, then 'key' is the minimum value after
00069     // inserting; compute the max.  Otherwise, 'key' is the max and we
00070     // compute the min.  If the list is empty, then both should be equal
00071     // to 'key'.
00072     min = max = key;
00073     if (less_than_base) {
00074       for(int i = nbuckets_ - 1; i >= 0; --i) {
00075         if (!buckets_[i].empty()) { max = base_ + i; break; }
00076       }
00077     } else {
00078       for(unsigned i = 0; i < nbuckets_; ++i) {
00079         if (!buckets_[i].empty()) { min = base_ + i; break; }
00080       }
00081     }
00082     assert(max >= min);
00083     unsigned new_range = max - min + 1;
00084     dprintf("Current base %d, nbuckets %u, key %d\n", base_, nbuckets_, key);
00085     dprintf("New range: %u (from %d to %d)\n", new_range, min, max);
00086 
00087     if (new_range == 1) { // i.e. queue currently empty
00088       delete [] buckets_;
00089       nbuckets_ = 1;
00090       buckets_ = new Bucket[1];
00091       base_ = key;
00092       finger_ = 0;
00093     } else {
00094       // double the range we need.  TODO: reuse buckets_ if possible?
00095       new_range *= 2;
00096       int new_base = ((max + min) - int(new_range)) / 2;
00097       dprintf(" grow: %u base %d\n", new_range, new_base);
00098       assert(min >= new_base);
00099       assert(unsigned(max - new_base) < new_range);
00100 
00101       // Create the new buckets, copying in from the old.
00102       Bucket *new_buckets = new Bucket[new_range];
00103       int copy_begin = less_than_base ? base_ : min;
00104       int copy_end = less_than_base ? (max+1) : (base_ + nbuckets_);
00105       dprintf(" copying from %d to %d (%u to %u)\n",
00106           copy_begin, copy_end, copy_begin - base_, copy_end - base_);
00107       for(int value = copy_begin; value < copy_end; ++value) {
00108         unsigned old_i = value - base_;
00109         unsigned new_i = value - new_base;
00110         assert(old_i < nbuckets_);
00111         assert(new_i < new_range);
00112         buckets_[old_i].swap(new_buckets[new_i]);
00113       }
00114       delete [] buckets_;
00115 
00116       // Set the new fields.
00117       buckets_ = new_buckets;
00118       nbuckets_ = new_range;
00119       base_ = new_base;
00120       finger_ = getIndex(min);
00121     }
00122   }
00123 
00127   unsigned getIndex(int key) const {
00128     assert(key >= base_);
00129     return key - base_;
00130   }
00131 
00132   public:
00133   BucketPQ() {
00134     buckets_ = NULL;
00135     nbuckets_ = 0;
00136     base_ = 0;
00137     finger_ = 0;
00138   }
00139 
00140   bool empty() const {
00141     find_non_empty_bucket();
00142     return finger_ == nbuckets_;
00143   }
00144 
00145   void push(int key, const Item& item) {
00146     if (buckets_ == NULL) {
00147       buckets_ = new Bucket[1];
00148       nbuckets_ = 1;
00149       base_ = key;
00150       finger_ = 0;
00151     } else if (key < base_) {
00152       expand_range(key, true);
00153     } else if ( getIndex(key) >= nbuckets_) {
00154       expand_range(key, false);
00155     }
00156 
00157     unsigned index = getIndex(key);
00158     dprintf("%d, %d, %u, %u\n", base_, key, index, nbuckets_);
00159     assert(index < nbuckets_);
00160     buckets_[index].push_front(item);
00161     if (index < finger_) {
00162       finger_ = index;
00163     }
00164   }
00165 
00166   Item& top() {
00167     find_non_empty_bucket();
00168     assert(finger_ != nbuckets_);
00169     return buckets_[finger_].front();
00170   }
00171 
00172   const Item& top() const {
00173     find_non_empty_bucket();
00174     assert(finger_ != nbuckets_);
00175     return buckets_[finger_].front();
00176   }
00177 
00178   void pop() {
00179     find_non_empty_bucket();
00180     assert(finger_ != nbuckets_);
00181     buckets_[finger_].pop_front();
00182   }
00183 
00186 };
00187 
00195 template <class Item>
00196 class BucketDoublePQ : public SmallMemoryItem< BucketDoublePQ<Item> > {
00197   BucketPQ<Item> pq_;
00198 
00199   public:
00200   bool empty() const { return pq_.empty(); }
00201   void push(double key, const Item& item) {
00202     assert(key > 0.0);
00203     pq_.push(bithacks::log2_norm(key), item);
00204   }
00205   Item& top() { return pq_.top(); }
00206   const Item& top() const { return pq_.top(); }
00207   void pop() { return pq_.pop(); }
00208 };
00209 
00210 }
00211 
00212 #undef dprintf
00213 
00214 #endif

Generated on Thu Mar 27 19:04:14 2008 by  doxygen 1.4.6