bluehorizons

Untitled

Jun 28th, 2026
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.55 KB | None | 0 0
  1. #ifndef HASH_TABLE_H
  2. #define HASH_TABLE_H
  3.  
  4. #include <stdbool.h>
  5. #include <stdint.h>
  6. #include <stddef.h>
  7.  
  8. struct allocator_t {
  9.     void* (*malloc)(size_t);
  10.     void* (*calloc)(size_t,size_t);
  11.     void* (*realloc)(void*,size_t);
  12.     void  (*free)(void*);
  13. };
  14.  
  15. struct hash_bucket_t {
  16.     bool owns_key;
  17.     void (*free_key)(void*); // This can be NULL if the key is a scalar type :D
  18.     bool owns_value;
  19.     void (*free_value)(void*);
  20.     uintptr_t key;
  21.     void* value;
  22.     struct hash_bucket_t* next; // Links directly to next bucket there
  23. };
  24.  
  25. struct hash_table_t {
  26.     unsigned int HASH_MODULUS; // DON'T CHANGE THIS
  27.     struct hash_bucket_t *buckets;
  28.     struct allocator_t allocator; // SHOULD NEVER CHANGE
  29.     unsigned int (*hash_function)(uintptr_t); // THIS IS UNCHANGEABLE
  30.     bool (*equals_function)(uintptr_t,uintptr_t); // DO NOT CHANGE.
  31. };
  32.  
  33. struct optional_t {
  34.     bool is_present;
  35.     void* value;
  36. };
  37.  
  38. struct hash_table_mem_info_t {
  39.     bool passes_ownership;
  40.     struct allocator_t allocator;
  41. };
  42.  
  43. #define HASH_LIB_HASH_VALIDATOR(one) {if (one == 0) return 0;}
  44. #define HASH_LIB_EQUALS_VALIDATOR(one, two) {if (one == two) return true; if (one == 0 || two == 0) return false;}
  45.  
  46. struct hash_table_t create_hash_table(unsigned int modulus, struct allocator_t allocator, unsigned int (*hash_function)(uintptr_t), bool (*equals_function)(uintptr_t,uintptr_t));
  47.  
  48. struct optional_t get_from_hash_table(struct hash_table_t table, uintptr_t key);
  49.  
  50. void put_in_hash_table(struct hash_table_t table, uintptr_t key, void* value, struct hash_table_mem_info_t key_info, struct hash_table_mem_info_t value_info);
  51.  
  52. struct optional_t remove_from_hash_table(struct hash_table_t table, uintptr_t key, bool free_if_possible);
  53.  
  54. void free_hash_table(struct hash_table_t table); // PLEASE call after
  55.  
  56. #endif
  57. #include <stdlib.h>
  58.  
  59. struct hash_table_t create_hash_table(unsigned int modulus, struct allocator_t allocator, unsigned int (*hash_function)(uintptr_t), bool (*equals_function)(uintptr_t,uintptr_t)) {
  60.     if (!allocator.calloc) {
  61.         allocator.calloc = calloc;
  62.     }
  63.     if (!allocator.free) {
  64.         allocator.free = free; // Setting default values
  65.     }
  66.     struct hash_bucket_t *buckets = (struct hash_bucket_t*) allocator.calloc(modulus, sizeof(struct hash_bucket_t));
  67.    
  68.     return (struct hash_table_t){modulus, buckets, allocator, hash_function, equals_function};
  69. }
  70.  
  71. struct optional_t get_from_hash_table(struct hash_table_t table, uintptr_t key) {
  72.     struct optional_t result = { false, NULL };
  73.  
  74.     unsigned int hash = table.hash_function(key);
  75.     unsigned int hash0 = hash % table.HASH_MODULUS;
  76.  
  77.     struct hash_bucket_t bucket = table.buckets[hash0];
  78.     goto into_loop1;
  79.  
  80.     do {
  81.         bucket = *bucket.next;
  82. into_loop1:
  83.         if (bucket.key == key || table.equals_function(key, bucket.key)) {
  84.             result.is_present = true;
  85.             result.value = bucket.value;
  86.             break;
  87.         }
  88.     } while (bucket.next != NULL);
  89.  
  90.     return result;
  91. }
  92.  
  93. void put_in_hash_table(struct hash_table_t table, uintptr_t key, void* value, struct hash_table_mem_info_t key_info, struct hash_table_mem_info_t value_info) {
  94.     unsigned int hash = table.hash_function(key);
  95.     unsigned int hash0 = hash % table.HASH_MODULUS;
  96.  
  97.     struct hash_bucket_t bucket = table.buckets[hash0];
  98.     goto into_loop2;
  99.  
  100.     do {
  101.         bucket = *bucket.next;
  102. into_loop2:
  103.         if (bucket.key == key || table.equals_function(key, bucket.key)) {
  104.             if (bucket.owns_key) {
  105.                 bucket.free_key((void*) bucket.key);
  106.             }
  107.             bucket.owns_key = key_info.passes_ownership;
  108.             bucket.free_key = key_info.allocator.free;
  109.             bucket.key = key;
  110.             if (bucket.owns_value) {
  111.                 bucket.free_value(bucket.value);
  112.             }
  113.             bucket.owns_value = value_info.passes_ownership;
  114.             bucket.free_value = value_info.allocator.free;
  115.             bucket.value = value;
  116.             return;
  117.         }
  118.     } while (bucket.next != NULL);
  119.    
  120.     // Program only lands here if it hasn't found anything.
  121.     struct hash_bucket_t* new_bucket = table.allocator.malloc(sizeof(struct hash_bucket_t));
  122.     new_bucket->owns_key = key_info.passes_ownership;
  123.     new_bucket->free_key = key_info.allocator.free;
  124.     new_bucket->owns_value = value_info.passes_ownership;
  125.     new_bucket->free_value = value_info.allocator.free;
  126.     new_bucket->key = key;
  127.     new_bucket->value = value;
  128.     new_bucket->next = NULL;
  129.    
  130.     bucket.next = new_bucket;
  131.  
  132.     return;
  133. } // TODO
  134.  
  135. struct optional_t remove_from_hash_table(struct hash_table_t table, uintptr_t key, bool free_if_possible) {
  136.     struct optional_t result = { false, NULL };
  137.  
  138.     unsigned int hash = table.hash_function(key);
  139.     unsigned int hash0 = hash % table.HASH_MODULUS;
  140.  
  141.     struct hash_bucket_t* bucket = table.buckets + hash0;
  142.  
  143.     struct hash_bucket_t* old_bucket = NULL;
  144.     goto into_loop3;
  145.  
  146.     do {
  147.         old_bucket = bucket;
  148.         bucket = bucket->next;
  149.         // Here we need to store the bucket above
  150. into_loop3:
  151.         if (bucket->key == key || table.equals_function(key, bucket->key)) {
  152.             result.is_present = true;
  153.             result.value = bucket->value;
  154.             break;
  155.         }
  156.     } while (bucket->next != NULL);
  157.     if (result.is_present = false) {
  158.         goto removal_ending; // Yee
  159.     }
  160.     // Cut out bucket and then free contents if possible
  161.     if (bucket->owns_key) {
  162.         bucket->free_key((void *)bucket->key);
  163.     }
  164.     if (bucket->owns_value) {
  165.         bucket->free_value(bucket->value);
  166.     }
  167.     if (old_bucket == NULL) {
  168.         goto removal_ending;
  169.     }
  170.     old_bucket->next = bucket->next;
  171.     table.allocator.free(bucket);
  172.  
  173. removal_ending:
  174.     return result;
  175. }
  176.  
  177. static void recursively_free(struct hash_bucket_t bucket, struct allocator_t allocator) {
  178.  
  179. }
  180.  
  181. void free_hash_table(struct hash_table_t table) {
  182.     for (int i = 0; i < table.HASH_MODULUS; i++) {
  183.         recursively_free(table.buckets[i], table.allocator);
  184.     }
  185. }
Advertisement
Add Comment
Please, Sign In to add comment