Makefile.in (CFILES): Add hashtab.c
* Makefile.in (CFILES): Add hashtab.c (REQUIRED_OFILES): Add hashtab.o (hashtab.o): Add dependencies. * hashtab.c: New file From-SVN: r30012
This commit is contained in:
parent
005a696e18
commit
a2f945c649
3 changed files with 302 additions and 3 deletions
|
@ -1,3 +1,10 @@
|
|||
Fri Oct 15 01:47:51 1999 Vladimir Makarov <vmakarov@loony.cygnus.com>
|
||||
|
||||
* Makefile.in (CFILES): Add hashtab.c
|
||||
(REQUIRED_OFILES): Add hashtab.o
|
||||
(hashtab.o): Add dependencies.
|
||||
* hashtab.c: New file
|
||||
|
||||
Wed Oct 13 01:16:47 1999 Mumit Khan <khan@xraylith.wisc.edu>
|
||||
|
||||
* basename.c (DIR_SEPARATOR): New macro.
|
||||
|
|
|
@ -123,7 +123,7 @@ HFILES = alloca-conf.h
|
|||
CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c \
|
||||
bzero.c calloc.c choose-temp.c clock.c concat.c cplus-dem.c fdmatch.c \
|
||||
fnmatch.c getcwd.c getpwd.c getopt.c getopt1.c getpagesize.c \
|
||||
getruntime.c floatformat.c hex.c index.c insque.c memchr.c \
|
||||
getruntime.c floatformat.c hashtab.c hex.c index.c insque.c memchr.c \
|
||||
memcmp.c memcpy.c memmove.c memset.c mkstemps.c objalloc.c obstack.c \
|
||||
pexecute.c putenv.c random.c rename.c rindex.c setenv.c sigsetmask.c \
|
||||
spaces.c splay-tree.c strcasecmp.c strncasecmp.c strchr.c strdup.c \
|
||||
|
@ -133,8 +133,8 @@ CFILES = asprintf.c alloca.c argv.c atexit.c basename.c bcmp.c bcopy.c \
|
|||
|
||||
# These are always included in the library.
|
||||
REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o \
|
||||
fdmatch.o fnmatch.o getopt.o getopt1.o getpwd.o getruntime.o hex.o \
|
||||
floatformat.o objalloc.o obstack.o pexecute.o spaces.o \
|
||||
fdmatch.o fnmatch.o getopt.o getopt1.o getpwd.o getruntime.o hashtab.o \
|
||||
hex.o floatformat.o objalloc.o obstack.o pexecute.o spaces.o \
|
||||
splay-tree.o strerror.o strsignal.o xatexit.o xexit.o xmalloc.o \
|
||||
xmemdup.o xstrdup.o xstrerror.o
|
||||
|
||||
|
@ -273,3 +273,4 @@ xmalloc.o: $(INCDIR)/libiberty.h
|
|||
xmemdup.o: config.h $(INCDIR)/libiberty.h
|
||||
xstrdup.o: config.h $(INCDIR)/libiberty.h
|
||||
xstrerror.o: config.h $(INCDIR)/libiberty.h
|
||||
hashtab.o: config.h $(INCDIR)/libiberty.h $(INCDIR)/hashtab.h $(INCDIR)/ansidecl.h
|
||||
|
|
291
libiberty/hashtab.c
Normal file
291
libiberty/hashtab.c
Normal file
|
@ -0,0 +1,291 @@
|
|||
/* An expandable hash tables datatype.
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
Contributed by Vladimir Makarov (vmakarov@cygnus.com).
|
||||
|
||||
This file is part of the libiberty library.
|
||||
Libiberty is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
Libiberty is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with libiberty; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This package implements basic hash table functionality. It is possible
|
||||
to search for an entry, create an entry and destroy an entry.
|
||||
|
||||
Elements in the table are generic pointers.
|
||||
|
||||
The size of the table is not fixed; if the occupancy of the table
|
||||
grows too high the hash table will be expanded.
|
||||
|
||||
The abstract data implementation is based on generalized Algorithm D
|
||||
from Knuth's book "The art of computer programming". Hash table is
|
||||
expanded by creation of new hash table and transferring elements from
|
||||
the old table to the new table. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
/* This macro defines reserved value for table entry which contained
|
||||
a deleted element. */
|
||||
|
||||
#define DELETED_ENTRY ((void *) 1)
|
||||
|
||||
/* The following function returns the nearest prime number which is
|
||||
greater than given source number. */
|
||||
|
||||
static unsigned long
|
||||
higher_prime_number (number)
|
||||
unsigned long number;
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (number = (number / 2) * 2 + 3;; number += 2)
|
||||
{
|
||||
for (i = 3; i * i <= number; i += 2)
|
||||
if (number % i == 0)
|
||||
break;
|
||||
if (i * i > number)
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
hash_table_t
|
||||
create_hash_table (size, hash_function, eq_function)
|
||||
size_t size;
|
||||
unsigned (*hash_function) PARAMS ((hash_table_entry_t));
|
||||
int (*eq_function) PARAMS ((hash_table_entry_t, hash_table_entry_t));
|
||||
{
|
||||
hash_table_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->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));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* This function frees all memory allocated for given hash table.
|
||||
Naturally the hash table must already exist. */
|
||||
|
||||
void
|
||||
delete_hash_table (htab)
|
||||
hash_table_t htab;
|
||||
{
|
||||
free (htab->entries);
|
||||
free (htab);
|
||||
}
|
||||
|
||||
/* This function clears all entries in the given hash table. */
|
||||
|
||||
void
|
||||
empty_hash_table (htab)
|
||||
hash_table_t htab;
|
||||
{
|
||||
memset (htab->entries, 0, htab->size * sizeof (hash_table_entry_t));
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
static void
|
||||
expand_hash_table (htab)
|
||||
hash_table_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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
{
|
||||
hash_table_entry_t *entry_ptr;
|
||||
hash_table_entry_t *first_deleted_entry_ptr;
|
||||
unsigned index, hash_value, secondary_hash_value;
|
||||
|
||||
if (htab->size * 3 <= htab->number_of_elements * 4)
|
||||
{
|
||||
all_expansions++;
|
||||
expand_hash_table (htab);
|
||||
}
|
||||
hash_value = (*htab->hash_function) (element);
|
||||
secondary_hash_value = 1 + hash_value % (htab->size - 2);
|
||||
index = hash_value % htab->size;
|
||||
htab->searches++;
|
||||
all_searches++;
|
||||
first_deleted_entry_ptr = NULL;
|
||||
for (;;htab->collisions++, all_collisions++)
|
||||
{
|
||||
entry_ptr = htab->entries + index;
|
||||
if (*entry_ptr == EMPTY_ENTRY)
|
||||
{
|
||||
if (reserve)
|
||||
{
|
||||
htab->number_of_elements++;
|
||||
if (first_deleted_entry_ptr != NULL)
|
||||
{
|
||||
entry_ptr = first_deleted_entry_ptr;
|
||||
*entry_ptr = DELETED_ENTRY;
|
||||
}
|
||||
}
|
||||
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 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). */
|
||||
|
||||
void
|
||||
remove_element_from_hash_table_entry (htab, element)
|
||||
hash_table_t htab;
|
||||
hash_table_entry_t element;
|
||||
{
|
||||
hash_table_entry_t *entry_ptr;
|
||||
|
||||
entry_ptr = find_hash_table_entry (htab, element, 0);
|
||||
*entry_ptr = DELETED_ENTRY;
|
||||
htab->number_of_deleted_elements++;
|
||||
}
|
||||
|
||||
/* The following function returns current size of given hash table. */
|
||||
|
||||
size_t
|
||||
hash_table_size (htab)
|
||||
hash_table_t htab;
|
||||
{
|
||||
return htab->size;
|
||||
}
|
||||
|
||||
/* The following function returns current number of elements in given
|
||||
hash table. */
|
||||
|
||||
size_t
|
||||
hash_table_elements_number (htab)
|
||||
hash_table_t htab;
|
||||
{
|
||||
return htab->number_of_elements - htab->number_of_deleted_elements;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
{
|
||||
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;
|
||||
}
|
Loading…
Add table
Reference in a new issue