1 /* Fixed size hash table with internal linking. 2 Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. 3 This file is part of elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2000. 5 6 This file is free software; you can redistribute it and/or modify 7 it under the terms of either 8 9 * the GNU Lesser General Public License as published by the Free 10 Software Foundation; either version 3 of the License, or (at 11 your option) any later version 12 13 or 14 15 * the GNU General Public License as published by the Free 16 Software Foundation; either version 2 of the License, or (at 17 your option) any later version 18 19 or both in parallel, as here. 20 21 elfutils is distributed in the hope that it will be useful, but 22 WITHOUT ANY WARRANTY; without even the implied warranty of 23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 General Public License for more details. 25 26 You should have received copies of the GNU General Public License and 27 the GNU Lesser General Public License along with this program. If 28 not, see <http://www.gnu.org/licenses/>. */ 29 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/cdefs.h> 34 #include <sys/param.h> 35 36 #include <system.h> 37 38 #define CONCAT(t1,t2) __CONCAT (t1,t2) 39 40 /* Before including this file the following macros must be defined: 41 42 TYPE data type of the hash table entries 43 HASHFCT name of the hashing function to use 44 HASHTYPE type used for the hashing value 45 COMPARE comparison function taking two pointers to TYPE objects 46 CLASS can be defined to `static' to avoid exporting the functions 47 PREFIX prefix to be used for function and data type names 48 STORE_POINTER if defined the table stores a pointer and not an element 49 of type TYPE 50 INSERT_HASH if defined alternate insert function which takes a hash 51 value is defined 52 NO_FINI_FCT if defined the fini function is not defined 53 */ 54 55 56 /* Defined separately. */ 57 extern size_t next_prime (size_t seed); 58 59 60 /* Set default values. */ 61 #ifndef HASHTYPE 62 # define HASHTYPE size_t 63 #endif 64 65 #ifndef CLASS 66 # define CLASS 67 #endif 68 69 #ifndef PREFIX 70 # define PREFIX 71 #endif 72 73 74 /* The data structure. */ 75 struct CONCAT(PREFIX,fshash) 76 { 77 size_t nslots; 78 struct CONCAT(PREFIX,fshashent) 79 { 80 HASHTYPE hval; 81 #ifdef STORE_POINTER 82 # define ENTRYP(el) (el).entry 83 TYPE *entry; 84 #else 85 # define ENTRYP(el) &(el).entry 86 TYPE entry; 87 #endif 88 } table[0]; 89 }; 90 91 92 /* Constructor for the hashing table. */ 93 CLASS struct CONCAT(PREFIX,fshash) * 94 CONCAT(PREFIX,fshash_init) (size_t nelems) 95 { 96 struct CONCAT(PREFIX,fshash) *result; 97 /* We choose a size for the hashing table 150% over the number of 98 entries. This will guarantee short medium search lengths. */ 99 const size_t max_size_t = ~((size_t) 0); 100 101 if (nelems >= (max_size_t / 3) * 2) 102 { 103 errno = EINVAL; 104 return NULL; 105 } 106 107 /* Adjust the size to be used for the hashing table. */ 108 nelems = next_prime (MAX ((nelems * 3) / 2, 10)); 109 110 /* Allocate the data structure for the result. */ 111 result = (struct CONCAT(PREFIX,fshash) *) 112 xcalloc (sizeof (struct CONCAT(PREFIX,fshash)) 113 + (nelems + 1) * sizeof (struct CONCAT(PREFIX,fshashent)), 1); 114 if (result == NULL) 115 return NULL; 116 117 result->nslots = nelems; 118 119 return result; 120 } 121 122 123 #ifndef NO_FINI_FCT 124 CLASS void 125 CONCAT(PREFIX,fshash_fini) (struct CONCAT(PREFIX,fshash) *htab) 126 { 127 free (htab); 128 } 129 #endif 130 131 132 static struct CONCAT(PREFIX,fshashent) * 133 CONCAT(PREFIX,fshash_lookup) (struct CONCAT(PREFIX,fshash) *htab, 134 HASHTYPE hval, TYPE *data) 135 { 136 size_t idx = 1 + hval % htab->nslots; 137 138 if (htab->table[idx].hval != 0) 139 { 140 HASHTYPE hash; 141 142 /* See whether this is the same entry. */ 143 if (htab->table[idx].hval == hval 144 && COMPARE (data, ENTRYP (htab->table[idx])) == 0) 145 return &htab->table[idx]; 146 147 /* Second hash function as suggested in [Knuth]. */ 148 hash = 1 + hval % (htab->nslots - 2); 149 150 do 151 { 152 if (idx <= hash) 153 idx = htab->nslots + idx - hash; 154 else 155 idx -= hash; 156 157 if (htab->table[idx].hval == hval 158 && COMPARE (data, ENTRYP(htab->table[idx])) == 0) 159 return &htab->table[idx]; 160 } 161 while (htab->table[idx].hval != 0); 162 } 163 164 return &htab->table[idx]; 165 } 166 167 168 CLASS int 169 __attribute__ ((unused)) 170 CONCAT(PREFIX,fshash_insert) (struct CONCAT(PREFIX,fshash) *htab, 171 const char *str, 172 size_t len __attribute__ ((unused)), TYPE *data) 173 { 174 HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); 175 struct CONCAT(PREFIX,fshashent) *slot; 176 177 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); 178 if (slot->hval != 0) 179 /* We don't want to overwrite the old value. */ 180 return -1; 181 182 slot->hval = hval; 183 #ifdef STORE_POINTER 184 slot->entry = data; 185 #else 186 slot->entry = *data; 187 #endif 188 189 return 0; 190 } 191 192 193 #ifdef INSERT_HASH 194 CLASS int 195 __attribute__ ((unused)) 196 CONCAT(PREFIX,fshash_insert_hash) (struct CONCAT(PREFIX,fshash) *htab, 197 HASHTYPE hval, TYPE *data) 198 { 199 struct CONCAT(PREFIX,fshashent) *slot; 200 201 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); 202 if (slot->hval != 0) 203 /* We don't want to overwrite the old value. */ 204 return -1; 205 206 slot->hval = hval; 207 #ifdef STORE_POINTER 208 slot->entry = data; 209 #else 210 slot->entry = *data; 211 #endif 212 213 return 0; 214 } 215 #endif 216 217 218 CLASS int 219 __attribute__ ((unused)) 220 CONCAT(PREFIX,fshash_overwrite) (struct CONCAT(PREFIX,fshash) *htab, 221 const char *str, 222 size_t len __attribute__ ((unused)), 223 TYPE *data) 224 { 225 HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); 226 struct CONCAT(PREFIX,fshashent) *slot; 227 228 slot = CONCAT(PREFIX,fshash_lookup) (htab, hval, data); 229 slot->hval = hval; 230 #ifdef STORE_POINTER 231 slot->entry = data; 232 #else 233 slot->entry = *data; 234 #endif 235 236 return 0; 237 } 238 239 240 CLASS const TYPE * 241 CONCAT(PREFIX,fshash_find) (const struct CONCAT(PREFIX,fshash) *htab, 242 const char *str, 243 size_t len __attribute__ ((unused)), TYPE *data) 244 { 245 HASHTYPE hval = HASHFCT (str, len ?: strlen (str)); 246 struct CONCAT(PREFIX,fshashent) *slot; 247 248 slot = CONCAT(PREFIX,fshash_lookup) ((struct CONCAT(PREFIX,fshash) *) htab, 249 hval, data); 250 if (slot->hval == 0) 251 /* Not found. */ 252 return NULL; 253 254 return ENTRYP(*slot); 255 } 256 257 258 /* Unset the macros we expect. */ 259 #undef TYPE 260 #undef HASHFCT 261 #undef HASHTYPE 262 #undef COMPARE 263 #undef CLASS 264 #undef PREFIX 265 #undef INSERT_HASH 266 #undef STORE_POINTER 267 #undef NO_FINI_FCT 268