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
00047
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;
00067
00068
00069
00070
00071
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) {
00088 delete [] buckets_;
00089 nbuckets_ = 1;
00090 buckets_ = new Bucket[1];
00091 base_ = key;
00092 finger_ = 0;
00093 } else {
00094
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
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
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