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