dict.c revision bc8caf0ca16c8cb87bc8288c7a49ee164d075ead
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 * 34dict_init(unsigned int (*key2hash) (void *), 35 int (*key_cmp) (void *, void *)) { 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 53dict_clear(struct dict *d) { 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 69dict_enter(struct dict *d, void *key, void *value) { 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 * 100dict_find_entry(struct dict *d, void *key) { 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 int i; 121 122 if (!d) { 123 return; 124 } 125 for (i = 0; i < DICTTABLESIZE; i++) { 126 struct dict_entry *entry = d->buckets[i]; 127 while (entry) { 128 func(entry->key, entry->value, data); 129 entry = entry->next; 130 } 131 } 132} 133 134/*****************************************************************************/ 135 136unsigned int 137dict_key2hash_string(void *key) { 138 const char *s = (const char *)key; 139 unsigned int total = 0, shift = 0; 140 141 assert(key); 142 while (*s) { 143 total = total ^ ((*s) << shift); 144 shift += 5; 145 if (shift > 24) 146 shift -= 24; 147 s++; 148 } 149 return total; 150} 151 152int 153dict_key_cmp_string(void *key1, void *key2) { 154 assert(key1); 155 assert(key2); 156 return strcmp((const char *)key1, (const char *)key2); 157} 158 159unsigned int 160dict_key2hash_int(void *key) { 161 return (unsigned long)key; 162} 163 164int 165dict_key_cmp_int(void *key1, void *key2) { 166 return key1 - key2; 167} 168 169struct dict * 170dict_clone(struct dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) { 171 struct dict *d; 172 int i; 173 174 d = malloc(sizeof(struct dict)); 175 if (!d) { 176 perror("malloc()"); 177 exit(1); 178 } 179 memcpy(d, old, sizeof(struct dict)); 180 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */ 181 struct dict_entry *de_old; 182 struct dict_entry **de_new; 183 184 de_old = old->buckets[i]; 185 de_new = &d->buckets[i]; 186 while (de_old) { 187 *de_new = malloc(sizeof(struct dict_entry)); 188 if (!*de_new) { 189 perror("malloc()"); 190 exit(1); 191 } 192 memcpy(*de_new, de_old, sizeof(struct dict_entry)); 193 (*de_new)->key = key_clone(de_old->key); 194 (*de_new)->value = value_clone(de_old->value); 195 de_new = &(*de_new)->next; 196 de_old = de_old->next; 197 } 198 } 199 return d; 200} 201