X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=libiberty%2Fhashtab.c;h=3896328717a37d3b04bc6cfa58348f56af6c8a93;hb=49a19cfd34783bd7d261bb0caa4ffcda5aa44b96;hp=89bfe085be985ee41fa0f47d73bbf83c96d1962b;hpb=0ed5305d8db372b0bbaca3401326b04d19786b51;p=gcc.git diff --git a/libiberty/hashtab.c b/libiberty/hashtab.c index 89bfe085be9..3896328717a 100644 --- a/libiberty/hashtab.c +++ b/libiberty/hashtab.c @@ -1,5 +1,5 @@ /* An expandable hash tables datatype. - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Vladimir Makarov (vmakarov@cygnus.com). This file is part of the libiberty library. @@ -80,8 +80,7 @@ higher_prime_number (n) { /* These are primes that are near, but slightly smaller than, a power of two. */ - static unsigned long primes[] = { - (unsigned long) 2, + static const unsigned long primes[] = { (unsigned long) 7, (unsigned long) 13, (unsigned long) 31, @@ -115,12 +114,12 @@ higher_prime_number (n) ((unsigned long) 2147483647) + ((unsigned long) 2147483644), }; - unsigned long* low = &primes[0]; - unsigned long* high = &primes[sizeof(primes) / sizeof(primes[0])]; + const unsigned long *low = &primes[0]; + const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])]; while (low != high) { - unsigned long* mid = low + (high - low) / 2; + const unsigned long *mid = low + (high - low) / 2; if (n > *mid) low = mid + 1; else @@ -159,62 +158,119 @@ eq_pointer (p1, p2) /* This function creates table with length slightly longer than given source length. Created hash table is initiated as empty (all the hash table entries are EMPTY_ENTRY). The function returns the - created hash table. Memory allocation must not fail. */ + created hash table, or NULL if memory allocation fails. */ htab_t -htab_create (size, hash_f, eq_f, del_f) +htab_create_alloc (size, hash_f, eq_f, del_f, alloc_f, free_f) size_t size; htab_hash hash_f; htab_eq eq_f; htab_del del_f; + htab_alloc alloc_f; + htab_free free_f; { htab_t result; size = higher_prime_number (size); - result = (htab_t) xcalloc (1, sizeof (struct htab)); - result->entries = (PTR *) xcalloc (size, sizeof (PTR)); + result = (htab_t) (*alloc_f) (1, sizeof (struct htab)); + if (result == NULL) + return NULL; + result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR)); + if (result->entries == NULL) + { + if (free_f != NULL) + (*free_f) (result); + return NULL; + } result->size = size; result->hash_f = hash_f; result->eq_f = eq_f; result->del_f = del_f; - result->return_allocation_failure = 0; + result->alloc_f = alloc_f; + result->free_f = free_f; return result; } -/* This function creates table with length slightly longer than given - source length. The created hash table is initiated as empty (all the - hash table entries are EMPTY_ENTRY). The function returns the created - hash table. Memory allocation may fail; it may return NULL. */ +/* As above, but use the variants of alloc_f and free_f which accept + an extra argument. */ htab_t -htab_try_create (size, hash_f, eq_f, del_f) +htab_create_alloc_ex (size, hash_f, eq_f, del_f, alloc_arg, alloc_f, + free_f) size_t size; htab_hash hash_f; htab_eq eq_f; htab_del del_f; + PTR alloc_arg; + htab_alloc_with_arg alloc_f; + htab_free_with_arg free_f; { htab_t result; size = higher_prime_number (size); - result = (htab_t) calloc (1, sizeof (struct htab)); + result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab)); if (result == NULL) return NULL; - - result->entries = (PTR *) calloc (size, sizeof (PTR)); + result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR)); if (result->entries == NULL) { - free (result); + if (free_f != NULL) + (*free_f) (alloc_arg, result); return NULL; } - result->size = size; result->hash_f = hash_f; result->eq_f = eq_f; result->del_f = del_f; - result->return_allocation_failure = 1; + result->alloc_arg = alloc_arg; + result->alloc_with_arg_f = alloc_f; + result->free_with_arg_f = free_f; return result; } +/* Update the function pointers and allocation parameter in the htab_t. */ + +void +htab_set_functions_ex (htab, hash_f, eq_f, del_f, alloc_arg, alloc_f, free_f) + htab_t htab; + htab_hash hash_f; + htab_eq eq_f; + htab_del del_f; + PTR alloc_arg; + htab_alloc_with_arg alloc_f; + htab_free_with_arg free_f; +{ + htab->hash_f = hash_f; + htab->eq_f = eq_f; + htab->del_f = del_f; + htab->alloc_arg = alloc_arg; + htab->alloc_with_arg_f = alloc_f; + htab->free_with_arg_f = free_f; +} + +/* These functions exist solely for backward compatibility. */ + +#undef htab_create +htab_t +htab_create (size, hash_f, eq_f, del_f) + size_t size; + htab_hash hash_f; + htab_eq eq_f; + htab_del del_f; +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free); +} + +htab_t +htab_try_create (size, hash_f, eq_f, del_f) + size_t size; + htab_hash hash_f; + htab_eq eq_f; + htab_del del_f; +{ + return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free); +} + /* This function frees all memory allocated for given hash table. Naturally the hash table must already exist. */ @@ -230,8 +286,16 @@ htab_delete (htab) && htab->entries[i] != DELETED_ENTRY) (*htab->del_f) (htab->entries[i]); - free (htab->entries); - free (htab); + if (htab->free_f != NULL) + { + (*htab->free_f) (htab->entries); + (*htab->free_f) (htab); + } + else if (htab->free_with_arg_f != NULL) + { + (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries); + (*htab->free_with_arg_f) (htab->alloc_arg, htab); + } } /* This function clears all entries in the given hash table. */ @@ -264,21 +328,27 @@ find_empty_slot_for_expand (htab, hash) hashval_t hash; { size_t size = htab->size; - hashval_t hash2 = 1 + hash % (size - 2); unsigned int index = hash % size; + PTR *slot = htab->entries + index; + hashval_t hash2; + if (*slot == EMPTY_ENTRY) + return slot; + else if (*slot == DELETED_ENTRY) + abort (); + + hash2 = 1 + hash % (size - 2); for (;;) { - PTR *slot = htab->entries + index; + index += hash2; + if (index >= size) + index -= size; + slot = htab->entries + index; if (*slot == EMPTY_ENTRY) return slot; else if (*slot == DELETED_ENTRY) abort (); - - index += hash2; - if (index >= size) - index -= size; } } @@ -297,21 +367,30 @@ htab_expand (htab) PTR *oentries; PTR *olimit; PTR *p; + PTR *nentries; + size_t nsize; oentries = htab->entries; olimit = oentries + htab->size; - htab->size = higher_prime_number (htab->size * 2); + /* Resize only when table after removal of unused elements is either + too full or too empty. */ + if ((htab->n_elements - htab->n_deleted) * 2 > htab->size + || ((htab->n_elements - htab->n_deleted) * 8 < htab->size + && htab->size > 32)) + nsize = higher_prime_number ((htab->n_elements - htab->n_deleted) * 2); + else + nsize = htab->size; - if (htab->return_allocation_failure) - { - PTR *nentries = (PTR *) calloc (htab->size, sizeof (PTR *)); - if (nentries == NULL) - return 0; - htab->entries = nentries; - } + if (htab->alloc_with_arg_f != NULL) + nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, + sizeof (PTR *)); else - htab->entries = (PTR *) xcalloc (htab->size, sizeof (PTR *)); + nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); + if (nentries == NULL) + return 0; + htab->entries = nentries; + htab->size = nsize; htab->n_elements -= htab->n_deleted; htab->n_deleted = 0; @@ -332,7 +411,10 @@ htab_expand (htab) } while (p < olimit); - free (oentries); + if (htab->free_f != NULL) + (*htab->free_f) (oentries); + else if (htab->free_with_arg_f != NULL) + (*htab->free_with_arg_f) (htab->alloc_arg, oentries); return 1; } @@ -405,50 +487,59 @@ htab_find_slot_with_hash (htab, element, hash, insert) unsigned int index; hashval_t hash2; size_t size; + PTR entry; if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4 && htab_expand (htab) == 0) return NULL; size = htab->size; - hash2 = 1 + hash % (size - 2); index = hash % size; htab->searches++; first_deleted_slot = NULL; + entry = htab->entries[index]; + if (entry == EMPTY_ENTRY) + goto empty_entry; + else if (entry == DELETED_ENTRY) + first_deleted_slot = &htab->entries[index]; + else if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + + hash2 = 1 + hash % (size - 2); for (;;) { - PTR entry = htab->entries[index]; + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; + + entry = htab->entries[index]; if (entry == EMPTY_ENTRY) - { - if (insert == NO_INSERT) - return NULL; - - htab->n_elements++; - - if (first_deleted_slot) - { - *first_deleted_slot = EMPTY_ENTRY; - return first_deleted_slot; - } - - return &htab->entries[index]; - } - - if (entry == DELETED_ENTRY) + goto empty_entry; + else if (entry == DELETED_ENTRY) { if (!first_deleted_slot) first_deleted_slot = &htab->entries[index]; } - else if ((*htab->eq_f) (entry, element)) + else if ((*htab->eq_f) (entry, element)) return &htab->entries[index]; - - htab->collisions++; - index += hash2; - if (index >= size) - index -= size; } + + empty_entry: + if (insert == NO_INSERT) + return NULL; + + htab->n_elements++; + + if (first_deleted_slot) + { + *first_deleted_slot = EMPTY_ENTRY; + return first_deleted_slot; + } + + return &htab->entries[index]; } /* Like htab_find_slot_with_hash, but compute the hash value from the @@ -512,13 +603,16 @@ htab_clear_slot (htab, slot) argument. */ void -htab_traverse (htab, callback, info) +htab_traverse_noresize (htab, callback, info) htab_t htab; htab_trav callback; PTR info; { - PTR *slot = htab->entries; - PTR *limit = slot + htab->size; + PTR *slot; + PTR *limit; + + slot = htab->entries; + limit = slot + htab->size; do { @@ -531,6 +625,21 @@ htab_traverse (htab, callback, info) while (++slot < limit); } +/* Like htab_traverse_noresize, but does resize the table when it is + too empty to improve effectivity of subsequent calls. */ + +void +htab_traverse (htab, callback, info) + htab_t htab; + htab_trav callback; + PTR info; +{ + if ((htab->n_elements - htab->n_deleted) * 8 < htab->size) + htab_expand (htab); + + htab_traverse_noresize (htab, callback, info); +} + /* Return the current size of given hash table. */ size_t @@ -600,3 +709,141 @@ htab_hash_string (p) return r; } + +/* DERIVED FROM: +-------------------------------------------------------------------- +lookup2.c, by Bob Jenkins, December 1996, Public Domain. +hash(), hash2(), hash3, and mix() are externally useful functions. +Routines to test the hash are included if SELF_TEST is defined. +You can use this free for any purpose. It has no warranty. +-------------------------------------------------------------------- +*/ + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bit set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +/* same, but slower, works on systems that might have 8 byte hashval_t's */ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<< 8); \ + c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ + a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ + b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ + a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ + b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ + c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ +} + +/* +-------------------------------------------------------------------- +hash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + level : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 36+6len instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (ub1 **)k, do it like this: + for (i=0, h=0; i= 12) /* aligned */ + { + a += *(hashval_t *)(k+0); + b += *(hashval_t *)(k+4); + c += *(hashval_t *)(k+8); + mix(a,b,c); + k += 12; len -= 12; + } + else /* unaligned */ +#endif + while (len >= 12) + { + a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); + b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); + c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch(len) /* all the case statements fall through */ + { + case 11: c+=((hashval_t)k[10]<<24); + case 10: c+=((hashval_t)k[9]<<16); + case 9 : c+=((hashval_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b+=((hashval_t)k[7]<<24); + case 7 : b+=((hashval_t)k[6]<<16); + case 6 : b+=((hashval_t)k[5]<<8); + case 5 : b+=k[4]; + case 4 : a+=((hashval_t)k[3]<<24); + case 3 : a+=((hashval_t)k[2]<<16); + case 2 : a+=((hashval_t)k[1]<<8); + case 1 : a+=k[0]; + /* case 0: nothing left to add */ + } + mix(a,b,c); + /*-------------------------------------------- report the result */ + return c; +}