Grafalgo
Library of useful data structures and algorithms
|
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