| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 | /* * The hashcode handling code below is heavily inspired in libiberty's * hashtab code, but with most adaptation points and support for * deleting elements removed. * * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. * Contributed by Vladimir Makarov (vmakarov@cygnus.com). */#ifndef INLINE_HASHTAB_H# define INLINE_HASHTAB_H 1static __always_inline unsigned longhigher_prime_number(unsigned long n){	/* These are primes that are near, but slightly smaller than, a power of two. */	static const unsigned long primes[] = {		7,		13,		31,		61,		127,		251,		509,		1021,		2039,		4093,		8191,		16381,		32749,		65521,		131071,		262139,		524287,		1048573,		2097143,		4194301,		8388593,		16777213,		33554393,		67108859,		134217689,		268435399,		536870909,		1073741789,		/* 4294967291 */		((unsigned long) 2147483647) + ((unsigned long) 2147483644),	};	const unsigned long *low = &primes[0];	const unsigned long *high = &primes[ARRAY_SIZE(primes)];	while (low != high) {		const unsigned long *mid = low + (high - low) / 2;		if (n > *mid)			low = mid + 1;		else			high = mid;	}#if 0	/* If we've run out of primes, abort.  */	if (n > *low) {		fprintf(stderr, "Cannot find prime bigger than %lu\n", n);		abort();	}#endif	return *low;}struct funcdesc_ht{	/* Table itself */	void **entries;	/* Current size (in entries) of the hash table */	size_t size;	/* Current number of elements */	size_t n_elements;};static __always_inline struct funcdesc_ht *htab_create(void){	struct funcdesc_ht *ht = _dl_malloc(sizeof(*ht));	size_t ent_size;	if (!ht)		return NULL;	ht->size = 3;	ent_size = sizeof(void *) * ht->size;	ht->entries = _dl_malloc(ent_size);	if (!ht->entries)		return NULL;	ht->n_elements = 0;	_dl_memset(ht->entries, 0, ent_size);	return ht;}/* * This is only called from _dl_loadaddr_unmap, so it's safe to call * _dl_free().  See the discussion below. */static __always_inline voidhtab_delete(struct funcdesc_ht *htab){	size_t i;	for (i = htab->size - 1; i >= 0; i--)		if (htab->entries[i])			_dl_free(htab->entries[i]);	_dl_free(htab->entries);	_dl_free(htab);}/* * Similar to htab_find_slot, but without several unwanted side effects: *  - Does not call htab->eq_f when it finds an existing entry. *  - Does not change the count of elements/searches/collisions in the *    hash table. * This function also assumes there are no deleted entries in the table. * HASH is the hash value for the element to be inserted. */static __always_inline void **find_empty_slot_for_expand(struct funcdesc_ht *htab, int hash){	size_t size = htab->size;	unsigned int index = hash % size;	void **slot = htab->entries + index;	int hash2;	if (!*slot)		return slot;	hash2 = 1 + hash % (size - 2);	for (;;) {		index += hash2;		if (index >= size)			index -= size;		slot = htab->entries + index;		if (!*slot)			return slot;	}}/* * The following function changes size of memory allocated for the * entries and repeatedly inserts the table elements.  The occupancy * of the table after the call will be about 50%.  Naturally the hash * table must already exist.  Remember also that the place of the * table entries is changed.  If memory allocation failures are allowed, * this function will return zero, indicating that the table could not be * expanded.  If all goes well, it will return a non-zero value. */static __always_inline inthtab_expand(struct funcdesc_ht *htab, int (*hash_fn) (void *)){	void **oentries;	void **olimit;	void **p;	void **nentries;	size_t nsize;	oentries = htab->entries;	olimit = oentries + htab->size;	/*	 * Resize only when table after removal of unused elements is either	 * too full or too empty.	 */	if (htab->n_elements * 2 > htab->size)		nsize = higher_prime_number(htab->n_elements * 2);	else		nsize = htab->size;	nentries = _dl_malloc(sizeof(*nentries) * nsize);	_dl_memset(nentries, 0, sizeof(*nentries) * nsize);	if (nentries == NULL)		return 0;	htab->entries = nentries;	htab->size = nsize;	p = oentries;	do {		if (*p)			*find_empty_slot_for_expand(htab, hash_fn(*p)) = *p;		p++;	} while (p < olimit);#if 0	/*	 * We can't tell whether this was allocated by the _dl_malloc()	 * built into ld.so or malloc() in the main executable or libc,	 * and calling free() for something that wasn't malloc()ed could	 * do Very Bad Things (TM).  Take the conservative approach	 * here, potentially wasting as much memory as actually used by	 * the hash table, even if multiple growths occur.  That's not	 * so bad as to require some overengineered solution that would	 * enable us to keep track of how it was allocated.	 */	_dl_free(oentries);#endif	return 1;}/* * This function searches for a hash table slot containing an entry * equal to the given element.  To delete an entry, call this with * INSERT = 0, then call htab_clear_slot on the slot returned (possibly * after doing some checks).  To insert an entry, call this with * INSERT = 1, then write the value you want into the returned slot. * When inserting an entry, NULL may be returned if memory allocation * fails. */static __always_inline void **htab_find_slot(struct funcdesc_ht *htab, void *ptr, int insert,	       int (*hash_fn)(void *), int (*eq_fn)(void *, void *)){	unsigned int index;	int hash, hash2;	size_t size;	void **entry;	if (htab->size * 3 <= htab->n_elements * 4 &&	    htab_expand(htab, hash_fn) == 0)		return NULL;	hash = hash_fn(ptr);	size = htab->size;	index = hash % size;	entry = &htab->entries[index];	if (!*entry)		goto empty_entry;	else if (eq_fn(*entry, ptr))		return entry;	hash2 = 1 + hash % (size - 2);	for (;;) {		index += hash2;		if (index >= size)			index -= size;		entry = &htab->entries[index];		if (!*entry)			goto empty_entry;		else if (eq_fn(*entry, ptr))			return entry;	} empty_entry:	if (!insert)		return NULL;	htab->n_elements++;	return entry;}#endif
 |