dict.c revision 9a2ad351a1c3215dc596ff3e2e3fd4bc24445a6b
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 *), int (*key_cmp)(void *, void *)) { 35 struct dict * d; 36 int i; 37 38 d = malloc(sizeof(struct dict)); 39 if (!d) { 40 perror("malloc()"); 41 exit(1); 42 } 43 for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */ 44 d->buckets[i] = NULL; 45 } 46 d->key2hash = key2hash; 47 d->key_cmp = key_cmp; 48 return d; 49} 50 51void 52dict_clear(struct dict * d) { 53 int i; 54 struct dict_entry * entry, * nextentry; 55 56 assert(d); 57 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 67int 68dict_enter(struct dict * d, void * key, void * value) { 69 struct dict_entry * entry, * newentry; 70 unsigned int hash = d->key2hash(key); 71 unsigned int bucketpos = hash % DICTTABLESIZE; 72 73 assert(d); 74 newentry = malloc(sizeof(struct dict_entry)); 75 if (!newentry) { 76 perror("malloc"); 77 exit(1); 78 } 79 80 newentry->hash = hash; 81 newentry->key = key; 82 newentry->value = value; 83 newentry->next = NULL; 84 85 entry = d->buckets[bucketpos]; 86 while (entry && entry->next) entry = entry->next; 87 88 if (entry) entry->next = newentry; 89 else d->buckets[bucketpos] = newentry; 90 91 debug(3, "new dict entry at %p[%d]: (%p,%p)", d, bucketpos, key, value); 92 return 0; 93} 94 95void * 96dict_find_entry(struct dict * d, void * key) { 97 unsigned int hash = d->key2hash(key); 98 unsigned int bucketpos = hash % DICTTABLESIZE; 99 struct dict_entry * entry; 100 101 assert(d); 102 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 114dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) { 115 int i; 116 117 if (!d) { 118 return; 119 } 120 for (i = 0; i < DICTTABLESIZE; i++) { 121 struct dict_entry * entry = d->buckets[i]; 122 while (entry) { 123 func(entry->key, entry->value, data); 124 entry = entry->next; 125 } 126 } 127} 128 129/*****************************************************************************/ 130 131unsigned int 132dict_key2hash_string(void * key) { 133 const char * s = (const char *)key; 134 unsigned int total = 0, shift = 0; 135 136 assert(key); 137 while (*s) { 138 total = total ^ ((*s) << shift); 139 shift += 5; 140 if (shift > 24) shift -= 24; 141 s++; 142 } 143 return total; 144} 145 146int 147dict_key_cmp_string(void * key1, void * key2) { 148 assert(key1); 149 assert(key2); 150 return strcmp((const char *)key1, (const char *)key2); 151} 152 153unsigned int 154dict_key2hash_int(void * key) { 155 return (unsigned long)key; 156} 157 158int 159dict_key_cmp_int(void * key1, void * key2) { 160 return key1 - key2; 161} 162 163