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