00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 #include "hash.h"
00009 #include "../debug.h"
00010 #include "threads/malloc.h"
00011 
00012 #define list_elem_to_hash_elem(LIST_ELEM)                       \
00013         list_entry(LIST_ELEM, struct hash_elem, list_elem)
00014 
00015 static struct list *find_bucket (struct hash *, struct hash_elem *);
00016 static struct hash_elem *find_elem (struct hash *, struct list *,
00017                                     struct hash_elem *);
00018 static void insert_elem (struct hash *, struct list *, struct hash_elem *);
00019 static void remove_elem (struct hash *, struct hash_elem *);
00020 static void rehash (struct hash *);
00021 
00022 
00023 
00024 bool
00025 hash_init (struct hash *h,
00026            hash_hash_func *hash, hash_less_func *less, void *aux) 
00027 {
00028   h->elem_cnt = 0;
00029   h->bucket_cnt = 4;
00030   h->buckets = malloc (sizeof *h->buckets * h->bucket_cnt);
00031   h->hash = hash;
00032   h->less = less;
00033   h->aux = aux;
00034 
00035   if (h->buckets != NULL) 
00036     {
00037       hash_clear (h, NULL);
00038       return true;
00039     }
00040   else
00041     return false;
00042 }
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 void
00054 hash_clear (struct hash *h, hash_action_func *destructor) 
00055 {
00056   size_t i;
00057 
00058   for (i = 0; i < h->bucket_cnt; i++) 
00059     {
00060       struct list *bucket = &h->buckets[i];
00061 
00062       if (destructor != NULL) 
00063         while (!list_empty (bucket)) 
00064           {
00065             struct list_elem *list_elem = list_pop_front (bucket);
00066             struct hash_elem *hash_elem = list_elem_to_hash_elem (list_elem);
00067             destructor (hash_elem, h->aux);
00068           }
00069 
00070       list_init (bucket); 
00071     }    
00072 
00073   h->elem_cnt = 0;
00074 }
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 void
00087 hash_destroy (struct hash *h, hash_action_func *destructor) 
00088 {
00089   if (destructor != NULL)
00090     hash_clear (h, destructor);
00091   free (h->buckets);
00092 }
00093 
00094 
00095 
00096 
00097    
00098 struct hash_elem *
00099 hash_insert (struct hash *h, struct hash_elem *new)
00100 {
00101   struct list *bucket = find_bucket (h, new);
00102   struct hash_elem *old = find_elem (h, bucket, new);
00103 
00104   if (old == NULL) 
00105     insert_elem (h, bucket, new);
00106 
00107   rehash (h);
00108 
00109   return old; 
00110 }
00111 
00112 
00113 
00114 struct hash_elem *
00115 hash_replace (struct hash *h, struct hash_elem *new) 
00116 {
00117   struct list *bucket = find_bucket (h, new);
00118   struct hash_elem *old = find_elem (h, bucket, new);
00119 
00120   if (old != NULL)
00121     remove_elem (h, old);
00122   insert_elem (h, bucket, new);
00123 
00124   rehash (h);
00125 
00126   return old;
00127 }
00128 
00129 
00130 
00131 struct hash_elem *
00132 hash_find (struct hash *h, struct hash_elem *e) 
00133 {
00134   return find_elem (h, find_bucket (h, e), e);
00135 }
00136 
00137 
00138 
00139 
00140 
00141 
00142 
00143 
00144 struct hash_elem *
00145 hash_delete (struct hash *h, struct hash_elem *e)
00146 {
00147   struct hash_elem *found = find_elem (h, find_bucket (h, e), e);
00148   if (found != NULL) 
00149     {
00150       remove_elem (h, found);
00151       rehash (h); 
00152     }
00153   return found;
00154 }
00155 
00156 
00157 
00158 
00159 
00160 
00161 
00162 void
00163 hash_apply (struct hash *h, hash_action_func *action) 
00164 {
00165   size_t i;
00166   
00167   ASSERT (action != NULL);
00168 
00169   for (i = 0; i < h->bucket_cnt; i++) 
00170     {
00171       struct list *bucket = &h->buckets[i];
00172       struct list_elem *elem, *next;
00173 
00174       for (elem = list_begin (bucket); elem != list_end (bucket); elem = next) 
00175         {
00176           next = list_next (elem);
00177           action (list_elem_to_hash_elem (elem), h->aux);
00178         }
00179     }
00180 }
00181 
00182 
00183 
00184 
00185 
00186 
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194 
00195 
00196 
00197 
00198 
00199 void
00200 hash_first (struct hash_iterator *i, struct hash *h) 
00201 {
00202   ASSERT (i != NULL);
00203   ASSERT (h != NULL);
00204 
00205   i->hash = h;
00206   i->bucket = i->hash->buckets;
00207   i->elem = list_elem_to_hash_elem (list_head (i->bucket));
00208 }
00209 
00210 
00211 
00212 
00213 
00214 
00215 
00216 
00217 
00218 struct hash_elem *
00219 hash_next (struct hash_iterator *i)
00220 {
00221   ASSERT (i != NULL);
00222 
00223   i->elem = list_elem_to_hash_elem (list_next (&i->elem->list_elem));
00224   while (i->elem == list_elem_to_hash_elem (list_end (i->bucket)))
00225     {
00226       if (++i->bucket >= i->hash->buckets + i->hash->bucket_cnt)
00227         {
00228           i->elem = NULL;
00229           break;
00230         }
00231       i->elem = list_elem_to_hash_elem (list_begin (i->bucket));
00232     }
00233   
00234   return i->elem;
00235 }
00236 
00237 
00238 
00239 
00240 struct hash_elem *
00241 hash_cur (struct hash_iterator *i) 
00242 {
00243   return i->elem;
00244 }
00245 
00246 
00247 size_t
00248 hash_size (struct hash *h) 
00249 {
00250   return h->elem_cnt;
00251 }
00252 
00253 
00254 bool
00255 hash_empty (struct hash *h) 
00256 {
00257   return h->elem_cnt == 0;
00258 }
00259 
00260 
00261 #define FNV_32_PRIME 16777619u
00262 #define FNV_32_BASIS 2166136261u
00263 
00264 
00265 unsigned
00266 hash_bytes (const void *buf_, size_t size)
00267 {
00268   
00269   const unsigned char *buf = buf_;
00270   unsigned hash;
00271 
00272   ASSERT (buf != NULL);
00273 
00274   hash = FNV_32_BASIS;
00275   while (size-- > 0)
00276     hash = (hash * FNV_32_PRIME) ^ *buf++;
00277 
00278   return hash;
00279 } 
00280 
00281 
00282 unsigned
00283 hash_string (const char *s_) 
00284 {
00285   const unsigned char *s = (const unsigned char *) s_;
00286   unsigned hash;
00287 
00288   ASSERT (s != NULL);
00289 
00290   hash = FNV_32_BASIS;
00291   while (*s != '\0')
00292     hash = (hash * FNV_32_PRIME) ^ *s++;
00293 
00294   return hash;
00295 }
00296 
00297 
00298 unsigned
00299 hash_int (int i) 
00300 {
00301   return hash_bytes (&i, sizeof i);
00302 }
00303 
00304 
00305 static struct list *
00306 find_bucket (struct hash *h, struct hash_elem *e) 
00307 {
00308   size_t bucket_idx = h->hash (e, h->aux) & (h->bucket_cnt - 1);
00309   return &h->buckets[bucket_idx];
00310 }
00311 
00312 
00313 
00314 static struct hash_elem *
00315 find_elem (struct hash *h, struct list *bucket, struct hash_elem *e) 
00316 {
00317   struct list_elem *i;
00318 
00319   for (i = list_begin (bucket); i != list_end (bucket); i = list_next (i)) 
00320     {
00321       struct hash_elem *hi = list_elem_to_hash_elem (i);
00322       if (!h->less (hi, e, h->aux) && !h->less (e, hi, h->aux))
00323         return hi; 
00324     }
00325   return NULL;
00326 }
00327 
00328 
00329 static inline size_t
00330 turn_off_least_1bit (size_t x) 
00331 {
00332   return x & (x - 1);
00333 }
00334 
00335 
00336 static inline size_t
00337 is_power_of_2 (size_t x) 
00338 {
00339   return x != 0 && turn_off_least_1bit (x) == 0;
00340 }
00341 
00342 
00343 #define MIN_ELEMS_PER_BUCKET  1 
00344 #define BEST_ELEMS_PER_BUCKET 2 
00345 #define MAX_ELEMS_PER_BUCKET  4 
00346 
00347 
00348 
00349 
00350 
00351 static void
00352 rehash (struct hash *h) 
00353 {
00354   size_t old_bucket_cnt, new_bucket_cnt;
00355   struct list *new_buckets, *old_buckets;
00356   size_t i;
00357 
00358   ASSERT (h != NULL);
00359 
00360   
00361   old_buckets = h->buckets;
00362   old_bucket_cnt = h->bucket_cnt;
00363 
00364   
00365 
00366 
00367 
00368   new_bucket_cnt = h->elem_cnt / BEST_ELEMS_PER_BUCKET;
00369   if (new_bucket_cnt < 4)
00370     new_bucket_cnt = 4;
00371   while (!is_power_of_2 (new_bucket_cnt))
00372     new_bucket_cnt = turn_off_least_1bit (new_bucket_cnt);
00373 
00374   
00375   if (new_bucket_cnt == old_bucket_cnt)
00376     return;
00377 
00378   
00379   new_buckets = malloc (sizeof *new_buckets * new_bucket_cnt);
00380   if (new_buckets == NULL) 
00381     {
00382       
00383 
00384 
00385       return;
00386     }
00387   for (i = 0; i < new_bucket_cnt; i++) 
00388     list_init (&new_buckets[i]);
00389 
00390   
00391   h->buckets = new_buckets;
00392   h->bucket_cnt = new_bucket_cnt;
00393 
00394   
00395   for (i = 0; i < old_bucket_cnt; i++) 
00396     {
00397       struct list *old_bucket;
00398       struct list_elem *elem, *next;
00399 
00400       old_bucket = &old_buckets[i];
00401       for (elem = list_begin (old_bucket);
00402            elem != list_end (old_bucket); elem = next) 
00403         {
00404           struct list *new_bucket
00405             = find_bucket (h, list_elem_to_hash_elem (elem));
00406           next = list_next (elem);
00407           list_remove (elem);
00408           list_push_front (new_bucket, elem);
00409         }
00410     }
00411 
00412   free (old_buckets);
00413 }
00414 
00415 
00416 static void
00417 insert_elem (struct hash *h, struct list *bucket, struct hash_elem *e) 
00418 {
00419   h->elem_cnt++;
00420   list_push_front (bucket, &e->list_elem);
00421 }
00422 
00423 
00424 static void
00425 remove_elem (struct hash *h, struct hash_elem *e) 
00426 {
00427   h->elem_cnt--;
00428   list_remove (&e->list_elem);
00429 }
00430