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