Advertisement
Guest User

Untitled

a guest
Dec 5th, 2019
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.65 KB | None | 0 0
  1. #ifndef HASHTABLE_H
  2. #define HASHTABLE_H
  3.  
  4. typedef struct {
  5.     void **table;
  6.     unsigned int n_items;
  7.     unsigned int n_buckets;
  8.     unsigned int next_resize;
  9. } Hashtable_Data_t;
  10.  
  11. typedef struct {
  12.     Hashtable_Data_t *data; // should not be stack allocated
  13.     unsigned int (*hashcode)(void *);
  14.     #ifndef NO_HASH_EQUALS
  15.     unsigned int (*equals)(void *, void *);
  16.     #endif
  17. } Hashtable_t;
  18.  
  19. // buckets must be > 3
  20. Hashtable_t *table_create(Hashtable_t *ht, unsigned int (*hashcode)(void *),
  21.     #ifndef NO_HASH_EQUALS
  22.     unsigned int (*equals)(void *, void *),
  23.     #endif
  24.     unsigned int initial_buckets);
  25.  
  26.  
  27. int table_insert(Hashtable_t *ht, void *item);
  28.  
  29. int table_insert_fast(Hashtable_t *ht, void *item);
  30.  
  31. int table_contains(Hashtable_t *ht, void *item);
  32.  
  33. int table_remove(Hashtable_t *ht, void *item);
  34.  
  35. void table_free(Hashtable_t *ht);
  36.  
  37. #endif /* HASHTABLE_H */
  38.  
  39. #include <stdlib.h>
  40. #include "hashtable.h"
  41.  
  42. static int rehash(Hashtable_t *);
  43. inline static void internal_table_insert(Hashtable_t *ht, Hashtable_Data_t *data, void *item);
  44. inline static unsigned int internal_hashpos(Hashtable_t *ht, Hashtable_Data_t *data, void *item);
  45.  
  46. Hashtable_t *table_create(Hashtable_t *ht, unsigned int (*hashcode)(void *),
  47.     #ifndef NO_HASH_EQUALS
  48.     unsigned int (*equals)(void *, void *),
  49.     #endif
  50.     unsigned int buckets) {
  51.     Hashtable_t *ht_local;
  52.    
  53.     if(ht == NULL) {
  54.         ht_local = (Hashtable_t *) malloc(sizeof(Hashtable_t));
  55.         if(ht_local == NULL)
  56.             return NULL;
  57.     } else {
  58.         ht_local = ht;
  59.     }
  60.    
  61.     ht_local->data = (Hashtable_Data_t *) malloc(sizeof(Hashtable_Data_t));
  62.    
  63.     if(ht_local->data == NULL) {
  64.         if(ht == NULL)
  65.             free(ht_local);
  66.        
  67.         return NULL;
  68.     }
  69.    
  70.     ht_local->data->table = calloc(buckets, sizeof(void *));
  71.    
  72.     if(ht_local->data->table == NULL) {
  73.         if(ht == NULL) {
  74.             free(ht_local->data);
  75.             free(ht_local);
  76.         }
  77.        
  78.         return NULL;
  79.     }
  80.     ht_local->hashcode = hashcode;
  81.     #ifndef NO_HASH_EQUALS
  82.     ht_local->equals = equals;
  83.     #endif
  84.    
  85.     ht_local->data->n_items = 0;
  86.     ht_local->data->n_buckets = buckets;
  87.     ht_local->data->next_resize = (buckets >> 1) + (buckets >> 2);
  88.    
  89.     return ht_local;
  90. }
  91.  
  92. // returns -1 on failure, 0 if no failure.
  93. static int rehash(Hashtable_t *ht) {
  94.     Hashtable_Data_t *new_data = (Hashtable_Data_t *) malloc(sizeof(Hashtable_Data_t));
  95.  
  96.     if(new_data == NULL)
  97.         return -1;
  98.    
  99.     new_data->n_buckets = ht->data->n_buckets << 1;
  100.     new_data->table = calloc(new_data->n_buckets, sizeof(void *));
  101.    
  102.     if(new_data->table == NULL) {
  103.         free(new_data);
  104.         return -1;
  105.     }
  106.    
  107.     // 1.5 of old data so 75% of new bucket size. (75% load factor)
  108.     new_data->next_resize = ht->data->n_buckets + (ht->data->n_buckets >> 1);
  109.    
  110.     unsigned int a;
  111.     for(a=0; a<ht->data->n_buckets; a++)
  112.         if(ht->data->table[a] != NULL)
  113.             internal_table_insert(ht, new_data, ht->data->table[a]);
  114.    
  115.     free(ht->data->table);
  116.     free(ht->data);
  117.     ht->data = new_data;
  118.    
  119.     return 0;
  120. }
  121.  
  122. inline static unsigned int internal_hashpos(Hashtable_t *ht, Hashtable_Data_t *data, void *item) {
  123.     return ht->hashcode(item)%data->n_buckets;
  124. }
  125.  
  126. // returns NULL for no entry, &item if item is in table, and table[a] ifndef NO_HASH_EQUALS && ht->equals returned 1
  127. inline static void *internal_table_nexthit(Hashtable_t *ht, void *item) {
  128.     unsigned int hashcode = internal_hashpos(ht, ht->data, item);
  129.    
  130.     unsigned int a, lim;
  131.    
  132.     a = hashcode;
  133.     lim = ht->data->n_buckets;
  134.     for(;;) {
  135.         if(ht->data->table[a] == NULL || ht->data->table[a] == item
  136.         #ifndef NO_HASH_EQUALS
  137.         || ht->equals(ht->data->table[a], item)
  138.         #endif
  139.             ) return ht->data->table[a];
  140.        
  141.         a++;
  142.         if(a == lim) {
  143.             if(lim != hashcode) {
  144.                 a = 0;
  145.                 lim = hashcode;
  146.             }/* else {
  147.                 return;
  148.                 // table will never be full, so returning here is unneccessary.
  149.             }*/
  150.         }
  151.     }
  152. }
  153.  
  154. // uses table Hashtable_t for function pointers.
  155. // optimized for just inserting, use internal_table_nexthit if
  156. // you want to see if table contains, and then insert.
  157. inline static void internal_table_insert(Hashtable_t *ht, Hashtable_Data_t *data, void *item) {
  158.     unsigned int hashcode = internal_hashpos(ht, data, item);
  159.    
  160.     unsigned int a, lim;
  161.    
  162.     a = hashcode;
  163.     lim = data->n_buckets;
  164.     for(;;) {
  165.         if(data->table[a] == NULL) {
  166.             data->table[a] = item;
  167.             return;
  168.         }
  169.        
  170.         a++;
  171.         if(a == lim) {
  172.             if(lim != hashcode) {
  173.                 a = 0;
  174.                 lim = hashcode;
  175.             }/* else {
  176.                 return;
  177.                 // table will never be full, so returning here is unneccessary.
  178.             }*/
  179.         }
  180.     }
  181. }
  182.  
  183. int table_insert(Hashtable_t *ht, void *item) {
  184.     unsigned int tmp = ht->data->n_items+1;
  185.     if(tmp > ht->data->next_resize)
  186.         if(rehash(ht) == -1) return -1;
  187.    
  188.     internal_table_insert(ht, ht->data, item);
  189.    
  190.     ht->data->n_items = tmp;
  191.     return 0;
  192. }
  193.  
  194. // up to caller to free table if not stack allocated
  195. void table_free(Hashtable_t *ht) {
  196.     free(ht->data->table);
  197.     free(ht->data);
  198. }
  199. #include <stdlib.h>
  200. #include <stdio.h>
  201. #include "hashtable.h"
  202. #define NULLCHK(ptr) if(ptr == NULL) memoryerror()
  203.  
  204. unsigned int hashcode(void *);
  205. unsigned int equals(void *, void *);
  206. void memoryerror(void);
  207. void disptable(Hashtable_t *);
  208.  
  209. int main(void) {
  210.     int items[] = {
  211.         5123,
  212.         1283,
  213.         1235,
  214.         634,
  215.         12356,
  216.         12356,
  217.         534,
  218.         654,
  219.     };
  220.     size_t itemsize = sizeof(items)/sizeof(items[0]);
  221.     Hashtable_t *ht = table_create(NULL, hashcode, equals, (itemsize << 1)-(itemsize >> 1));
  222.     NULLCHK(ht);
  223.    
  224.     unsigned int a;
  225.     for(a=0; a<itemsize; a++) {
  226.         if(table_insert(ht, items+a) == -1) memoryerror();
  227.     }
  228.    
  229.     disptable(ht);
  230. }
  231.  
  232. void disptable(Hashtable_t *ht) {
  233.     printf("items: %u\nbuckets: %u\n", ht->data->n_items, ht->data->n_buckets);
  234.     unsigned int a;
  235.     for(a=0; a<ht->data->n_buckets; a++) {
  236.         void *item = ht->data->table[a];
  237.         if(item != NULL) {
  238.             printf("[%d] %d\n", a, *((int *)item));
  239.         }
  240.     }
  241. }
  242.  
  243. void memoryerror() {
  244.     puts("Memory error.");
  245.     exit(1);
  246. }
  247.  
  248. unsigned int hashcode(void *item) {
  249.     return *((int *)item);
  250. }
  251.  
  252. unsigned int equals(void *item1, void *item2) {
  253.     return 0;
  254. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement