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