ref: e09ff804102de75826409b6043619d2668d9cef8
dir: /htable.c/
/* * This work is dedicated to the public domain. * See COPYING file for more information. */ #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "htable.h" static unsigned int hash(Htable *ht, void *key) { unsigned int i; unsigned int sum = 0; /* very simple hash function */ for (i = 0; i < (unsigned int)ht->keylenfn(key); i++) { sum += ((unsigned char *)key)[i] * (i + 1); } return (sum % ht->cap); } Htable * htcreate(KeyLenFn *keylenfn, KeyCmpFn *keycmpfn, FreeKeyFn *freekeyfn, FreeValFn *freevalfn, unsigned int cap) { unsigned int i; Htable *ht; if (keylenfn == NULL || keycmpfn == NULL || freekeyfn == NULL || freevalfn == NULL) { printf("error: callback function(s) cannot be NULL\n"); return NULL; } /* create a hash table */ if ((ht = calloc(1, sizeof(Htable))) == NULL) { printf("error: calloc: %s\n", strerror(errno)); return NULL; } if ((ht->nodes = calloc(cap, sizeof(Htnode))) == NULL) { printf("error: calloc: %s\n", strerror(errno)); return NULL; } ht->cap = cap; ht->len = 0; ht->keylenfn = keylenfn; ht->keycmpfn = keycmpfn; ht->freekeyfn = freekeyfn; ht->freevalfn = freevalfn; for (i = 0; i < cap; i++) ht->nodes[i] = NULL; return ht; } static void __htdestroy(Htable *ht, int dofree) { unsigned int i; Htnode *n; Htnode *tmp; for (i = 0; i < ht->cap; i++) { for (n = ht->nodes[i]; n != NULL;) { if (dofree) { ht->freekeyfn(n->key); ht->freevalfn(n->val); } tmp = n; n = n->next; free(tmp); } } free(ht->nodes); free(ht); } void htdestroy(Htable *ht) { __htdestroy(ht, 1); } void * htsearch(Htable *ht, void *key) { unsigned int i; Htnode *n; i = hash(ht, key); for (n = ht->nodes[i]; n != NULL; n = n->next) { if (ht->keycmpfn(key, n->key) == 0) return n->val; } return NULL; } int htinsert(Htable *ht, void *key, void *val) { unsigned int i; Htnode *n; /* current node */ Htnode *pn; /* previous node */ pn = NULL; i = hash(ht, key); for (n = ht->nodes[i]; n != NULL; n = n->next) { /*if key already exist, override value */ if (ht->keycmpfn(key, n->key) == 0) { ht->freekeyfn(n->key); ht->freevalfn(n->val); n->key = key; n->val = val; return 0; } pn = n; } /* create a new node */ if ((n = calloc(1, sizeof(Htnode))) == NULL) { printf("error: calloc: %s\n", strerror(errno)); return -1; } n->key = key; n->val = val; n->next = NULL; /* link to the previous node */ if (pn == NULL) ht->nodes[i] = n; else pn->next = n; /* increment the hash table length */ ht->len++; return 1; } static int __htremove(Htable *ht, void *key, int freeval) { unsigned int i; Htnode *n; /* current node */ Htnode *pn; /* previous node */ pn = NULL; i = hash(ht, key); for (n = ht->nodes[i]; n != NULL; n = n->next) { if (ht->keycmpfn(key, n->key) == 0) { /* free node memory */ ht->freekeyfn(n->key); if (freeval) ht->freevalfn(n->val); /* link to the previous node */ if (pn == NULL) ht->nodes[i] = n->next; else pn->next = n->next; /* free the node */ free(n); return 1; } pn = n; } return -1; } int htremove(Htable *ht, void *key) { return __htremove(ht, key, 1); } int htsetkey(Htable *ht, void *oldkey, void *newkey) { void *val = NULL; if ((val = htsearch(ht, oldkey)) == NULL) return -1; __htremove(ht, oldkey, 0); htinsert(ht, newkey, val); return 1; } void htresize(Htable *ht, unsigned int ncap) { unsigned int i, tmp; Htable *nht; /* new hash table */ Htnode *n; /* current node */ Htnode **list; /* list of nodes */ /* create a new hash table */ nht = htcreate(ht->keylenfn, ht->keycmpfn, ht->freekeyfn, ht->freevalfn, ncap); for (i = 0; i < ht->cap; i++) { for (n = ht->nodes[i]; n != NULL; n = n->next) htinsert(nht, n->key, n->val); } /* swap old hash table with new one */ list = ht->nodes; ht->nodes = nht->nodes; nht->nodes = list; tmp = ht->cap; ht->cap = nht->cap; nht->cap = tmp; tmp = ht->len; ht->len = nht->len; nht->len = tmp; /* destroy new(old) hash table */ __htdestroy(nht, 0); } int htiterate(Htable *ht, Htiter *it) { if (it->index == 0 && it->node == NULL) { it->index = 0; it->node = ht->nodes[0]; } else { it->node = it->node->next; } while (it->index < ht->cap) { while (it->node != NULL) { return 1; it->node = it->node->next; } it->index++; it->node = ht->nodes[it->index]; } return 0; }