blob: 8d9722011407e07d551bda4211140867dfadecdb [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 Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +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 Wienand9a2ad352006-02-20 22:44:45 +010033struct dict *
34dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) {
35 struct dict * d;
Juan Cespedescac15c32003-01-31 18:58:58 +010036 int i;
37
38 d = malloc(sizeof(struct dict));
39 if (!d) {
40 perror("malloc()");
41 exit(1);
42 }
Ian Wienand9a2ad352006-02-20 22:44:45 +010043 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
Juan Cespedescac15c32003-01-31 18:58:58 +010044 d->buckets[i] = NULL;
45 }
46 d->key2hash = key2hash;
47 d->key_cmp = key_cmp;
48 return d;
49}
50
Ian Wienand9a2ad352006-02-20 22:44:45 +010051void
52dict_clear(struct dict * d) {
Juan Cespedescac15c32003-01-31 18:58:58 +010053 int i;
Ian Wienand9a2ad352006-02-20 22:44:45 +010054 struct dict_entry * entry, * nextentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010055
Juan Cespedesa0ccf392003-02-01 19:02:37 +010056 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010057 for (i = 0; i < DICTTABLESIZE; i++) {
58 for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
59 nextentry = entry->next;
60 free(entry);
61 }
62 d->buckets[i] = NULL;
63 }
64 free(d);
65}
66
Ian Wienand9a2ad352006-02-20 22:44:45 +010067int
68dict_enter(struct dict * d, void * key, void * value) {
69 struct dict_entry * entry, * newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010070 unsigned int hash = d->key2hash(key);
71 unsigned int bucketpos = hash % DICTTABLESIZE;
72
Juan Cespedesa0ccf392003-02-01 19:02:37 +010073 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +010074 newentry = malloc(sizeof(struct dict_entry));
75 if (!newentry) {
76 perror("malloc");
77 exit(1);
78 }
79
Ian Wienand9a2ad352006-02-20 22:44:45 +010080 newentry->hash = hash;
81 newentry->key = key;
Juan Cespedescac15c32003-01-31 18:58:58 +010082 newentry->value = value;
Ian Wienand9a2ad352006-02-20 22:44:45 +010083 newentry->next = NULL;
Juan Cespedescac15c32003-01-31 18:58:58 +010084
85 entry = d->buckets[bucketpos];
Ian Wienand9a2ad352006-02-20 22:44:45 +010086 while (entry && entry->next) entry = entry->next;
Juan Cespedescac15c32003-01-31 18:58:58 +010087
Ian Wienand9a2ad352006-02-20 22:44:45 +010088 if (entry) entry->next = newentry;
89 else d->buckets[bucketpos] = newentry;
Juan Cespedescac15c32003-01-31 18:58:58 +010090
Ian Wienand9a2ad352006-02-20 22:44:45 +010091 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value);
Juan Cespedescac15c32003-01-31 18:58:58 +010092 return 0;
93}
94
Ian Wienand9a2ad352006-02-20 22:44:45 +010095void *
96dict_find_entry(struct dict * d, void * key) {
Juan Cespedescac15c32003-01-31 18:58:58 +010097 unsigned int hash = d->key2hash(key);
98 unsigned int bucketpos = hash % DICTTABLESIZE;
Ian Wienand9a2ad352006-02-20 22:44:45 +010099 struct dict_entry * entry;
Juan Cespedescac15c32003-01-31 18:58:58 +0100100
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100101 assert(d);
Juan Cespedescac15c32003-01-31 18:58:58 +0100102 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
103 if (hash != entry->hash) {
104 continue;
105 }
106 if (!d->key_cmp(key, entry->key)) {
107 break;
108 }
109 }
110 return entry ? entry->value : NULL;
111}
112
113void
Ian Wienand9a2ad352006-02-20 22:44:45 +0100114dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100115 int i;
116
Juan Cespedesefe85f02004-04-04 01:31:38 +0200117 if (!d) {
118 return;
119 }
Juan Cespedescac15c32003-01-31 18:58:58 +0100120 for (i = 0; i < DICTTABLESIZE; i++) {
Ian Wienand9a2ad352006-02-20 22:44:45 +0100121 struct dict_entry * entry = d->buckets[i];
Juan Cespedescac15c32003-01-31 18:58:58 +0100122 while (entry) {
123 func(entry->key, entry->value, data);
124 entry = entry->next;
125 }
126 }
127}
128
129/*****************************************************************************/
130
Ian Wienand9a2ad352006-02-20 22:44:45 +0100131unsigned int
132dict_key2hash_string(void * key) {
133 const char * s = (const char *)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100134 unsigned int total = 0, shift = 0;
135
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100136 assert(key);
Juan Cespedescac15c32003-01-31 18:58:58 +0100137 while (*s) {
138 total = total ^ ((*s) << shift);
139 shift += 5;
Ian Wienand9a2ad352006-02-20 22:44:45 +0100140 if (shift > 24) shift -= 24;
Juan Cespedescac15c32003-01-31 18:58:58 +0100141 s++;
142 }
143 return total;
144}
145
Ian Wienand9a2ad352006-02-20 22:44:45 +0100146int
147dict_key_cmp_string(void * key1, void * key2) {
Juan Cespedesa0ccf392003-02-01 19:02:37 +0100148 assert(key1);
149 assert(key2);
Juan Cespedescac15c32003-01-31 18:58:58 +0100150 return strcmp((const char *)key1, (const char *)key2);
151}
152
Ian Wienand9a2ad352006-02-20 22:44:45 +0100153unsigned int
154dict_key2hash_int(void * key) {
Juan Cespedesd914a202004-11-10 00:15:33 +0100155 return (unsigned long)key;
Juan Cespedescac15c32003-01-31 18:58:58 +0100156}
157
Ian Wienand9a2ad352006-02-20 22:44:45 +0100158int
159dict_key_cmp_int(void * key1, void * key2) {
Juan Cespedescac15c32003-01-31 18:58:58 +0100160 return key1 - key2;
161}
Ian Wienand9a2ad352006-02-20 22:44:45 +0100162