hash_table.c (4753B)
1 /* hash_table.c */ 2 #include <stdlib.h> 3 #include <string.h> 4 #include <stdio.h> 5 #include "hash_table.h" 6 7 /* Hash Table Data Structure */ 8 struct hash_table { 9 struct hash_table_entry **entries; 10 int size; 11 hash_table_cmp_fn cmp; 12 hash_table_hash_fn hash; 13 hash_table_dtor dtor; 14 }; 15 16 /* Hash Table Entry Data Structure */ 17 struct hash_table_entry { 18 void *key; 19 void *value; 20 struct hash_table_entry *next; 21 }; 22 23 24 hash_table_t *hash_table_create(int size, hash_table_cmp_fn cmp, hash_table_hash_fn hash, hash_table_dtor dtor) { 25 /* Allocate and Initialize Hash Table */ 26 hash_table_t *table = malloc(sizeof(struct hash_table)); 27 if (!table) { 28 fprintf(stderr, "Error: Out of memory, could not allocate hash table\n"); 29 exit(EXIT_FAILURE); 30 } 31 table->entries = calloc(size, sizeof(struct hash_table_entry *)); 32 if (!table->entries) { 33 fprintf(stderr, "Error: Out of memory, could not allocate hash table entries\n"); 34 free(table); 35 exit(EXIT_FAILURE); 36 } 37 table->size = size; 38 table->cmp = cmp; 39 table->hash = hash; 40 table->dtor = dtor; 41 42 return table; 43 } 44 45 void hash_table_destroy(hash_table_t *table) { 46 if (!table) return; 47 /* Destroy Entries */ 48 for (int i = 0; i < table->size; i++) { 49 struct hash_table_entry *entry = table->entries[i]; 50 while (entry) { 51 struct hash_table_entry *next = entry->next; 52 if (table->dtor) { 53 table->dtor(entry->key, 1); 54 table->dtor(entry->value, 0); 55 } 56 free(entry); 57 entry = next; 58 } 59 } 60 61 free(table->entries); 62 free(table); 63 } 64 65 void *hash_table_get(const hash_table_t *table, const void *key) { 66 if (!table || !key) return NULL; 67 /* Get Entry By Hash */ 68 unsigned int hash = table->hash(key) % table->size; 69 struct hash_table_entry *entry = table->entries[hash]; 70 71 /* Loop Through Entries and Return Value if Match */ 72 while (entry) { 73 if (table->cmp(entry->key, key) == 0) { 74 return entry->value; 75 } 76 entry = entry->next; 77 } 78 79 return NULL; 80 } 81 82 void hash_table_put(hash_table_t *table, void *key, void *value) { 83 if (!table || !key) return; 84 /* Get Entry By Hash */ 85 unsigned int hash = table->hash(key) % table->size; 86 struct hash_table_entry *entry = table->entries[hash]; 87 88 /* Loop Through Entries and Replace Value if Key Matches */ 89 while (entry) { 90 if (table->cmp(entry->key, key) == 0) { 91 if (table->dtor) table->dtor(entry->value, 0); 92 entry->value = value; 93 return; 94 } 95 entry = entry->next; 96 } 97 98 /* Allocate New Entry if No Match */ 99 struct hash_table_entry *new_entry = malloc(sizeof(struct hash_table_entry)); 100 if (!new_entry) { 101 fprintf(stderr, "Error: Out of memory, could not allocate hash table entry\n"); 102 exit(EXIT_FAILURE); 103 } 104 new_entry->key = key; 105 new_entry->value = value; 106 new_entry->next = table->entries[hash]; 107 table->entries[hash] = new_entry; 108 109 } 110 111 void hash_table_remove(hash_table_t *table, const void *key) { 112 if (!table || !key) return; 113 /* Get Entry By Hash */ 114 unsigned int hash = table->hash(key) % table->size; 115 struct hash_table_entry *entry = table->entries[hash]; 116 117 /* Loop Through Entries and Remove Entry if Key Matches */ 118 struct hash_table_entry *prev = NULL; 119 while (entry) { 120 if (table->cmp(entry->key, key) == 0) { 121 if (prev) 122 prev->next = entry->next; 123 else 124 table->entries[hash] = entry->next; 125 126 if (table->dtor) { 127 table->dtor(entry->key, 1); 128 table->dtor(entry->value, 0); 129 } 130 free(entry); 131 return; 132 } 133 prev = entry; 134 entry = entry->next; 135 } 136 137 } 138 139 #ifdef TEST_HASH_TABLE 140 #include <assert.h> 141 142 static int string_cmp(const void *key1, const void *key2) { 143 return strcmp((const char *)key1, (const char *)key2); 144 } 145 146 static unsigned int string_hash(const void *key) { 147 unsigned int hash = 5381; 148 const unsigned char *str = key; 149 int c; 150 151 while ((c = *str++)) 152 { 153 hash = ((hash << 5) + hash) + c; 154 } 155 156 return hash; 157 } 158 159 int main(void) { 160 hash_table_t *table = hash_table_create(16, string_cmp, string_hash, NULL); 161 assert(table != NULL); 162 163 hash_table_put(table, "foo", "bar"); 164 hash_table_put(table, "foo", "baz"); 165 assert(strcmp((const char *)hash_table_get(table, "foo"), "baz") == 0); 166 167 hash_table_remove(table, "foo"); 168 assert(hash_table_get(table, "foo") == NULL); 169 170 hash_table_destroy(table); 171 printf("All tests passed!\n"); 172 return 0; 173 } 174 #endif 175