blob: a24370af9ee763bd5abd1d8c677cba4afce73fcc [file] [log] [blame]
Juan Cespedescac15c32003-01-31 18:58:58 +01001#include <stdio.h>
2#include <stdlib.h>
Juan Cespedes7186e2a2003-01-31 19:56:34 +01003#include <string.h>
Juan Cespedesa0ccf392003-02-01 19:02:37 +01004#include <assert.h>
Juan Cespedescac15c32003-01-31 18:58:58 +01005
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;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010016 void *key;
17 void *value;
18 struct dict_entry *next;
Juan Cespedescac15c32003-01-31 18:58:58 +010019};
20
21/* #define DICTTABLESIZE 97 */
Ian Wienand2d45b1a2006-02-20 22:48:07 +010022#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
Juan Cespedescac15c32003-01-31 18:58:58 +010023/* #define DICTTABLESIZE 9973 */
24/* #define DICTTABLESIZE 99991 */
25/* #define DICTTABLESIZE 999983 */
26
27struct dict {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010028 struct dict_entry *buckets[DICTTABLESIZE];
29 unsigned int (*key2hash) (void *);
30 int (*key_cmp) (void *, void *);
Juan Cespedescac15c32003-01-31 18:58:58 +010031};
32
Ian Wienand2d45b1a2006-02-20 22:48:07 +010033struct dict *dict_init(unsigned int (*key2hash) (void *),
34 int (*key_cmp) (void *, void *))
35{
36 struct dict *d;
Juan Cespedescac15c32003-01-31 18:58:58 +010037 int i;
38
39 d = malloc(sizeof(struct dict));
40 if (!d) {
41 perror("malloc()");
42 exit(1);
43 }
Ian Wienand2d45b1a2006-02-20 22:48:07 +010044 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010045 d->buckets[i] = NULL;
46 }
47 d->key2hash = key2hash;
48 d->key_cmp = key_cmp;
49 return d;
50}
51
Ian Wienand2d45b1a2006-02-20 22:48:07 +010052void dict_clear(struct dict *d)
53{
Juan Cespedescac15c32003-01-31 18:58:58 +010054 int i;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010055 struct dict_entry *entry, *nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010056
Juan Cespedesa0ccf392003-02-01 19:02:37 +010057 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010058 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
Ian Wienand2d45b1a2006-02-20 22:48:07 +010068int dict_enter(struct dict *d, void *key, void *value)
69{
70 struct dict_entry *entry, *newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010071 unsigned int hash = d->key2hash(key);
72 unsigned int bucketpos = hash % DICTTABLESIZE;
73
Juan Cespedesa0ccf392003-02-01 19:02:37 +010074 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010075 newentry = malloc(sizeof(struct dict_entry));
76 if (!newentry) {
77 perror("malloc");
78 exit(1);
79 }
80
Ian Wienand2d45b1a2006-02-20 22:48:07 +010081 newentry->hash = hash;
82 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +010083 newentry->value = value;
Ian Wienand2d45b1a2006-02-20 22:48:07 +010084 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +010085
86 entry = d->buckets[bucketpos];
Ian Wienand2d45b1a2006-02-20 22:48:07 +010087 while (entry && entry->next)
88 entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +010089
Ian Wienand2d45b1a2006-02-20 22:48:07 +010090 if (entry)
91 entry->next = newentry;
92 else
93 d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010094
Ian Wienand9a2ad352006-02-20 22:44:45 +010095 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +010096 return 0;
97}
98
Ian Wienand2d45b1a2006-02-20 22:48:07 +010099void *dict_find_entry(struct dict *d, void *key)
100{
Juan Cespedescac15c32003-01-31 18:58:58 +0100101 unsigned int hash = d->key2hash(key);
102 unsigned int bucketpos = hash % DICTTABLESIZE;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100103 struct dict_entry *entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100104
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100105 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100106 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
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100118dict_apply_to_all(struct dict *d,
119 void (*func) (void *key, void *value, void *data), void *data)
120{
Juan Cespedescac15c32003-01-31 18:58:58 +0100121 int i;
122
Juan Cespedesefe85f02004-04-04 01:31:38 +0200123 if (!d) {
124 return;
125 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100126 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100127 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100128 while (entry) {
129 func(entry->key, entry->value, data);
130 entry = entry->next;
131 }
132 }
133}
134
135/*****************************************************************************/
136
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100137unsigned int dict_key2hash_string(void *key)
138{
139 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100140 unsigned int total = 0, shift = 0;
141
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100142 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100143 while (*s) {
144 total = total ^ ((*s) << shift);
145 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100146 if (shift > 24)
147 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100148 s++;
149 }
150 return total;
151}
152
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100153int dict_key_cmp_string(void *key1, void *key2)
154{
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100155 assert(key1);
156 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100157 return strcmp((const char *)key1, (const char *)key2);
158}
159
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100160unsigned int dict_key2hash_int(void *key)
161{
Juan Cespedesd914a202004-11-10 00:15:33 +0100162 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100163}
164
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100165int dict_key_cmp_int(void *key1, void *key2)
166{
Juan Cespedescac15c32003-01-31 18:58:58 +0100167 return key1 - key2;
168}