00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef MT_HASHTABLE_H_
00033 #define MT_HASHTABLE_H_
00034
00035
00036 #define MT_HASHTABLE_PARTITION_BITS 6
00037 #define MT_HASHTABLE_PARTITIONS (1<<MT_HASHTABLE_PARTITION_BITS)
00038 #define MT_HASHTABLE_PARTITION_MASK (MT_HASHTABLE_PARTITIONS - 1)
00039 #define MT_HASHTABLE_MAX_CHAIN_AVG_LEN 4
00040 template<class key_t, class data_t> struct HashTableEntry
00041 {
00042 key_t key;
00043 data_t data;
00044 HashTableEntry *next;
00045
00046 static HashTableEntry *alloc()
00047 {
00048 return (HashTableEntry *)ats_malloc(sizeof(HashTableEntry));
00049 }
00050
00051 static void free(HashTableEntry * entry)
00052 {
00053 ats_free(entry);
00054 }
00055 };
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 template<class key_t, class data_t> class HashTableIteratorState {
00071 public:
00072 HashTableIteratorState():cur_buck(-1), ppcur(NULL) {
00073 }
00074
00075 int cur_buck;
00076 HashTableEntry<key_t, data_t> **ppcur;
00077 };
00078
00079 template<class key_t, class data_t> class IMTHashTable {
00080 public:
00081 IMTHashTable(int size, bool(*gc_func) (data_t) = NULL, void (*pre_gc_func) (void) = NULL) {
00082 m_gc_func = gc_func;
00083 m_pre_gc_func = pre_gc_func;
00084 bucket_num = size;
00085 cur_size = 0;
00086 buckets = new HashTableEntry<key_t, data_t> *[bucket_num];
00087 memset(buckets, 0, bucket_num * sizeof(HashTableEntry<key_t, data_t> *));
00088 }
00089 ~IMTHashTable() {
00090 reset();
00091 }
00092
00093 int getBucketNum()
00094 {
00095 return bucket_num;
00096 }
00097 int getCurSize()
00098 {
00099 return cur_size;
00100 }
00101
00102 int bucket_id(key_t key, int a_bucket_num)
00103 {
00104 return (int) (((key >> MT_HASHTABLE_PARTITION_BITS) ^ key) % a_bucket_num);
00105 }
00106
00107 int bucket_id(key_t key)
00108 {
00109 return bucket_id(key, bucket_num);
00110 }
00111
00112 void reset()
00113 {
00114 HashTableEntry<key_t, data_t> *tmp;
00115 for (int i = 0; i < bucket_num; i++) {
00116 tmp = buckets[i];
00117 while (tmp) {
00118 buckets[i] = tmp->next;
00119 HashTableEntry<key_t, data_t>::free(tmp);
00120 tmp = buckets[i];
00121 }
00122 }
00123 delete[]buckets;
00124 buckets = NULL;
00125 }
00126
00127 data_t insert_entry(key_t key, data_t data);
00128 data_t remove_entry(key_t key);
00129 data_t lookup_entry(key_t key);
00130
00131 data_t first_entry(int bucket_id, HashTableIteratorState<key_t, data_t> *s);
00132 static data_t next_entry(HashTableIteratorState<key_t, data_t> *s);
00133 static data_t cur_entry(HashTableIteratorState<key_t, data_t> *s);
00134 data_t remove_entry(HashTableIteratorState<key_t, data_t> *s);
00135
00136 void GC(void)
00137 {
00138 if (m_gc_func == NULL)
00139 return;
00140 if (m_pre_gc_func)
00141 m_pre_gc_func();
00142 for (int i = 0; i < bucket_num; i++) {
00143 HashTableEntry<key_t, data_t> *cur = buckets[i];
00144 HashTableEntry<key_t, data_t> *prev = NULL;
00145 HashTableEntry<key_t, data_t> *next = NULL;
00146 while (cur != NULL) {
00147 next = cur->next;
00148 if (m_gc_func(cur->data)) {
00149 if (prev != NULL)
00150 prev->next = next;
00151 else
00152 buckets[i] = next;
00153 delete cur;
00154 cur_size--;
00155 } else {
00156 prev = cur;
00157 }
00158 cur = next;
00159 }
00160 }
00161 }
00162
00163 void resize(int size)
00164 {
00165 int new_bucket_num = size;
00166 HashTableEntry<key_t, data_t> **new_buckets = new HashTableEntry<key_t, data_t> *[new_bucket_num];
00167 memset(new_buckets, 0, new_bucket_num * sizeof(HashTableEntry<key_t, data_t> *));
00168
00169 for (int i = 0; i < bucket_num; i++) {
00170 HashTableEntry<key_t, data_t> *cur = buckets[i];
00171 HashTableEntry<key_t, data_t> *next = NULL;
00172 while (cur != NULL) {
00173 next = cur->next;
00174 int new_id = bucket_id(cur->key, new_bucket_num);
00175 cur->next = new_buckets[new_id];
00176 new_buckets[new_id] = cur;
00177 cur = next;
00178 }
00179 buckets[i] = NULL;
00180 }
00181 delete[]buckets;
00182 buckets = new_buckets;
00183 bucket_num = new_bucket_num;
00184 }
00185
00186 private:
00187 HashTableEntry<key_t, data_t> **buckets;
00188 int cur_size;
00189 int bucket_num;
00190 bool(*m_gc_func) (data_t);
00191 void (*m_pre_gc_func) (void);
00192
00193 private:
00194 IMTHashTable();
00195 IMTHashTable(IMTHashTable &);
00196 };
00197
00198
00199
00200
00201
00202 template<class key_t, class data_t> inline data_t IMTHashTable<key_t, data_t>::insert_entry(key_t key, data_t data)
00203 {
00204 int id = bucket_id(key);
00205 HashTableEntry<key_t, data_t> *cur = buckets[id];
00206 while (cur != NULL && cur->key != key) {
00207 cur = cur->next;
00208 }
00209 if (cur != NULL) {
00210 if (data == cur->data)
00211 return (data_t) 0;
00212 else {
00213 data_t tmp = cur->data;
00214 cur->data = data;
00215
00216 return tmp;
00217 }
00218 }
00219
00220 HashTableEntry<key_t, data_t> *newEntry = HashTableEntry<key_t, data_t>::alloc();
00221 newEntry->key = key;
00222 newEntry->data = data;
00223 newEntry->next = buckets[id];
00224 buckets[id] = newEntry;
00225 cur_size++;
00226 if (cur_size / bucket_num > MT_HASHTABLE_MAX_CHAIN_AVG_LEN) {
00227 GC();
00228 if (cur_size / bucket_num > MT_HASHTABLE_MAX_CHAIN_AVG_LEN)
00229 resize(bucket_num * 2);
00230 }
00231 return (data_t) 0;
00232 }
00233
00234
00235 template<class key_t, class data_t> inline data_t IMTHashTable<key_t, data_t>::remove_entry(key_t key)
00236 {
00237 int id = bucket_id(key);
00238 data_t ret = (data_t) 0;
00239 HashTableEntry<key_t, data_t> *cur = buckets[id];
00240 HashTableEntry<key_t, data_t> *prev = NULL;
00241 while (cur != NULL && cur->key != key) {
00242 prev = cur;
00243 cur = cur->next;
00244 }
00245 if (cur != NULL) {
00246 if (prev != NULL)
00247 prev->next = cur->next;
00248 else
00249 buckets[id] = cur->next;
00250 ret = cur->data;
00251 HashTableEntry<key_t, data_t>::free(cur);
00252 cur_size--;
00253 }
00254
00255 return ret;
00256 }
00257
00258 template<class key_t, class data_t> inline data_t IMTHashTable<key_t, data_t>::lookup_entry(key_t key)
00259 {
00260 int id = bucket_id(key);
00261 data_t ret = (data_t) 0;
00262 HashTableEntry<key_t, data_t> *cur = buckets[id];
00263 while (cur != NULL && cur->key != key) {
00264 cur = cur->next;
00265 }
00266 if (cur != NULL) {
00267 ret = cur->data;
00268 }
00269 return ret;
00270 }
00271
00272
00273 template<class key_t, class data_t>
00274 inline data_t IMTHashTable<key_t, data_t>::first_entry(int bucket_id, HashTableIteratorState<key_t, data_t> *s)
00275 {
00276 s->cur_buck = bucket_id;
00277 s->ppcur = &(buckets[bucket_id]);
00278 if (*(s->ppcur) != NULL)
00279 return (*(s->ppcur))->data;
00280 return (data_t) 0;
00281 }
00282
00283 template<class key_t, class data_t>
00284 inline data_t IMTHashTable<key_t, data_t>::next_entry(HashTableIteratorState<key_t, data_t> *s)
00285 {
00286 if ((*(s->ppcur)) != NULL) {
00287 s->ppcur = &((*(s->ppcur))->next);
00288 if (*(s->ppcur) != NULL)
00289 return (*(s->ppcur))->data;
00290 }
00291 return (data_t) 0;
00292 }
00293
00294 template<class key_t, class data_t>
00295 inline data_t IMTHashTable<key_t, data_t>::cur_entry(HashTableIteratorState<key_t, data_t> *s)
00296 {
00297 if (*(s->ppcur) == NULL)
00298 return (data_t) 0;
00299 return (*(s->ppcur))->data;
00300 }
00301
00302 template<class key_t, class data_t>
00303 inline data_t IMTHashTable<key_t, data_t>::remove_entry(HashTableIteratorState<key_t, data_t> *s)
00304 {
00305 data_t data = (data_t) 0;
00306 HashTableEntry<key_t, data_t> *pEntry = *(s->ppcur);
00307 if (pEntry != NULL) {
00308 data = pEntry->data;
00309 (*(s->ppcur)) = pEntry->next;
00310 HashTableEntry<key_t, data_t>::free(pEntry);
00311 cur_size--;
00312 }
00313 return data;
00314 }
00315
00316 template<class key_t, class data_t> class MTHashTable {
00317 public:
00318 MTHashTable(int size, bool(*gc_func) (data_t) = NULL, void (*pre_gc_func) (void) = NULL) {
00319 for (int i = 0; i < MT_HASHTABLE_PARTITIONS; i++) {
00320 locks[i] = new_ProxyMutex();
00321 hashTables[i] = new IMTHashTable<key_t, data_t> (size, gc_func, pre_gc_func);
00322
00323
00324 }
00325
00326 }
00327 ~MTHashTable() {
00328 for (int i = 0; i < MT_HASHTABLE_PARTITIONS; i++) {
00329 locks[i] = NULL;
00330 delete hashTables[i];
00331 }
00332 }
00333 ProxyMutex *lock_for_key(key_t key)
00334 {
00335 return locks[part_num(key)];
00336 }
00337
00338 int getSize()
00339 {
00340 return MT_HASHTABLE_PARTITIONS;
00341 }
00342 int part_num(key_t key)
00343 {
00344 return (int) (key & MT_HASHTABLE_PARTITION_MASK);
00345 }
00346 data_t insert_entry(key_t key, data_t data)
00347 {
00348
00349 return hashTables[part_num(key)]->insert_entry(key, data);
00350 }
00351 data_t remove_entry(key_t key)
00352 {
00353
00354 return hashTables[part_num(key)]->remove_entry(key);
00355 }
00356 data_t lookup_entry(key_t key)
00357 {
00358 return hashTables[part_num(key)]->lookup_entry(key);
00359 }
00360
00361 data_t first_entry(int part_id, HashTableIteratorState<key_t, data_t> *s)
00362 {
00363 data_t ret = (data_t) 0;
00364 for (int i = 0; i < hashTables[part_id]->getBucketNum(); i++) {
00365 ret = hashTables[part_id]->first_entry(i, s);
00366 if (ret != (data_t) 0)
00367 return ret;
00368 }
00369 return (data_t) 0;
00370 }
00371
00372 data_t cur_entry(int part_id, HashTableIteratorState<key_t, data_t> *s)
00373 {
00374 data_t data = IMTHashTable<key_t, data_t>::cur_entry(s);
00375 if (!data)
00376 data = next_entry(part_id, s);
00377 return data;
00378 };
00379 data_t next_entry(int part_id, HashTableIteratorState<key_t, data_t> *s)
00380 {
00381 data_t ret = IMTHashTable<key_t, data_t>::next_entry(s);
00382 if (ret != (data_t) 0)
00383 return ret;
00384 for (int i = s->cur_buck + 1; i < hashTables[part_id]->getBucketNum(); i++) {
00385 ret = hashTables[part_id]->first_entry(i, s);
00386 if (ret != (data_t) 0)
00387 return ret;
00388 }
00389 return (data_t) 0;
00390 }
00391 data_t remove_entry(int part_id, HashTableIteratorState<key_t, data_t> *s)
00392 {
00393
00394 return hashTables[part_id]->remove_entry(s);
00395 }
00396
00397 private:
00398 IMTHashTable<key_t, data_t> *hashTables[MT_HASHTABLE_PARTITIONS];
00399 Ptr<ProxyMutex> locks[MT_HASHTABLE_PARTITIONS];
00400
00401
00402
00403 };
00404
00405 #endif