#include #include #include #include "dict.h" struct elt { struct elt *next; char *key; char *value; }; struct dict { int size; /* size of the pointer table */ int n; /* number of elements stored */ struct elt **table; }; #define INITIAL_SIZE (1024) #define GROWTH_FACTOR (2) #define MAX_LOAD_FACTOR (1) /* dictionary initialization code used in both DictCreate and grow */ Dict internalDictCreate(int size) { Dict d; int i; d = malloc(sizeof(*d)); assert(d != 0); d->size = size; d->n = 0; d->table = malloc(sizeof(struct elt *) * d->size); assert(d->table != 0); for(i = 0; i < d->size; i++) d->table[i] = 0; return d; } Dict DictCreate(void) { return internalDictCreate(INITIAL_SIZE); } void DictDestroy(Dict d) { int i; struct elt *e; struct elt *next; for(i = 0; i < d->size; i++) { for(e = d->table[i]; e != 0; e = next) { next = e->next; free(e->key); free(e->value); free(e); } } free(d->table); free(d); } #define MULTIPLIER (97) static unsigned long hash_function(const char *s) { unsigned const char *us; unsigned long h; h = 0; for(us = (unsigned const char *) s; *us; us++) { h = h * MULTIPLIER + *us; } return h; } static void grow(Dict d) { Dict d2; /* new dictionary we'll create */ struct dict swap; /* temporary structure for brain transplant */ int i; struct elt *e; d2 = internalDictCreate(d->size * GROWTH_FACTOR); for(i = 0; i < d->size; i++) { for(e = d->table[i]; e != 0; e = e->next) { /* note: this recopies everything */ /* a more efficient implementation would * patch out the strdups inside DictInsert * to avoid this problem */ DictInsert(d2, e->key, e->value); } } /* the hideous part */ /* We'll swap the guts of d and d2 */ /* then call DictDestroy on d2 */ swap = *d; *d = *d2; *d2 = swap; DictDestroy(d2); } /* insert a new key-value pair into an existing dictionary */ void DictInsert(Dict d, const char *key, const char *value) { struct elt *e; unsigned long h; assert(key); assert(value); e = malloc(sizeof(*e)); assert(e); e->key = strdup(key); e->value = strdup(value); h = hash_function(key) % d->size; e->next = d->table[h]; d->table[h] = e; d->n++; /* grow table if there is not enough room */ if(d->n >= d->size * MAX_LOAD_FACTOR) { grow(d); } } /* return the most recently inserted value associated with a key */ /* or 0 if no matching key is present */ const char * DictSearch(Dict d, const char *key) { struct elt *e; for(e = d->table[hash_function(key) % d->size]; e != 0; e = e->next) { if(!strcmp(e->key, key)) { /* got it */ return e->value; } } return 0; } /* delete the most recently inserted record with the given key */ /* if there is no such record, has no effect */ void DictDelete(Dict d, const char *key) { struct elt **prev; /* what to change when elt is deleted */ struct elt *e; /* what to delete */ for(prev = &(d->table[hash_function(key) % d->size]); *prev != 0; prev = &((*prev)->next)) { if(!strcmp((*prev)->key, key)) { /* got it */ e = *prev; *prev = e->next; free(e->key); free(e->value); free(e); return; } } }