libStatGen Software
1
|
00001 /* 00002 * Copyright (C) 2010 Regents of the University of Michigan 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef __LONGHASH_H__ 00019 #define __LONGHASH_H__ 00020 00021 #include "Error.h" 00022 00023 #include <limits.h> 00024 00025 #ifdef UINT_MAX 00026 #define LH_NOTFOUND (UINT_MAX) 00027 #else 00028 #define LH_NOTFOUND 0xFFFFFFFF 00029 #endif 00030 00031 template <class ObjectT> class LongHash 00032 { 00033 protected: 00034 ObjectT * objects; 00035 long long * keys; 00036 bool * occupancy; 00037 unsigned int count, size; 00038 unsigned int mask; 00039 bool allowDuplicates; 00040 00041 public: 00042 LongHash(int startsize = 32) 00043 { 00044 count = 0; 00045 size = startsize; 00046 mask = startsize - 1; 00047 00048 // In this implementation, the size of hash tables must be a power of two 00049 if (startsize & mask) 00050 error("LongHash: Hash table size must be a power of two.\n"); 00051 00052 occupancy = new bool [size]; 00053 objects = new ObjectT [size]; 00054 keys = new long long [size]; 00055 00056 allowDuplicates = false; 00057 00058 for (unsigned int i = 0; i < size; i++) 00059 { 00060 occupancy[i] = false; 00061 } 00062 }; 00063 00064 ~LongHash() 00065 { 00066 delete [] occupancy; 00067 delete [] objects; 00068 delete [] keys; 00069 } 00070 00071 void Grow() 00072 { 00073 SetSize(size * 2); 00074 } 00075 void Shrink() 00076 { 00077 SetSize(size / 2); 00078 } 00079 00080 void SetSize(int newsize) 00081 { 00082 int newmask = newsize - 1; 00083 00084 bool * newoccupancy = new bool [newsize]; 00085 ObjectT * newobjects = new ObjectT [newsize]; 00086 long long * newkeys = new long long [newsize]; 00087 00088 for (int i = 0; i < newsize; i++) 00089 newoccupancy[i] = false; 00090 00091 if (count) 00092 for (unsigned int i = 0; i < size; i++) 00093 if (occupancy[i] != false) 00094 { 00095 long long key = keys[i]; 00096 unsigned int h = newmask & (unsigned int) key; 00097 00098 while (newoccupancy[h] == true && (newkeys[h] != key || allowDuplicates)) 00099 h = (h + 1) & newmask; 00100 00101 if (newoccupancy[h]) 00102 count--; 00103 00104 newkeys[h] = key; 00105 newobjects[h] = objects[i]; 00106 newoccupancy[h] = true; 00107 } 00108 00109 delete [] occupancy; 00110 delete [] objects; 00111 delete [] keys; 00112 00113 occupancy = newoccupancy; 00114 objects = newobjects; 00115 keys = newkeys; 00116 size = newsize; 00117 mask = newmask; 00118 } 00119 00120 void Clear() 00121 { 00122 count = 0; 00123 00124 if (size > 32) 00125 SetSize(32); 00126 00127 for (unsigned int i = 0; i < size; i++) 00128 occupancy[i] = false; 00129 } 00130 00131 int Capacity() const 00132 { 00133 return size; 00134 } 00135 int Entries() const 00136 { 00137 return count; 00138 } 00139 00140 ObjectT Object(int i) const 00141 { 00142 return objects[i]; 00143 } 00144 ObjectT & Object(int i) 00145 { 00146 return objects[i]; 00147 } 00148 00149 void SetObject(int i, ObjectT object) 00150 { 00151 objects[i] = object; 00152 } 00153 00154 unsigned int Add(long long key, ObjectT object) 00155 { 00156 if (count * 2 > size) 00157 Grow(); 00158 00159 unsigned int h = Iterate(key); 00160 00161 while (allowDuplicates && occupancy[h] && objects[h] != object) 00162 h = ReIterate(key, h); 00163 00164 if (!occupancy[h]) 00165 { 00166 occupancy[h] = true; 00167 keys[h] = key; 00168 count++; 00169 } 00170 00171 objects[h] = object; 00172 00173 return h; 00174 } 00175 00176 unsigned int Find(long long key) 00177 { 00178 unsigned int h = Iterate(key); 00179 00180 return occupancy[h] ? h : LH_NOTFOUND; 00181 } 00182 00183 unsigned int Rehash(long long key, unsigned int h) 00184 { 00185 h = ReIterate(key, h); 00186 00187 return occupancy[h] ? h : LH_NOTFOUND; 00188 } 00189 00190 LongHash & operator = (const LongHash & rhs); 00191 00192 ObjectT operator [](int i) const 00193 { 00194 return objects[i]; 00195 } 00196 ObjectT operator [](unsigned int i) const 00197 { 00198 return objects[i]; 00199 } 00200 00201 void Delete(unsigned int index) 00202 { 00203 if (index >= size || !occupancy[index]) 00204 return; 00205 00206 occupancy[index] = false; 00207 count--; 00208 00209 if (count * 8 < size && size > 32) 00210 Shrink(); 00211 else 00212 { 00213 // rehash the next entries until we find empty slot 00214 index = (index + 1) & mask; 00215 00216 while (occupancy[index]) 00217 { 00218 if ((keys[index] & mask) != index) 00219 { 00220 unsigned int h = Iterate(keys[index]); 00221 00222 while (occupancy[h] && objects[h] != objects[index]) 00223 h = ReIterate(keys[index], h); 00224 00225 if (h != (unsigned int) index) 00226 { 00227 keys[h] = keys[index]; 00228 occupancy[h] = true; 00229 objects[h] = objects[index]; 00230 00231 occupancy[index] = false; 00232 } 00233 } 00234 00235 index = (index + 1) & mask; 00236 } 00237 } 00238 } 00239 00240 00241 bool SlotInUse(int index) const 00242 { 00243 return occupancy[index] == true; 00244 } 00245 bool SlotInUse(unsigned int index) const 00246 { 00247 return occupancy[index] == true; 00248 } 00249 00250 // Accessor to get a key. 00251 long long GetKey(int index) const 00252 { 00253 return keys[index]; 00254 } 00255 00256 long long GetKey(const unsigned int index) const 00257 { 00258 return keys[index]; 00259 } 00260 00261 void SetAllowDuplicateKeys(bool toggle) 00262 { 00263 allowDuplicates = toggle; 00264 00265 if (count && !allowDuplicates) 00266 SetSize(size); 00267 } 00268 00269 private: 00270 unsigned int Iterate(long long key) const 00271 { 00272 unsigned int h = mask & (unsigned int) key; 00273 00274 while (occupancy[h] == true && keys[h] != key) 00275 h = (h + 1) & mask; 00276 00277 return h; 00278 } 00279 00280 unsigned int ReIterate(long long key, unsigned int h) const 00281 { 00282 h = (h + 1) & mask; 00283 00284 while (occupancy[h] == true && keys[h] != key) 00285 h = (h + 1) & mask; 00286 00287 return h; 00288 } 00289 }; 00290 00291 #endif