hash.c (5983B)
1 /* $Id: //depot/blt/lib/libblt/hash.c#3 $ 2 ** 3 ** Copyright 1999 Sidney Cammeresi. 4 ** All rights reserved. 5 ** 6 ** Redistribution and use in source and binary forms, with or without 7 ** modification, are permitted provided that the following conditions 8 ** are met: 9 ** 10 ** 1. Redistributions of source code must retain the above copyright notice, 11 ** this list of conditions and the following disclaimer. 12 ** 13 ** 2. Redistributions in binary form must reproduce the above copyright 14 ** notice, this list of conditions and the following disclaimer in the 15 ** documentation and/or other materials provided with the distribution. 16 ** 17 ** 3. The name of the author may not be used to endorse or promote products 18 ** derived from this software without specific prior written permission. 19 ** 20 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS' AND ANY EXPRESS OR IMPLIED 21 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 23 ** NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 ** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * these algorithms are based on knuth's algorithm 6.4d, as described in 34 * vol. 3, p. 529 of taocp. 35 * 36 * XXX - keys must be unique! 37 */ 38 39 /* 40 41 the primes were computed by using the following program: 42 43 int main (void) 44 { 45 unsigned int i, j, good, last; 46 47 for (i = 17, last = 0; i < 65536 * 16384 - 1; i++) 48 { 49 for (j = 2, good = 1; (j <= floor (sqrt ((double) i))) && good; j++) 50 if (!(i % j)) 51 good = 0; 52 if (good) 53 { 54 if (last == i - 2) 55 { 56 printf ("%d %d\n", last, i); 57 i *= 2; 58 } 59 last = i; 60 } 61 } 62 63 return 0; 64 } 65 66 */ 67 68 #include <stddef.h> 69 #include <stdlib.h> 70 #include <blt/hash.h> 71 72 static unsigned int table_size[] = { 7, 19, 43, 103, 229, 463, 1021, 2083, 4219, 73 8539, 17191, 34471, 69031, 138079, 276373, 552751, 1105549, 2211259, 74 4422619, 8845453, 17691043, 35382091, 70764259, 141528559, 283057213, 75 566115259 }; 76 77 static int hash (int key, int size); 78 static int rehash (int key, int size); 79 static void hashtable_rebuild (hashtable_t *t, int dir); 80 81 static int hash (int key, int size) 82 { 83 return key % table_size[size]; 84 } 85 86 static int rehash (int key, int size) 87 { 88 return 1 + (key % (table_size[size] - 2)); 89 } 90 91 hashtable_t *hashtable_new (float max_load) 92 { 93 int i; 94 hashtable_t *t; 95 96 t = (hashtable_t *) malloc (sizeof (hashtable_t)); 97 t->size_index = 0; 98 t->used = t->dirty = 0; 99 t->max_load = max_load; 100 t->table = (hashnode_t *) malloc (sizeof (hashnode_t) * *table_size); 101 for (i = 0; i < table_size[t->size_index]; i++) 102 t->table[i].valid = t->table[i].dirty = 0; 103 return t; 104 } 105 106 void hashtable_del (hashtable_t *t) 107 { 108 free (t->table); 109 } 110 111 void hashtable_insert (hashtable_t *t, int key, void *data, int dsize) 112 { 113 int i, c; 114 115 if (t->used > (t->max_load * table_size[t->size_index])) 116 hashtable_rebuild (t, 1); 117 118 i = hash (key, t->size_index); 119 if (t->table[i].valid) 120 do 121 { 122 c = rehash (key, t->size_index); 123 i -= c; 124 if (i < 0) 125 i += table_size[t->size_index]; 126 } 127 while (t->table[i].valid && !t->table[i].dirty); 128 if (!t->table[i].dirty) 129 t->used++; 130 t->table[i].valid = 1; 131 t->table[i].dirty = 0; 132 t->table[i].key = key; 133 t->table[i].dsize = dsize; 134 t->table[i].data = data; 135 } 136 137 static void hashtable_rebuild (hashtable_t *t, int dir) 138 { 139 int i, old_index; 140 hashnode_t *old; 141 142 old = t->table; 143 old_index = t->size_index; 144 switch (dir) 145 { 146 case -1: 147 t->size_index = t->size_index ? t->size_index - 1 : 0; 148 break; 149 case 0: 150 break; 151 case 1: 152 t->size_index++; 153 break; 154 default: 155 return; 156 } 157 158 t->used = t->dirty = 0; 159 t->table = (hashnode_t *) malloc (sizeof (hashnode_t) * 160 table_size[t->size_index]); 161 for (i = 0; i < table_size[t->size_index]; i++) 162 t->table[i].valid = t->table[i].dirty = 0; 163 for (i = 0; i < table_size[old_index]; i++) 164 if (old[i].valid && !old[i].dirty) 165 hashtable_insert (t, old[i].key, old[i].data, old[i].dsize); 166 free (old); 167 } 168 169 void *hashtable_lookup (hashtable_t *t, int key, int *dsize) 170 { 171 int i, c; 172 173 i = hash (key, t->size_index); 174 while (t->table[i].valid) 175 { 176 if ((t->table[i].key == key) && !t->table[i].dirty) 177 { 178 if (dsize != NULL) 179 *dsize = t->table[i].dsize; 180 return t->table[i].data; 181 } 182 c = rehash (key, t->size_index); 183 i -= c; 184 if (i < 0) 185 i += table_size[t->size_index]; 186 } 187 if (dsize != NULL) 188 *dsize = 0; 189 return NULL; 190 } 191 192 void *hashtable_remove (hashtable_t *t, int key, int *dsize) 193 { 194 int i, c; 195 void *temp; 196 197 i = hash (key, t->size_index); 198 while (t->table[i].valid) 199 { 200 if ((t->table[i].key == key) && !t->table[i].dirty) 201 { 202 if (dsize != NULL) 203 *dsize = t->table[i].dsize; 204 temp = t->table[i].data; 205 t->table[i].dirty = 1; 206 t->dirty++; 207 if ((t->dirty > ((1 - t->max_load) * 208 table_size[t->size_index])) && t->size_index) 209 hashtable_rebuild (t, -1); 210 return temp; 211 } 212 c = rehash (key, t->size_index); 213 i -= c; 214 if (i < 0) 215 i += table_size[t->size_index]; 216 } 217 if (dsize != NULL) 218 *dsize = 0; 219 return NULL; 220 } 221 222 /* 223 void hashtable_print (hashtable_t *t) 224 { 225 int i; 226 227 printf ("used: %d\ndirty: %d\n\n", t->used, t->dirty); 228 for (i = 0; i < table_size[t->size_index]; i++) 229 printf ("%3d: %d %d %3d %3d %3d\n", i, t->table[i].valid, 230 t->table[i].dirty, t->table[i].key, 231 t->table[i].data, t->table[i].dsize); 232 } 233 */ 234