dict.c revision cac15c3f170b5ec2cc6304c8c0763a78103e1778
1#include <stdio.h>
2#include <stdlib.h>
3
4#include "debug.h"
5
6/*
7  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
8*/
9
10#include "dict.h"
11
12struct dict_entry {
13	unsigned int hash;
14	void * key;
15	void * value;
16	struct dict_entry * next;
17};
18
19/* #define DICTTABLESIZE 97 */
20#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
21/* #define DICTTABLESIZE 9973 */
22/* #define DICTTABLESIZE 99991 */
23/* #define DICTTABLESIZE 999983 */
24
25struct dict {
26	struct dict_entry * buckets[DICTTABLESIZE];
27	unsigned int (*key2hash)(void *);
28	int (*key_cmp)(void *, void *);
29};
30
31struct dict *
32dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) {
33	struct dict * d;
34	int i;
35
36	d = malloc(sizeof(struct dict));
37	if (!d) {
38		perror("malloc()");
39		exit(1);
40	}
41	for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
42		d->buckets[i] = NULL;
43	}
44	d->key2hash = key2hash;
45	d->key_cmp = key_cmp;
46	return d;
47}
48
49void
50dict_clear(struct dict * d) {
51	int i;
52	struct dict_entry * entry, * nextentry;
53
54	for (i = 0; i < DICTTABLESIZE; i++) {
55		for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
56			nextentry = entry->next;
57			free(entry);
58		}
59		d->buckets[i] = NULL;
60	}
61	free(d);
62}
63
64int
65dict_enter(struct dict * d, void * key, void * value) {
66	struct dict_entry * entry, * newentry;
67	unsigned int hash = d->key2hash(key);
68	unsigned int bucketpos = hash % DICTTABLESIZE;
69
70	newentry = malloc(sizeof(struct dict_entry));
71	if (!newentry) {
72		perror("malloc");
73		exit(1);
74	}
75
76	newentry->hash  = hash;
77	newentry->key   = key;
78	newentry->value = value;
79	newentry->next  = NULL;
80
81	entry = d->buckets[bucketpos];
82	while (entry && entry->next) entry = entry->next;
83
84	if (entry) entry->next = newentry;
85	else d->buckets[bucketpos] = newentry;
86
87	debug(3, "new dict entry at %p[%d]: (%p,%p)\n", d, bucketpos, key, value);
88	return 0;
89}
90
91void *
92dict_find_entry(struct dict * d, void * key) {
93	unsigned int hash = d->key2hash(key);
94	unsigned int bucketpos = hash % DICTTABLESIZE;
95	struct dict_entry * entry;
96
97	for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
98		if (hash != entry->hash) {
99			continue;
100		}
101		if (!d->key_cmp(key, entry->key)) {
102			break;
103		}
104	}
105	return entry ? entry->value : NULL;
106}
107
108void
109dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) {
110	int i;
111
112	for (i = 0; i < DICTTABLESIZE; i++) {
113		struct dict_entry * entry = d->buckets[i];
114		while (entry) {
115			func(entry->key, entry->value, data);
116			entry = entry->next;
117		}
118	}
119}
120
121/*****************************************************************************/
122
123unsigned int
124dict_key2hash_string(void * key) {
125	const char * s = (const char *)key;
126	unsigned int total = 0, shift = 0;
127
128	while (*s) {
129		total = total ^ ((*s) << shift);
130		shift += 5;
131		if (shift > 24) shift -= 24;
132		s++;
133	}
134	return total;
135}
136
137int
138dict_key_cmp_string(void * key1, void * key2) {
139	return strcmp((const char *)key1, (const char *)key2);
140}
141
142unsigned int
143dict_key2hash_int(void * key) {
144	return (unsigned int)key;
145}
146
147int
148dict_key_cmp_int(void * key1, void * key2) {
149	return key1 - key2;
150}
151
152