dict.c revision 3219f320604810532a4938dda8f9dfadb0e840f3
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 *dict_init(unsigned int (*key2hash) (void *), 34 int (*key_cmp) (void *, void *)) 35{ 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 dict_clear(struct dict *d) 53{ 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 dict_enter(struct dict *d, void *key, void *value) 69{ 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)\n", d, bucketpos, key, 96 value); 97 return 0; 98} 99 100void *dict_find_entry(struct dict *d, void *key) 101{ 102 unsigned int hash = d->key2hash(key); 103 unsigned int bucketpos = hash % DICTTABLESIZE; 104 struct dict_entry *entry; 105 106 assert(d); 107 for (entry = d->buckets[bucketpos]; entry; entry = entry->next) { 108 if (hash != entry->hash) { 109 continue; 110 } 111 if (!d->key_cmp(key, entry->key)) { 112 break; 113 } 114 } 115 return entry ? entry->value : NULL; 116} 117 118void 119dict_apply_to_all(struct dict *d, 120 void (*func) (void *key, void *value, void *data), void *data) 121{ 122 int i; 123 124 if (!d) { 125 return; 126 } 127 for (i = 0; i < DICTTABLESIZE; i++) { 128 struct dict_entry *entry = d->buckets[i]; 129 while (entry) { 130 func(entry->key, entry->value, data); 131 entry = entry->next; 132 } 133 } 134} 135 136/*****************************************************************************/ 137 138unsigned int dict_key2hash_string(void *key) 139{ 140 const char *s = (const char *)key; 141 unsigned int total = 0, shift = 0; 142 143 assert(key); 144 while (*s) { 145 total = total ^ ((*s) << shift); 146 shift += 5; 147 if (shift > 24) 148 shift -= 24; 149 s++; 150 } 151 return total; 152} 153 154int dict_key_cmp_string(void *key1, void *key2) 155{ 156 assert(key1); 157 assert(key2); 158 return strcmp((const char *)key1, (const char *)key2); 159} 160 161unsigned int dict_key2hash_int(void *key) 162{ 163 return (unsigned long)key; 164} 165 166int dict_key_cmp_int(void *key1, void *key2) 167{ 168 return key1 - key2; 169} 170