Grafalgo
Library of useful data structures and algorithms
/Users/jst/src/grafalgo/cpp/dataStructures/hash/HashTbl.cpp
Go to the documentation of this file.
00001 
00009 #include "HashTbl.h"
00010 
00011 namespace grafalgo {
00012 
00016 HashTbl::HashTbl(int n1) : Adt(n1) { makeSpace(n()); }
00017         
00019 HashTbl::~HashTbl() { freeSpace(); }
00020 
00024 void HashTbl::makeSpace(int size) {
00025         if (size > MAXVAL) {
00026                 string s = "HashTbl::makeSpace: requested table size "
00027                            "exceeds limit";
00028                 throw IllegalArgumentException(s);
00029         }
00030         for (nb = 1; 8*nb <= size; nb <<= 1) {}
00031         nb = max(nb,4);
00032         bktMsk = nb - 1; valMsk = (8*nb) - 1; fpMsk = ~valMsk;
00033         try {
00034                 bkt = new bkt_t[2*nb]; keyVec = new uint64_t[size+1];
00035         } catch (std::bad_alloc e) {
00036                 stringstream ss;
00037                 ss << "HashTbl::makeSpace: insufficient space for "
00038                    << size << "index values";
00039                 string s = ss.str();
00040                 throw OutOfSpaceException(s);
00041         }
00042         nn = size; clear();
00043 }
00044 
00046 void HashTbl::freeSpace() { delete [] bkt; delete [] keyVec; }
00047 
00051 void HashTbl::resize(int size) {
00052         freeSpace();
00053         try { makeSpace(size); } catch(OutOfSpaceException e) {
00054                 string s; s = "HashTbl::resize:" + e.toString(s);
00055                 throw OutOfSpaceException(s);
00056         }
00057 }
00058 
00063 void HashTbl::expand(int size) {
00064         if (size <= n()) return;
00065         HashTbl old(this->n()); old.copyFrom(*this);
00066         resize(size); this->copyFrom(old);
00067 }
00068 
00070 void HashTbl::clear() {
00071         for (int i = 0; i < 2*nb; i++) {
00072                 for (int j = 0; j < BKT_SIZ; j++) bkt[i][j] = 0;
00073         }
00074         for (int i = 0; i < n(); i++) keyVec[i] = 0;
00075         siz = 0;
00076 }
00077 
00079 void HashTbl::copyFrom(const HashTbl& source) {
00080         if (&source == this) return;
00081         if (source.n() > n()) resize(source.n());
00082         else clear();
00083         for (int i = 0; i < source.n(); i++) insert(source.keyVec[i],i);
00084 }
00085 
00099 void HashTbl::hashit(uint64_t key, int hf, uint32_t& b, uint32_t& fp) const {
00100         const uint32_t A0 = 0xa96347c5;
00101         const uint32_t A1 = 0xe65ac2d3;
00102 
00103         uint32_t x, y; uint64_t z;
00104 
00105         x = (key >> 16) & 0xffff0000; x |= (key & 0xffff);
00106         y = (key >> 48) & 0xffff; y |= (key & 0xffff0000); 
00107         z = x ^ y;
00108         z *= (hf == 0 ? A0 : A1);
00109         b = (z >> 16) & bktMsk;
00110         fp  = (z >> 13) & fpMsk;
00111 }
00112 
00117 int HashTbl::lookup(uint64_t key) const {
00118         int i; uint32_t b, val, fp;
00119 
00120         // check bucket in the first half of the bucket array
00121         hashit(key,0,b,fp);
00122         for (i = 0; i < BKT_SIZ; i++) {
00123                 if ((bkt[b][i] & fpMsk) == fp) {
00124                         val = bkt[b][i] & valMsk;
00125                         if (keyVec[val] == key) return val;
00126                 }
00127         }
00128 
00129         // check bucket in the second half of the bucket array
00130         hashit(key,1,b,fp); b += nb;
00131         for (i = 0; i < BKT_SIZ; i++) {
00132                 if ((bkt[b][i] & fpMsk) == fp) {
00133                         val = bkt[b][i] & valMsk;
00134                         if (keyVec[val] == key) return val;
00135                 }
00136         }
00137         return 0;
00138 }
00139 
00146 bool HashTbl::insert(uint64_t key, index val) {
00147         int i, j0, j1, n0, n1;
00148         uint32_t b0, b1, fp0, fp1;
00149 
00150         if (val > n())  {
00151                 string s = "HashTbl::makeSpace: requested value exceeds "
00152                            "index range";
00153                 throw IllegalArgumentException(s);
00154         }
00155 
00156         // Count the number of unused items in each bucket
00157         // and find an unused item in each (if there is one)
00158         // quit early if we already have an entry for this key
00159         hashit(key,0,b0,fp0);
00160         j0 = n0 = 0;
00161         for (i = 0; i < BKT_SIZ; i++) {
00162                 if (bkt[b0][i] == 0) { n0++; j0 = i; }
00163                 else if ((bkt[b0][i] & fpMsk) == fp0) {
00164                         uint32_t oldval = bkt[b0][i] & valMsk;
00165                         if (keyVec[oldval] == key) {
00166                                 bkt[b0][i] = fp0 | (val & valMsk);
00167                                 keyVec[val] = key;
00168                                 return true;
00169                         }
00170                 }
00171         }
00172         hashit(key,1,b1,fp1); b1 += nb;
00173         j1 = n1 = 0;
00174         for (i = 0; i < BKT_SIZ; i++) {
00175                 if (bkt[b1][i] == 0) { n1++; j1 = i; }
00176                 else if ((bkt[b1][i] & fpMsk) == fp0) {
00177                         uint32_t oldval = bkt[b1][i] & valMsk;
00178                         if (keyVec[oldval] == key) {
00179                                 bkt[b1][i] = fp0 | (val & valMsk);
00180                                 keyVec[val] = key;
00181                                 return true;
00182                         }
00183                 }
00184         }
00185         // If no unused entry in either bucket, give up.
00186         if (n0 + n1 == 0) return false;
00187 
00188         // store the key value in keyVec and add entry in least-loaded bucket
00189         keyVec[val] = key;
00190         if (n0 >= n1) bkt[b0][j0] = fp0 | (val & valMsk);
00191         else bkt[b1][j1] = fp1 | (val & valMsk);
00192         siz++;
00193                 
00194         return true;
00195 }
00196 
00201 int HashTbl::remove(uint64_t key) {
00202         int i; uint32_t b, val, fp;
00203 
00204         hashit(key,0,b,fp);
00205         for (i = 0; i < BKT_SIZ; i++) {
00206                 if ((bkt[b][i] & fpMsk) == fp) {
00207                         val = bkt[b][i] & valMsk;
00208                         if (keyVec[val] == key) {
00209                                 bkt[b][i] = 0; { siz--; return val; }
00210                         }
00211                 }
00212         }
00213         hashit(key,1,b,fp); b += nb;
00214         for (i = 0; i < BKT_SIZ; i++) {
00215                 if ((bkt[b][i] & fpMsk) == fp) {
00216                         val = bkt[b][i] & valMsk;
00217                         if (keyVec[val] == key) {
00218                                 bkt[b][i] = 0; { siz--; return val; }
00219                         }
00220                 }
00221         }
00222         return 0;
00223 }
00224 
00229 string& HashTbl::toString(string& s) const {
00230         int i, j, shift; uint32_t vm, val, fp; uint32_t *bucket;
00231 
00232         // Determine amount to shift to right-justify fingerprints
00233         vm = valMsk; shift = 0; while (vm != 0) { vm >>= 1; shift++; }
00234 
00235         stringstream ss;
00236         for (i = 0; i < 2*nb; i++) {
00237                 bucket = &bkt[i][0];
00238                 for (j = 0; j < BKT_SIZ; j++) {
00239                         if (bucket[j] != 0) {
00240                                 ss << i << "," << j << ": ";
00241                                 val =  bucket[j] & valMsk;
00242                                 fp  = (bucket[j] &  fpMsk) >> shift;
00243                                 ss << keyVec[val] + " " << val + " "
00244                                    << fp + "\n";
00245                         }
00246                 }
00247         }
00248         s = ss.str();
00249         return s;
00250 }
00251 
00252 } // ends namespace
 All Classes Files Functions Variables Typedefs Friends