diff options
author | Jason Merrill <jason@redhat.com> | 2000-03-24 21:31:22 +0000 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2000-03-24 21:31:22 +0000 |
commit | b4fe2683639c4ac8a5a53576d1c7e020b6b7d05e (patch) | |
tree | 277d71524916ab66b2041249e09c6cefa14bc0f6 /libiberty/hashtab.c | |
parent | a91f7ea9baf74ec6527944b0b69c23c9c9b238bd (diff) | |
download | gdb-b4fe2683639c4ac8a5a53576d1c7e020b6b7d05e.zip gdb-b4fe2683639c4ac8a5a53576d1c7e020b6b7d05e.tar.gz gdb-b4fe2683639c4ac8a5a53576d1c7e020b6b7d05e.tar.bz2 |
merge from gcc
Diffstat (limited to 'libiberty/hashtab.c')
-rw-r--r-- | libiberty/hashtab.c | 431 |
1 files changed, 265 insertions, 166 deletions
diff --git a/libiberty/hashtab.c b/libiberty/hashtab.c index 3f5b303..16c5d3e 100644 --- a/libiberty/hashtab.c +++ b/libiberty/hashtab.c @@ -46,25 +46,9 @@ Boston, MA 02111-1307, USA. */ #include "libiberty.h" #include "hashtab.h" -/* The following variable is used for debugging. Its value is number - of all calls of `find_hash_table_entry' for all hash tables. */ - -static int all_searches = 0; - -/* The following variable is used for debugging. Its value is number - of collisions fixed for time of work with all hash tables. */ - -static int all_collisions = 0; - -/* The following variable is used for debugging. Its value is number - of all table expansions fixed for time of work with all hash - tables. */ - -static int all_expansions = 0; - /* This macro defines reserved value for empty table entry. */ -#define EMPTY_ENTRY NULL +#define EMPTY_ENTRY ((void *) 0) /* This macro defines reserved value for table entry which contained a deleted element. */ @@ -75,19 +59,27 @@ static int all_expansions = 0; greater than given source number. */ static unsigned long -higher_prime_number (number) - unsigned long number; +higher_prime_number (n) + unsigned long n; { unsigned long i; - for (number = (number / 2) * 2 + 3;; number += 2) + n |= 0x01; /* Force N to be odd. */ + if (n < 9) + return n; /* All odd numbers < 9 are prime. */ + + next: + n += 2; + i = 3; + do { - for (i = 3; i * i <= number; i += 2) - if (number % i == 0) - break; - if (i * i > number) - return number; + if (n % i == 0) + goto next; + i += 2; } + while ((i * i) <= n); + + return n; } /* This function creates table with length slightly longer than given @@ -95,26 +87,22 @@ higher_prime_number (number) hash table entries are EMPTY_ENTRY). The function returns the created hash table. */ -hash_table_t -create_hash_table (size, hash_function, eq_function) +htab_t +htab_create (size, hash_f, eq_f, del_f) size_t size; - unsigned (*hash_function) PARAMS ((hash_table_entry_t)); - int (*eq_function) PARAMS ((hash_table_entry_t, hash_table_entry_t)); + htab_hash hash_f; + htab_eq eq_f; + htab_del del_f; { - hash_table_t result; + htab_t result; size = higher_prime_number (size); - result = (hash_table_t) xmalloc (sizeof (*result)); - result->entries - = (hash_table_entry_t *) xmalloc (size * sizeof (hash_table_entry_t)); + result = (htab_t) xcalloc (1, sizeof (struct htab)); + result->entries = (void **) xcalloc (size, sizeof (void *)); result->size = size; - result->hash_function = hash_function; - result->eq_function = eq_function; - result->number_of_elements = 0; - result->number_of_deleted_elements = 0; - result->searches = 0; - result->collisions = 0; - memset (result->entries, 0, size * sizeof (hash_table_entry_t)); + result->hash_f = hash_f; + result->eq_f = eq_f; + result->del_f = del_f; return result; } @@ -122,9 +110,18 @@ create_hash_table (size, hash_function, eq_function) Naturally the hash table must already exist. */ void -delete_hash_table (htab) - hash_table_t htab; +htab_delete (htab) + htab_t htab; { + int i; + if (htab->del_f) + for (i = htab->size - 1; i >= 0; i--) + { + if (htab->entries[i] != EMPTY_ENTRY + && htab->entries[i] != DELETED_ENTRY) + (*htab->del_f) (htab->entries[i]); + } + free (htab->entries); free (htab); } @@ -132,10 +129,49 @@ delete_hash_table (htab) /* This function clears all entries in the given hash table. */ void -empty_hash_table (htab) - hash_table_t htab; +htab_empty (htab) + htab_t htab; +{ + int i; + if (htab->del_f) + for (i = htab->size - 1; i >= 0; i--) + { + if (htab->entries[i] != EMPTY_ENTRY + && htab->entries[i] != DELETED_ENTRY) + (*htab->del_f) (htab->entries[i]); + } + + memset (htab->entries, 0, htab->size * sizeof (void *)); +} + +/* 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 void ** +find_empty_slot_for_expand (htab, hash) + htab_t htab; + unsigned int hash; { - memset (htab->entries, 0, htab->size * sizeof (hash_table_entry_t)); + size_t size = htab->size; + unsigned int hash2 = 1 + hash % (size - 2); + unsigned int index = hash % size; + + for (;;) + { + void **slot = htab->entries + index; + if (*slot == EMPTY_ENTRY) + return slot; + + if (*slot == DELETED_ENTRY) + abort (); + + index += hash2; + if (index >= size) + index -= size; + } } /* The following function changes size of memory allocated for the @@ -145,121 +181,193 @@ empty_hash_table (htab) table entries is changed. */ static void -expand_hash_table (htab) - hash_table_t htab; +htab_expand (htab) + htab_t htab; { - hash_table_t new_htab; - hash_table_entry_t *entry_ptr; - hash_table_entry_t *new_entry_ptr; - - new_htab = create_hash_table (htab->number_of_elements * 2, - htab->hash_function, htab->eq_function); - for (entry_ptr = htab->entries; entry_ptr < htab->entries + htab->size; - entry_ptr++) - if (*entry_ptr != EMPTY_ENTRY && *entry_ptr != DELETED_ENTRY) - { - new_entry_ptr = find_hash_table_entry (new_htab, *entry_ptr, 1); - *new_entry_ptr = (*entry_ptr); - } - free (htab->entries); - *htab = (*new_htab); - free (new_htab); + void **oentries; + void **olimit; + void **p; + + oentries = htab->entries; + olimit = oentries + htab->size; + + htab->size = higher_prime_number (htab->size * 2); + htab->entries = xcalloc (htab->size, sizeof (void **)); + + htab->n_elements -= htab->n_deleted; + htab->n_deleted = 0; + + p = oentries; + do + { + void *x = *p; + if (x != EMPTY_ENTRY && x != DELETED_ENTRY) + { + void **q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); + *q = x; + } + p++; + } + while (p < olimit); + free (oentries); } -/* This function searches for hash table entry which contains element - equal to given value or empty entry in which given value can be - placed (if the element with given value does not exist in the - table). The function works in two regimes. The first regime is - used only for search. The second is used for search and - reservation empty entry for given value. The table is expanded if - occupancy (taking into accout also deleted elements) is more than - 75%. Naturally the hash table must already exist. If reservation - flag is TRUE then the element with given value should be inserted - into the table entry before another call of - `find_hash_table_entry'. */ - -hash_table_entry_t * -find_hash_table_entry (htab, element, reserve) - hash_table_t htab; - hash_table_entry_t element; - int reserve; +/* This function searches for a hash table entry equal to the given + element. It cannot be used to insert or delete an element. */ + +void * +htab_find_with_hash (htab, element, hash) + htab_t htab; + const void *element; + unsigned int hash; { - hash_table_entry_t *entry_ptr; - hash_table_entry_t *first_deleted_entry_ptr; - unsigned index, hash_value, secondary_hash_value; + unsigned int index, hash2; + size_t size; - if (htab->size * 3 <= htab->number_of_elements * 4) + htab->searches++; + size = htab->size; + hash2 = 1 + hash % (size - 2); + index = hash % size; + + for (;;) { - all_expansions++; - expand_hash_table (htab); + void *entry = htab->entries[index]; + if (entry == EMPTY_ENTRY) + return NULL; + else if (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)) + return entry; + + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; } - hash_value = (*htab->hash_function) (element); - secondary_hash_value = 1 + hash_value % (htab->size - 2); - index = hash_value % htab->size; +} + +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ +void * +htab_find (htab, element) + htab_t htab; + const void *element; +{ + return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); +} + +/* 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. */ + +void ** +htab_find_slot_with_hash (htab, element, hash, insert) + htab_t htab; + const void *element; + unsigned int hash; + int insert; +{ + void **first_deleted_slot; + unsigned int index, hash2; + size_t size; + + if (insert && htab->size * 3 <= htab->n_elements * 4) + htab_expand (htab); + + size = htab->size; + hash2 = 1 + hash % (size - 2); + index = hash % size; + htab->searches++; - all_searches++; - first_deleted_entry_ptr = NULL; - for (;;htab->collisions++, all_collisions++) + first_deleted_slot = NULL; + + for (;;) { - entry_ptr = htab->entries + index; - if (*entry_ptr == EMPTY_ENTRY) - { - if (reserve) + void *entry = htab->entries[index]; + if (entry == EMPTY_ENTRY) + { + if (!insert) + return NULL; + + htab->n_elements++; + + if (first_deleted_slot) { - htab->number_of_elements++; - if (first_deleted_entry_ptr != NULL) - { - entry_ptr = first_deleted_entry_ptr; - *entry_ptr = EMPTY_ENTRY; - } + *first_deleted_slot = EMPTY_ENTRY; + return first_deleted_slot; } - break; - } - else if (*entry_ptr != DELETED_ENTRY) - { - if ((*htab->eq_function) (*entry_ptr, element)) - break; - } - else if (first_deleted_entry_ptr == NULL) - first_deleted_entry_ptr = entry_ptr; - index += secondary_hash_value; - if (index >= htab->size) - index -= htab->size; + + return &htab->entries[index]; + } + + if (entry == DELETED_ENTRY) + { + if (!first_deleted_slot) + first_deleted_slot = &htab->entries[index]; + } + else + { + if ((*htab->eq_f) (entry, element)) + return &htab->entries[index]; + } + + htab->collisions++; + index += hash2; + if (index >= size) + index -= size; } - return entry_ptr; } -/* This function deletes element with given value from hash table. - The hash table entry value will be `DELETED_ENTRY' after the - function call. Naturally the hash table must already exist. Hash - table entry for given value should be not empty (or deleted). */ +/* Like htab_find_slot_with_hash, but compute the hash value from the + element. */ +void ** +htab_find_slot (htab, element, insert) + htab_t htab; + const void *element; + int insert; +{ + return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), + insert); +} + +/* This function deletes an element with the given value from hash + table. If there is no matching element in the hash table, this + function does nothing. */ void -remove_element_from_hash_table_entry (htab, element) - hash_table_t htab; - hash_table_entry_t element; +htab_remove_elt (htab, element) + htab_t htab; + void *element; { - hash_table_entry_t *entry_ptr; + void **slot; + + slot = htab_find_slot (htab, element, 0); + if (*slot == EMPTY_ENTRY) + return; + + if (htab->del_f) + (*htab->del_f) (*slot); - entry_ptr = find_hash_table_entry (htab, element, 0); - *entry_ptr = DELETED_ENTRY; - htab->number_of_deleted_elements++; + *slot = DELETED_ENTRY; + htab->n_deleted++; } -/* This function clears a specified slot in a hash table. - It is useful when you've already done the lookup and don't want to - do it again. */ +/* This function clears a specified slot in a hash table. It is + useful when you've already done the lookup and don't want to do it + again. */ void -clear_hash_table_slot (htab, slot) - hash_table_t htab; - hash_table_entry_t *slot; +htab_clear_slot (htab, slot) + htab_t htab; + void **slot; { if (slot < htab->entries || slot >= htab->entries + htab->size || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY) abort (); + if (htab->del_f) + (*htab->del_f) (*slot); *slot = DELETED_ENTRY; - htab->number_of_deleted_elements++; + htab->n_deleted++; } /* This function scans over the entire hash table calling @@ -268,24 +376,29 @@ clear_hash_table_slot (htab, slot) argument. */ void -traverse_hash_table (htab, callback, info) - hash_table_t htab; - int (*callback) PARAMS ((hash_table_entry_t, void *)); +htab_traverse (htab, callback, info) + htab_t htab; + htab_trav callback; void *info; { - hash_table_entry_t *entry_ptr; - for (entry_ptr = htab->entries; entry_ptr < htab->entries + htab->size; - entry_ptr++) - if (*entry_ptr != EMPTY_ENTRY && *entry_ptr != DELETED_ENTRY) - if (!callback (*entry_ptr, info)) - break; + void **slot, **limit; + slot = htab->entries; + limit = slot + htab->size; + do + { + void *x = *slot; + if (x != EMPTY_ENTRY && x != DELETED_ENTRY) + if (!(*callback) (slot, info)) + break; + } + while (++slot < limit); } /* The following function returns current size of given hash table. */ size_t -hash_table_size (htab) - hash_table_t htab; +htab_size (htab) + htab_t htab; { return htab->size; } @@ -294,37 +407,23 @@ hash_table_size (htab) hash table. */ size_t -hash_table_elements_number (htab) - hash_table_t htab; +htab_elements (htab) + htab_t htab; { - return htab->number_of_elements - htab->number_of_deleted_elements; + return htab->n_elements - htab->n_deleted; } /* The following function returns number of percents of fixed collisions during all work with given hash table. */ -int -hash_table_collisions (htab) - hash_table_t htab; +double +htab_collisions (htab) + htab_t htab; { int searches; searches = htab->searches; if (searches == 0) - searches++; - return htab->collisions * 100 / searches; -} - -/* The following function returns number of percents of fixed - collisions during all work with all hash tables. */ - -int -all_hash_table_collisions () -{ - int searches; - - searches = all_searches; - if (searches == 0) - searches++; - return all_collisions * 100 / searches; + return 0.0; + return (double)htab->collisions / (double)searches; } |