dict.c revision cd8976dbee947f152c3a322503a1063c6359da76
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <assert.h>
5
6#include "debug.h"
7
8/*
9  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
10*/
11
12#include "dict.h"
13
14struct dict_entry {
15	unsigned int hash;
16	void *key;
17	void *value;
18	struct dict_entry *next;
19};
20
21/* #define DICTTABLESIZE 97 */
22#define DICTTABLESIZE 997	/* Semi-randomly selected prime number. */
23/* #define DICTTABLESIZE 9973 */
24/* #define DICTTABLESIZE 99991 */
25/* #define DICTTABLESIZE 999983 */
26
27struct dict {
28	struct dict_entry *buckets[DICTTABLESIZE];
29	unsigned int (*key2hash) (void *);
30	int (*key_cmp) (void *, void *);
31};
32
33struct dict *
34dict_init(unsigned int (*key2hash) (void *),
35		       int (*key_cmp) (void *, void *)) {
36	struct dict *d;
37	int i;
38
39	debug(DEBUG_FUNCTION, "dict_init()");
40
41	d = malloc(sizeof(struct dict));
42	if (!d) {
43		perror("malloc()");
44		exit(1);
45	}
46	for (i = 0; i < DICTTABLESIZE; i++) {	/* better use memset()? */
47		d->buckets[i] = NULL;
48	}
49	d->key2hash = key2hash;
50	d->key_cmp = key_cmp;
51	return d;
52}
53
54void
55dict_clear(struct dict *d) {
56	int i;
57	struct dict_entry *entry, *nextentry;
58
59	debug(DEBUG_FUNCTION, "dict_clear()");
60	assert(d);
61	for (i = 0; i < DICTTABLESIZE; i++) {
62		for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
63			nextentry = entry->next;
64			free(entry);
65		}
66		d->buckets[i] = NULL;
67	}
68	free(d);
69}
70
71int
72dict_enter(struct dict *d, void *key, void *value) {
73	struct dict_entry *entry, *newentry;
74	unsigned int hash;
75	unsigned int bucketpos;
76
77	debug(DEBUG_FUNCTION, "dict_enter()");
78
79	hash = d->key2hash(key);
80	bucketpos = hash % DICTTABLESIZE;
81
82	assert(d);
83	newentry = malloc(sizeof(struct dict_entry));
84	if (!newentry) {
85		perror("malloc");
86		exit(1);
87	}
88
89	newentry->hash = hash;
90	newentry->key = key;
91	newentry->value = value;
92	newentry->next = NULL;
93
94	entry = d->buckets[bucketpos];
95	while (entry && entry->next)
96		entry = entry->next;
97
98	if (entry)
99		entry->next = newentry;
100	else
101		d->buckets[bucketpos] = newentry;
102
103	debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
104	return 0;
105}
106
107void *
108dict_find_entry(struct dict *d, void *key) {
109	unsigned int hash;
110	unsigned int bucketpos;
111	struct dict_entry *entry;
112
113	debug(DEBUG_FUNCTION, "dict_find_entry()");
114
115	hash = d->key2hash(key);
116	bucketpos = hash % DICTTABLESIZE;
117
118	assert(d);
119	for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
120		if (hash != entry->hash) {
121			continue;
122		}
123		if (!d->key_cmp(key, entry->key)) {
124			break;
125		}
126	}
127	return entry ? entry->value : NULL;
128}
129
130void
131dict_apply_to_all(struct dict *d,
132		  void (*func) (void *key, void *value, void *data), void *data) {
133	int i;
134
135	debug(DEBUG_FUNCTION, "dict_apply_to_all()");
136
137	if (!d) {
138		return;
139	}
140	for (i = 0; i < DICTTABLESIZE; i++) {
141		struct dict_entry *entry = d->buckets[i];
142		while (entry) {
143			func(entry->key, entry->value, data);
144			entry = entry->next;
145		}
146	}
147}
148
149/*****************************************************************************/
150
151unsigned int
152dict_key2hash_string(void *key) {
153	const char *s = (const char *)key;
154	unsigned int total = 0, shift = 0;
155
156	assert(key);
157	while (*s) {
158		total = total ^ ((*s) << shift);
159		shift += 5;
160		if (shift > 24)
161			shift -= 24;
162		s++;
163	}
164	return total;
165}
166
167int
168dict_key_cmp_string(void *key1, void *key2) {
169	assert(key1);
170	assert(key2);
171	return strcmp((const char *)key1, (const char *)key2);
172}
173
174unsigned int
175dict_key2hash_int(void *key) {
176	return (unsigned long)key;
177}
178
179int
180dict_key_cmp_int(void *key1, void *key2) {
181	return key1 - key2;
182}
183
184struct dict *
185dict_clone(struct dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) {
186	struct dict *d;
187	int i;
188
189	debug(DEBUG_FUNCTION, "dict_clone()");
190
191	d = malloc(sizeof(struct dict));
192	if (!d) {
193		perror("malloc()");
194		exit(1);
195	}
196	memcpy(d, old, sizeof(struct dict));
197	for (i = 0; i < DICTTABLESIZE; i++) {	/* better use memset()? */
198		struct dict_entry *de_old;
199		struct dict_entry **de_new;
200
201		de_old = old->buckets[i];
202		de_new = &d->buckets[i];
203		while (de_old) {
204			*de_new = malloc(sizeof(struct dict_entry));
205			if (!*de_new) {
206				perror("malloc()");
207				exit(1);
208			}
209			memcpy(*de_new, de_old, sizeof(struct dict_entry));
210			(*de_new)->key = key_clone(de_old->key);
211			(*de_new)->value = value_clone(de_old->value);
212			de_new = &(*de_new)->next;
213			de_old = de_old->next;
214		}
215	}
216	return d;
217}
218