Grafalgo
Library of useful data structures and algorithms
/Users/jst/src/grafalgo/cpp/dataStructures/hash/HashSet.cpp
Go to the documentation of this file.
00001 
00009 #include "HashSet.h"
00010 
00011 namespace grafalgo {
00012 
00017 HashSet::HashSet(int n1) : Adt(n1) { makeSpace(n()); }
00018         
00020 HashSet::~HashSet() { freeSpace(); }
00021 
00025 void HashSet::makeSpace(int size) {
00026         for (nb = 1; BKT_SIZ*nb <= size; nb <<= 1) {}
00027         nb = max(nb,4);
00028         bktMsk = nb - 1;
00029         nn = 2*nb*BKT_SIZ+1;
00030         try {
00031                 bkt = new bkt_t[2*nb];
00032                 ex = new SetPair(n());
00033         } catch (std::bad_alloc e) {
00034                 stringstream ss;
00035                 ss << "HashSet::makeSpace: insufficient space for "
00036                    << size << " values";
00037                 string s = ss.str();
00038                 throw OutOfSpaceException(s);
00039         }
00040         clear();
00041 }
00042 
00044 void HashSet::freeSpace() { delete [] bkt; }
00045 
00049 void HashSet::resize(int size) {
00050         freeSpace();
00051         try { makeSpace(size); } catch(OutOfSpaceException e) {
00052                 string s; s = "HashSet::resize:" + e.toString(s);
00053                 throw OutOfSpaceException(s);
00054         }
00055 }
00056 
00062 void HashSet::expand(int size) {
00063         if (size <= n()) return;
00064         HashSet old(ex->getNumIn()); old.copyFrom(*this);
00065         resize(size); this->copyFrom(old);
00066 }
00067 
00069 void HashSet::clear() {
00070         while (first() != 0) remove(val(first()));
00071 }
00072 
00074 void HashSet::copyFrom(const HashSet& source) {
00075         if (&source == this) return;
00076         if (source.n() > n()) resize(source.n());
00077         else clear();
00078         for (index x = source.first(); x != 0; x = source.next(x)) 
00079                 insert(source.val(x));
00080 }
00081 
00092 uint32_t HashSet::hashit(int64_t val, int hf) const {
00093         const uint32_t A0 = 0xa96347c5;
00094         const uint32_t A1 = 0xe65ac2d3;
00095 
00096         uint32_t x, y; uint64_t z;
00097 
00098         x = (val >> 16) & 0xffff0000; x |= (val & 0xffff);
00099         y = (val >> 48) & 0xffff; y |= (val & 0xffff0000); 
00100         z = x ^ y;
00101         z *= (hf == 0 ? A0 : A1);
00102         return (z >> 16) & bktMsk;
00103 }
00104 
00109 index HashSet::getIndex(int64_t val) const {
00110         int i; uint32_t b;
00111 
00112         // check bucket in the first half of the bucket array
00113         b = hashit(val,0); int x = b*BKT_SIZ+1;
00114         for (i = 0; i < BKT_SIZ; i++) {
00115                 if (ex->isIn(x) && bkt[b][i] == val) return x;
00116                 x++;
00117         }
00118 
00119         // check bucket in the second half of the bucket array
00120         b = nb + hashit(val,1); x = b*BKT_SIZ+1;
00121         for (i = 0; i < BKT_SIZ; i++) {
00122                 if (ex->isIn(x) && bkt[b][i] == val) return x;
00123                 x++;
00124         }
00125         return 0;
00126 }
00127 
00133 index HashSet::insert(int64_t val) {
00134         int i, j0, j1, n0, n1;
00135         uint32_t b0, b1;
00136 
00137         // Count the number of unused items in each bucket
00138         // and find an unused item in each (if there is one)
00139         // quit early if we already have an entry for this val
00140         b0 = hashit(val,0);
00141         j0 = n0 = 0; int x = b0*BKT_SIZ+1;
00142         for (i = 0; i < BKT_SIZ; i++) {
00143                 if (ex->isOut(x)) { n0++; j0 = i; }
00144                 else if (bkt[b0][i] == val) return x;
00145                 x++;
00146         }
00147         b1 = nb + hashit(val,1);
00148         j1 = n1 = 0; x = b1*BKT_SIZ+1;
00149         for (i = 0; i < BKT_SIZ; i++) {
00150                 if (ex->isOut(x)) { n1++; j1 = i; }
00151                 else if (bkt[b1][i] == val) return x;
00152                 x++;
00153         }
00154         // if no unused entry in either bucket, give up.
00155         if (n0 + n1 == 0) return false;
00156 
00157         // store the value in least-loaded bucket
00158         if (n0 >= n1) {
00159                 bkt[b0][j0] = val; x = b0*BKT_SIZ+j0+1;
00160         } else {
00161                 bkt[b1][j1] = val; x = b1*BKT_SIZ+j1+1;
00162         }
00163         ex->swap(x);
00164         return x;
00165 }
00166 
00170 void HashSet::remove(int64_t val) {
00171         int i; uint32_t b;
00172 
00173         b = hashit(val,0); int x = b*BKT_SIZ+1;
00174         for (i = 0; i < BKT_SIZ; i++) {
00175                 if (ex->isIn(x) && bkt[b][i] == val) {
00176                         ex->swap(x); return;
00177                 }
00178                 x++;
00179         }
00180         b = nb + hashit(val,1); x = b*BKT_SIZ+1;
00181         for (i = 0; i < BKT_SIZ; i++) {
00182                 if (ex->isIn(x) && bkt[b][i] == val) {
00183                         ex->swap(x); return;
00184                 }
00185                 x++;
00186         }
00187 }
00188 
00193 string& HashSet::toString(string& s) const {
00194         stringstream ss;
00195         ss << "{";
00196         for (index x = first(); x != 0; x = next(x)) {
00197                 if (x != first()) ss << " ";
00198                 ss << bkt[(x-1)/BKT_SIZ][(x-1)%BKT_SIZ];
00199         }
00200         ss << "}";
00201         s = ss.str();
00202         return s;
00203 }
00204 
00205 } // ends namespace
 All Classes Files Functions Variables Typedefs Friends