dict.c revision 2d45b1a8e26a36a9f85dc49e721c4390ca93dc40
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 *dict_init(unsigned int (*key2hash) (void *),
34		       int (*key_cmp) (void *, void *))
35{
36	struct dict *d;
37	int i;
38
39	d = malloc(sizeof(struct dict));
40	if (!d) {
41		perror("malloc()");
42		exit(1);
43	}
44	for (i = 0; i < DICTTABLESIZE; i++) {	/* better use memset()? */
45		d->buckets[i] = NULL;
46	}
47	d->key2hash = key2hash;
48	d->key_cmp = key_cmp;
49	return d;
50}
51
52void dict_clear(struct dict *d)
53{
54	int i;
55	struct dict_entry *entry, *nextentry;
56
57	assert(d);
58	for (i = 0; i < DICTTABLESIZE; i++) {
59		for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
60			nextentry = entry->next;
61			free(entry);
62		}
63		d->buckets[i] = NULL;
64	}
65	free(d);
66}
67
68int dict_enter(struct dict *d, void *key, void *value)
69{
70	struct dict_entry *entry, *newentry;
71	unsigned int hash = d->key2hash(key);
72	unsigned int bucketpos = hash % DICTTABLESIZE;
73
74	assert(d);
75	newentry = malloc(sizeof(struct dict_entry));
76	if (!newentry) {
77		perror("malloc");
78		exit(1);
79	}
80
81	newentry->hash = hash;
82	newentry->key = key;
83	newentry->value = value;
84	newentry->next = NULL;
85
86	entry = d->buckets[bucketpos];
87	while (entry && entry->next)
88		entry = entry->next;
89
90	if (entry)
91		entry->next = newentry;
92	else
93		d->buckets[bucketpos] = newentry;
94
95	debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
96	return 0;
97}
98
99void *dict_find_entry(struct dict *d, void *key)
100{
101	unsigned int hash = d->key2hash(key);
102	unsigned int bucketpos = hash % DICTTABLESIZE;
103	struct dict_entry *entry;
104
105	assert(d);
106	for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
107		if (hash != entry->hash) {
108			continue;
109		}
110		if (!d->key_cmp(key, entry->key)) {
111			break;
112		}
113	}
114	return entry ? entry->value : NULL;
115}
116
117void
118dict_apply_to_all(struct dict *d,
119		  void (*func) (void *key, void *value, void *data), void *data)
120{
121	int i;
122
123	if (!d) {
124		return;
125	}
126	for (i = 0; i < DICTTABLESIZE; i++) {
127		struct dict_entry *entry = d->buckets[i];
128		while (entry) {
129			func(entry->key, entry->value, data);
130			entry = entry->next;
131		}
132	}
133}
134
135/*****************************************************************************/
136
137unsigned int dict_key2hash_string(void *key)
138{
139	const char *s = (const char *)key;
140	unsigned int total = 0, shift = 0;
141
142	assert(key);
143	while (*s) {
144		total = total ^ ((*s) << shift);
145		shift += 5;
146		if (shift > 24)
147			shift -= 24;
148		s++;
149	}
150	return total;
151}
152
153int dict_key_cmp_string(void *key1, void *key2)
154{
155	assert(key1);
156	assert(key2);
157	return strcmp((const char *)key1, (const char *)key2);
158}
159
160unsigned int dict_key2hash_int(void *key)
161{
162	return (unsigned long)key;
163}
164
165int dict_key_cmp_int(void *key1, void *key2)
166{
167	return key1 - key2;
168}
169