htable.c (4220B)
1 /* 2 * This work is dedicated to the public domain. 3 * See COPYING file for more information. 4 */ 5 6 #include <stdlib.h> 7 #include <stdio.h> 8 9 #include "htable.h" 10 11 /* 12 * Destroy the hash table and, if the free_key_val flag is true, free the keys and values. 13 */ 14 static void 15 destroy_and_free(struct htable *ht, int free_key_val) 16 { 17 unsigned int i; 18 struct htnode *n, *tmp; 19 20 for (i = 0; i < ht->cap; i++) { 21 for (n = ht->nodes[i]; n != NULL;) { 22 if (free_key_val) { 23 ht->key_free(n->key); 24 ht->val_free(n->val); 25 } 26 tmp = n; 27 n = n->next; 28 free(tmp); 29 } 30 } 31 free(ht->nodes); 32 free(ht); 33 } 34 35 /* 36 * Insert a new node or, if the replace flag is true, replace the value of an existing node. 37 */ 38 static int 39 insert_or_replace_val(struct htable *ht, void *key, void *val, int replace) 40 { 41 unsigned int i; 42 struct htnode *n, *ln; /* current and last node */ 43 44 i = ht->hash(key, ht->cap); 45 ln = NULL; 46 for (n = ht->nodes[i]; n != NULL; n = n->next) { 47 /* if key already exist */ 48 if (ht->key_cmp(key, n->key) == 0) { 49 if (replace) { 50 ht->val_free(n->val); 51 n->val = val; 52 return 0; 53 } else { 54 return -1; 55 } 56 } 57 ln = n; 58 } 59 60 if (replace) /* failed to replace */ 61 return -1; 62 63 if ((n = malloc(sizeof(struct htnode))) == NULL) { 64 perror("error: malloc"); 65 return -1; 66 } 67 n->key = key; 68 n->val = val; 69 n->next = NULL; 70 /* link to the last node */ 71 if (ln == NULL) 72 ht->nodes[i] = n; 73 else 74 ln->next = n; 75 ht->len++; 76 return 0; 77 } 78 79 /* 80 * Remove a node or, if the replace flag is true, change the key of the node. 81 */ 82 static int 83 remove_or_replace_key(struct htable *ht, void *key, int replace, void *newkey) 84 { 85 unsigned int i; 86 struct htnode *n, *ln; /* current and last node */ 87 88 i = ht->hash(key, ht->cap); 89 ln = NULL; 90 for (n = ht->nodes[i]; n != NULL; n = n->next) { 91 if (ht->key_cmp(key, n->key) == 0) { 92 ht->key_free(n->key); 93 if (!replace) { 94 ht->val_free(n->val); 95 } else { 96 if (htinsert(ht, newkey, n->val) == -1) 97 return -1; 98 } 99 /* link to the last node */ 100 if (ln == NULL) 101 ht->nodes[i] = n->next; 102 else 103 ln->next = n->next; 104 free(n); 105 return 0; 106 } 107 ln = n; 108 } 109 return -1; 110 } 111 112 struct htable * 113 htcreate(hash_fn *hash, key_cmp_fn *key_cmp, key_free_fn *key_free, 114 val_free_fn *val_free, unsigned int cap) 115 { 116 unsigned int i; 117 struct htable *ht; 118 119 if ((ht = malloc(sizeof(struct htable))) == NULL) { 120 perror("error: malloc"); 121 return NULL; 122 } 123 if ((ht->nodes = malloc(cap * sizeof(struct htnode *))) == NULL) { 124 perror("error: malloc"); 125 return NULL; 126 } 127 for (i = 0; i < cap; i++) 128 ht->nodes[i] = NULL; 129 130 ht->cap = cap; 131 ht->len = 0; 132 ht->hash = hash; 133 ht->key_cmp = key_cmp; 134 ht->key_free = key_free; 135 ht->val_free = val_free; 136 return ht; 137 } 138 139 void 140 htdestroy(struct htable *ht) 141 { 142 destroy_and_free(ht, 1); 143 } 144 145 void * 146 htsearch(struct htable *ht, void *key) 147 { 148 unsigned int i; 149 struct htnode *n; 150 151 i = ht->hash(key, ht->cap); 152 for (n = ht->nodes[i]; n != NULL; n = n->next) { 153 if (ht->key_cmp(key, n->key) == 0) 154 return n->val; 155 } 156 return NULL; 157 } 158 159 int 160 htinsert(struct htable *ht, void *key, void *val) 161 { 162 return insert_or_replace_val(ht, key, val, 0); 163 } 164 165 int 166 htremove(struct htable *ht, void *key) 167 { 168 return remove_or_replace_key(ht, key, 0, NULL); 169 } 170 171 int 172 htmodkey(struct htable *ht, void *oldkey, void *newkey) 173 { 174 return remove_or_replace_key(ht, oldkey, 1, newkey); 175 } 176 177 int 178 htmodval(struct htable *ht, void *key, void *newval) 179 { 180 return insert_or_replace_val(ht, key, newval, 1); 181 } 182 183 struct htable * 184 htresize(struct htable *ht, unsigned int newcap) 185 { 186 struct htable *newht; 187 struct htiter it; 188 189 newht = htcreate(ht->hash, ht->key_cmp, ht->key_free, ht->val_free, newcap); 190 if (newht == NULL) 191 return NULL; 192 193 htiter_init(&it); 194 while(htiterate(ht, &it)) { 195 if (htinsert(newht, it.node->key, it.node->val) == -1) { 196 htdestroy(newht); 197 return NULL; 198 } 199 } 200 201 destroy_and_free(ht, 0); 202 return newht; 203 } 204 205 void 206 htiter_init(struct htiter *it) 207 { 208 it->index = 0; 209 it->node = NULL; 210 } 211 212 int 213 htiterate(struct htable *ht, struct htiter *it) 214 { 215 if (it->node != NULL) 216 it->node = it->node->next; 217 218 while (it->node == NULL && it->index < ht->cap) { 219 it->node = ht->nodes[it->index]; 220 it->index++; 221 } 222 223 if (it->node != NULL) 224 return 1; 225 else 226 return 0; 227 }