hash.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /* ----- hash.c ----- */
  2. typedef struct {
  3. hash_t hash;
  4. char* key;
  5. void* value;
  6. } hashbucket;
  7. typedef struct hashtable {
  8. int fill;
  9. int alloc;
  10. hashbucket* buckets;
  11. } hashtable;
  12. void hash_init(hashtable* ht, int alloc) {
  13. ht->fill = 0;
  14. ht->alloc = alloc ? alloc : 128;
  15. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  16. }
  17. hashtable* hash_new(int alloc) {
  18. hashtable* ht = malloc(sizeof(*ht));
  19. hash_init(ht, alloc);
  20. return ht;
  21. }
  22. int hash_find_bucket(hashtable* ht, hash_t hash, char* key) {
  23. int b = hash % ht->alloc;
  24. for(int i = 0; i < ht->alloc; i++) {
  25. // empty bucket
  26. if(ht->buckets[b].key == NULL) return b;
  27. // full bucket
  28. if(ht->buckets[b].hash == hash) {
  29. if(0 == strcmp(key, ht->buckets[b].key)) {
  30. return b;
  31. }
  32. }
  33. // probe forward on collisions
  34. b = (b + 1) % ht->alloc;
  35. }
  36. // should never reach here
  37. printf("oops. -1 bucket \n");
  38. return -1;
  39. }
  40. void hash_expand(hashtable* ht) {
  41. int old_alloc = ht->alloc;
  42. ht->alloc *= 2;
  43. hashbucket* old = ht->buckets;
  44. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  45. for(int i = 0, f = 0; i < old_alloc && f < ht->fill; i++) {
  46. if(!old[i].key) continue;
  47. int b = hash_find_bucket(ht, old[i].hash, old[i].key);
  48. ht->buckets[b] = old[i];
  49. f++;
  50. }
  51. free(old);
  52. }
  53. void hash_insert(hashtable* ht, char* key, void* value) {
  54. hash_t hash = strhash(key);
  55. int b = hash_find_bucket(ht, hash, key);
  56. if(!ht->buckets[b].key) {
  57. if(ht->fill > ht->alloc * .80) {
  58. hash_expand(ht);
  59. // the bucket location has changed
  60. b = hash_find_bucket(ht, hash, key);
  61. }
  62. ht->fill++;
  63. }
  64. ht->buckets[b].key = strcache(key);
  65. ht->buckets[b].hash = hash;
  66. ht->buckets[b].value = value;
  67. }
  68. void* hash_find(hashtable* ht, char* key) {
  69. hash_t hash = strhash(key);
  70. int b = hash_find_bucket(ht, hash, key);
  71. return ht->buckets[b].value;
  72. }
  73. /* -END- hash.c ----- */