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