blob: fe8a0bccef02fb82670aed4ddcba84daa2e8cc9f [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
Juan Cespedesf1350522008-12-16 18:19:58 +010033struct dict *
34dict_init(unsigned int (*key2hash) (void *),
35 int (*key_cmp) (void *, void *)) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010036 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
Juan Cespedesf1350522008-12-16 18:19:58 +010052void
53dict_clear(struct dict *d) {
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
Juan Cespedesf1350522008-12-16 18:19:58 +010068int
69dict_enter(struct dict *d, void *key, void *value) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +010070 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
Juan Cespedesf1350522008-12-16 18:19:58 +010099void *
100dict_find_entry(struct dict *d, void *key) {
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,
Juan Cespedesf1350522008-12-16 18:19:58 +0100119 void (*func) (void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100120 int i;
121
Juan Cespedesefe85f02004-04-04 01:31:38 +0200122 if (!d) {
123 return;
124 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100125 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100126 struct dict_entry *entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100127 while (entry) {
128 func(entry->key, entry->value, data);
129 entry = entry->next;
130 }
131 }
132}
133
134/*****************************************************************************/
135
Juan Cespedesf1350522008-12-16 18:19:58 +0100136unsigned int
137dict_key2hash_string(void *key) {
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100138 const char *s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100139 unsigned int total = 0, shift = 0;
140
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100141 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100142 while (*s) {
143 total = total ^ ((*s) << shift);
144 shift += 5;
Ian Wienand2d45b1a2006-02-20 22:48:07 +0100145 if (shift > 24)
146 shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100147 s++;
148 }
149 return total;
150}
151
Juan Cespedesf1350522008-12-16 18:19:58 +0100152int
153dict_key_cmp_string(void *key1, void *key2) {
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100154 assert(key1);
155 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100156 return strcmp((const char *)key1, (const char *)key2);
157}
158
Juan Cespedesf1350522008-12-16 18:19:58 +0100159unsigned int
160dict_key2hash_int(void *key) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100161 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100162}
163
Juan Cespedesf1350522008-12-16 18:19:58 +0100164int
165dict_key_cmp_int(void *key1, void *key2) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100166 return key1 - key2;
167}