blob: f4288208405008d38b04d5df57c625d2edff71bc [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
/*
Dictionary based on code by Morten Eriksen <[email protected]>.
*/
#include "dict.h"
struct dict_entry {
unsigned int hash;
void * key;
void * value;
struct dict_entry * next;
};
/* #define DICTTABLESIZE 97 */
#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
/* #define DICTTABLESIZE 9973 */
/* #define DICTTABLESIZE 99991 */
/* #define DICTTABLESIZE 999983 */
struct dict {
struct dict_entry * buckets[DICTTABLESIZE];
unsigned int (*key2hash)(void *);
int (*key_cmp)(void *, void *);
};
struct dict *
dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) {
struct dict * d;
int i;
d = malloc(sizeof(struct dict));
if (!d) {
perror("malloc()");
exit(1);
}
for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
d->buckets[i] = NULL;
}
d->key2hash = key2hash;
d->key_cmp = key_cmp;
return d;
}
void
dict_clear(struct dict * d) {
int i;
struct dict_entry * entry, * nextentry;
for (i = 0; i < DICTTABLESIZE; i++) {
for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
nextentry = entry->next;
free(entry);
}
d->buckets[i] = NULL;
}
free(d);
}
int
dict_enter(struct dict * d, void * key, void * value) {
struct dict_entry * entry, * newentry;
unsigned int hash = d->key2hash(key);
unsigned int bucketpos = hash % DICTTABLESIZE;
newentry = malloc(sizeof(struct dict_entry));
if (!newentry) {
perror("malloc");
exit(1);
}
newentry->hash = hash;
newentry->key = key;
newentry->value = value;
newentry->next = NULL;
entry = d->buckets[bucketpos];
while (entry && entry->next) entry = entry->next;
if (entry) entry->next = newentry;
else d->buckets[bucketpos] = newentry;
debug(3, "new dict entry at %p[%d]: (%p,%p)\n", d, bucketpos, key, value);
return 0;
}
void *
dict_find_entry(struct dict * d, void * key) {
unsigned int hash = d->key2hash(key);
unsigned int bucketpos = hash % DICTTABLESIZE;
struct dict_entry * entry;
for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
if (hash != entry->hash) {
continue;
}
if (!d->key_cmp(key, entry->key)) {
break;
}
}
return entry ? entry->value : NULL;
}
void
dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) {
int i;
for (i = 0; i < DICTTABLESIZE; i++) {
struct dict_entry * entry = d->buckets[i];
while (entry) {
func(entry->key, entry->value, data);
entry = entry->next;
}
}
}
/*****************************************************************************/
unsigned int
dict_key2hash_string(void * key) {
const char * s = (const char *)key;
unsigned int total = 0, shift = 0;
while (*s) {
total = total ^ ((*s) << shift);
shift += 5;
if (shift > 24) shift -= 24;
s++;
}
return total;
}
int
dict_key_cmp_string(void * key1, void * key2) {
return strcmp((const char *)key1, (const char *)key2);
}
unsigned int
dict_key2hash_int(void * key) {
return (unsigned int)key;
}
int
dict_key_cmp_int(void * key1, void * key2) {
return key1 - key2;
}