mirror of
https://github.com/containers/fuse-overlayfs.git
synced 2025-09-09 15:24:54 -04:00
lib: update hash library
it was relicensed as LGPLv2+ upstream in gnulib. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
db404d85d4
commit
cc1b0e2d34
154
lib/hash.c
154
lib/hash.c
@ -1,20 +1,20 @@
|
|||||||
/* hash - hashing table processing.
|
/* hash - hashing table processing.
|
||||||
|
|
||||||
Copyright (C) 1998-2004, 2006-2007, 2009-2019 Free Software Foundation, Inc.
|
Copyright (C) 1998-2004, 2006-2007, 2009-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
Written by Jim Meyering, 1992.
|
Written by Jim Meyering, 1992.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Lesser General Public License as
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
(at your option) any later version.
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This file is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
/* A generic hash table package. */
|
/* A generic hash table package. */
|
||||||
@ -138,38 +138,24 @@ static const Hash_tuning default_tuning =
|
|||||||
|
|
||||||
/* Information and lookup. */
|
/* Information and lookup. */
|
||||||
|
|
||||||
/* The following few functions provide information about the overall hash
|
|
||||||
table organization: the number of entries, number of buckets and maximum
|
|
||||||
length of buckets. */
|
|
||||||
|
|
||||||
/* Return the number of buckets in the hash table. The table size, the total
|
|
||||||
number of buckets (used plus unused), or the maximum number of slots, are
|
|
||||||
the same quantity. */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_get_n_buckets (const Hash_table *table)
|
hash_get_n_buckets (const Hash_table *table)
|
||||||
{
|
{
|
||||||
return table->n_buckets;
|
return table->n_buckets;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of slots in use (non-empty buckets). */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_get_n_buckets_used (const Hash_table *table)
|
hash_get_n_buckets_used (const Hash_table *table)
|
||||||
{
|
{
|
||||||
return table->n_buckets_used;
|
return table->n_buckets_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of active entries. */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_get_n_entries (const Hash_table *table)
|
hash_get_n_entries (const Hash_table *table)
|
||||||
{
|
{
|
||||||
return table->n_entries;
|
return table->n_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the length of the longest chain (bucket). */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_get_max_bucket_length (const Hash_table *table)
|
hash_get_max_bucket_length (const Hash_table *table)
|
||||||
{
|
{
|
||||||
@ -194,9 +180,6 @@ hash_get_max_bucket_length (const Hash_table *table)
|
|||||||
return max_bucket_length;
|
return max_bucket_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do a mild validation of a hash table, by traversing it and checking two
|
|
||||||
statistics. */
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
hash_table_ok (const Hash_table *table)
|
hash_table_ok (const Hash_table *table)
|
||||||
{
|
{
|
||||||
@ -254,9 +237,6 @@ safe_hasher (const Hash_table *table, const void *key)
|
|||||||
return table->bucket + n;
|
return table->bucket + n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If ENTRY matches an entry already in the hash table, return the
|
|
||||||
entry from the table. Otherwise, return NULL. */
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_lookup (const Hash_table *table, const void *entry)
|
hash_lookup (const Hash_table *table, const void *entry)
|
||||||
{
|
{
|
||||||
@ -275,15 +255,6 @@ hash_lookup (const Hash_table *table, const void *entry)
|
|||||||
|
|
||||||
/* Walking. */
|
/* Walking. */
|
||||||
|
|
||||||
/* The functions in this page traverse the hash table and process the
|
|
||||||
contained entries. For the traversal to work properly, the hash table
|
|
||||||
should not be resized nor modified while any particular entry is being
|
|
||||||
processed. In particular, entries should not be added, and an entry
|
|
||||||
may be removed only if there is no shrink threshold and the entry being
|
|
||||||
removed has already been passed to hash_get_next. */
|
|
||||||
|
|
||||||
/* Return the first data in the table, or NULL if the table is empty. */
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_get_first (const Hash_table *table)
|
hash_get_first (const Hash_table *table)
|
||||||
{
|
{
|
||||||
@ -299,10 +270,6 @@ hash_get_first (const Hash_table *table)
|
|||||||
return bucket->data;
|
return bucket->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the user data for the entry following ENTRY, where ENTRY has been
|
|
||||||
returned by a previous call to either 'hash_get_first' or 'hash_get_next'.
|
|
||||||
Return NULL if there are no more entries. */
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_get_next (const Hash_table *table, const void *entry)
|
hash_get_next (const Hash_table *table, const void *entry)
|
||||||
{
|
{
|
||||||
@ -328,10 +295,6 @@ hash_get_next (const Hash_table *table, const void *entry)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill BUFFER with pointers to active user entries in the hash table, then
|
|
||||||
return the number of pointers copied. Do not copy more than BUFFER_SIZE
|
|
||||||
pointers. */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_get_entries (const Hash_table *table, void **buffer,
|
hash_get_entries (const Hash_table *table, void **buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
@ -356,14 +319,6 @@ hash_get_entries (const Hash_table *table, void **buffer,
|
|||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call a PROCESSOR function for each entry of a hash table, and return the
|
|
||||||
number of entries for which the processor function returned success. A
|
|
||||||
pointer to some PROCESSOR_DATA which will be made available to each call to
|
|
||||||
the processor function. The PROCESSOR accepts two arguments: the first is
|
|
||||||
the user entry being walked into, the second is the value of PROCESSOR_DATA
|
|
||||||
as received. The walking continue for as long as the PROCESSOR function
|
|
||||||
returns nonzero. When it returns zero, the walking is interrupted. */
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
hash_do_for_each (const Hash_table *table, Hash_processor processor,
|
hash_do_for_each (const Hash_table *table, Hash_processor processor,
|
||||||
void *processor_data)
|
void *processor_data)
|
||||||
@ -390,9 +345,6 @@ hash_do_for_each (const Hash_table *table, Hash_processor processor,
|
|||||||
|
|
||||||
/* Allocation and clean-up. */
|
/* Allocation and clean-up. */
|
||||||
|
|
||||||
/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
|
|
||||||
This is a convenience routine for constructing other hashing functions. */
|
|
||||||
|
|
||||||
#if USE_DIFF_HASH
|
#if USE_DIFF_HASH
|
||||||
|
|
||||||
/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
|
/* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
|
||||||
@ -546,7 +498,7 @@ compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
|
|||||||
if (!tuning->is_n_buckets)
|
if (!tuning->is_n_buckets)
|
||||||
{
|
{
|
||||||
float new_candidate = candidate / tuning->growth_threshold;
|
float new_candidate = candidate / tuning->growth_threshold;
|
||||||
if (SIZE_MAX <= new_candidate)
|
if ((float) SIZE_MAX <= new_candidate)
|
||||||
return 0;
|
return 0;
|
||||||
candidate = new_candidate;
|
candidate = new_candidate;
|
||||||
}
|
}
|
||||||
@ -556,40 +508,6 @@ compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
|
|||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and return a new hash table, or NULL upon failure. The initial
|
|
||||||
number of buckets is automatically selected so as to _guarantee_ that you
|
|
||||||
may insert at least CANDIDATE different user entries before any growth of
|
|
||||||
the hash table size occurs. So, if have a reasonably tight a-priori upper
|
|
||||||
bound on the number of entries you intend to insert in the hash table, you
|
|
||||||
may save some table memory and insertion time, by specifying it here. If
|
|
||||||
the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
|
|
||||||
argument has its meaning changed to the wanted number of buckets.
|
|
||||||
|
|
||||||
TUNING points to a structure of user-supplied values, in case some fine
|
|
||||||
tuning is wanted over the default behavior of the hasher. If TUNING is
|
|
||||||
NULL, the default tuning parameters are used instead. If TUNING is
|
|
||||||
provided but the values requested are out of bounds or might cause
|
|
||||||
rounding errors, return NULL.
|
|
||||||
|
|
||||||
The user-supplied HASHER function, when not NULL, accepts two
|
|
||||||
arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a
|
|
||||||
slot number for that entry which should be in the range 0..TABLE_SIZE-1.
|
|
||||||
This slot number is then returned.
|
|
||||||
|
|
||||||
The user-supplied COMPARATOR function, when not NULL, accepts two
|
|
||||||
arguments pointing to user data, it then returns true for a pair of entries
|
|
||||||
that compare equal, or false otherwise. This function is internally called
|
|
||||||
on entries which are already known to hash to the same bucket index,
|
|
||||||
but which are distinct pointers.
|
|
||||||
|
|
||||||
The user-supplied DATA_FREER function, when not NULL, may be later called
|
|
||||||
with the user data as an argument, just before the entry containing the
|
|
||||||
data gets freed. This happens from within 'hash_free' or 'hash_clear'.
|
|
||||||
You should specify this function only if you want these functions to free
|
|
||||||
all of your 'data' data. This is typically the case when your data is
|
|
||||||
simply an auxiliary struct that you have malloc'd to aggregate several
|
|
||||||
values. */
|
|
||||||
|
|
||||||
Hash_table *
|
Hash_table *
|
||||||
hash_initialize (size_t candidate, const Hash_tuning *tuning,
|
hash_initialize (size_t candidate, const Hash_tuning *tuning,
|
||||||
Hash_hasher hasher, Hash_comparator comparator,
|
Hash_hasher hasher, Hash_comparator comparator,
|
||||||
@ -645,10 +563,6 @@ hash_initialize (size_t candidate, const Hash_tuning *tuning,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make all buckets empty, placing any chained entries on the free list.
|
|
||||||
Apply the user-specified function data_freer (if any) to the data of any
|
|
||||||
affected entries. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
hash_clear (Hash_table *table)
|
hash_clear (Hash_table *table)
|
||||||
{
|
{
|
||||||
@ -687,11 +601,6 @@ hash_clear (Hash_table *table)
|
|||||||
table->n_entries = 0;
|
table->n_entries = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reclaim all storage associated with a hash table. If a data_freer
|
|
||||||
function has been supplied by the user when the hash table was created,
|
|
||||||
this function applies it to the data of each entry before freeing that
|
|
||||||
entry. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
hash_free (Hash_table *table)
|
hash_free (Hash_table *table)
|
||||||
{
|
{
|
||||||
@ -931,14 +840,6 @@ transfer_entries (Hash_table *dst, Hash_table *src, bool safe)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For an already existing hash table, change the number of buckets through
|
|
||||||
specifying CANDIDATE. The contents of the hash table are preserved. The
|
|
||||||
new number of buckets is automatically selected so as to _guarantee_ that
|
|
||||||
the table may receive at least CANDIDATE different user entries, including
|
|
||||||
those already in the table, before any other growth of the hash table size
|
|
||||||
occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
|
|
||||||
exact number of buckets desired. Return true iff the rehash succeeded. */
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
hash_rehash (Hash_table *table, size_t candidate)
|
hash_rehash (Hash_table *table, size_t candidate)
|
||||||
{
|
{
|
||||||
@ -1018,22 +919,6 @@ hash_rehash (Hash_table *table, size_t candidate)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert ENTRY into hash TABLE if there is not already a matching entry.
|
|
||||||
|
|
||||||
Return -1 upon memory allocation failure.
|
|
||||||
Return 1 if insertion succeeded.
|
|
||||||
Return 0 if there is already a matching entry in the table,
|
|
||||||
and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
|
|
||||||
to that entry.
|
|
||||||
|
|
||||||
This interface is easier to use than hash_insert when you must
|
|
||||||
distinguish between the latter two cases. More importantly,
|
|
||||||
hash_insert is unusable for some types of ENTRY values. When using
|
|
||||||
hash_insert, the only way to distinguish those cases is to compare
|
|
||||||
the return value and ENTRY. That works only when you can have two
|
|
||||||
different ENTRY values that point to data that compares "equal". Thus,
|
|
||||||
when the ENTRY value is a simple scalar, you must use
|
|
||||||
hash_insert_if_absent. ENTRY must not be NULL. */
|
|
||||||
int
|
int
|
||||||
hash_insert_if_absent (Hash_table *table, void const *entry,
|
hash_insert_if_absent (Hash_table *table, void const *entry,
|
||||||
void const **matched_ent)
|
void const **matched_ent)
|
||||||
@ -1076,7 +961,7 @@ hash_insert_if_absent (Hash_table *table, void const *entry,
|
|||||||
: (table->n_buckets * tuning->growth_factor
|
: (table->n_buckets * tuning->growth_factor
|
||||||
* tuning->growth_threshold));
|
* tuning->growth_threshold));
|
||||||
|
|
||||||
if (SIZE_MAX <= candidate)
|
if ((float) SIZE_MAX <= candidate)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* If the rehash fails, arrange to return NULL. */
|
/* If the rehash fails, arrange to return NULL. */
|
||||||
@ -1116,12 +1001,6 @@ hash_insert_if_absent (Hash_table *table, void const *entry,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If ENTRY matches an entry already in the hash table, return the pointer
|
|
||||||
to the entry from the table. Otherwise, insert ENTRY and return ENTRY.
|
|
||||||
Return NULL if the storage required for insertion cannot be allocated.
|
|
||||||
This implementation does not support duplicate entries or insertion of
|
|
||||||
NULL. */
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_insert (Hash_table *table, void const *entry)
|
hash_insert (Hash_table *table, void const *entry)
|
||||||
{
|
{
|
||||||
@ -1132,12 +1011,8 @@ hash_insert (Hash_table *table, void const *entry)
|
|||||||
: (void *) (err == 0 ? matched_ent : entry));
|
: (void *) (err == 0 ? matched_ent : entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If ENTRY is already in the table, remove it and return the just-deleted
|
|
||||||
data (the user may want to deallocate its storage). If ENTRY is not in the
|
|
||||||
table, don't modify the table and return NULL. */
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_delete (Hash_table *table, const void *entry)
|
hash_remove (Hash_table *table, const void *entry)
|
||||||
{
|
{
|
||||||
void *data;
|
void *data;
|
||||||
struct hash_entry *bucket;
|
struct hash_entry *bucket;
|
||||||
@ -1196,6 +1071,12 @@ hash_delete (Hash_table *table, const void *entry)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
hash_delete (Hash_table *table, const void *entry)
|
||||||
|
{
|
||||||
|
return hash_remove (table, entry);
|
||||||
|
}
|
||||||
|
|
||||||
/* Testing. */
|
/* Testing. */
|
||||||
|
|
||||||
#if TESTING
|
#if TESTING
|
||||||
@ -1215,6 +1096,7 @@ hash_print (const Hash_table *table)
|
|||||||
for (cursor = bucket; cursor; cursor = cursor->next)
|
for (cursor = bucket; cursor; cursor = cursor->next)
|
||||||
{
|
{
|
||||||
char const *s = cursor->data;
|
char const *s = cursor->data;
|
||||||
|
/* FIXME */
|
||||||
if (s)
|
if (s)
|
||||||
printf (" %s\n", s);
|
printf (" %s\n", s);
|
||||||
}
|
}
|
||||||
|
263
lib/hash.h
263
lib/hash.h
@ -1,19 +1,19 @@
|
|||||||
/* hash - hashing table processing.
|
/* hash - hashing table processing.
|
||||||
Copyright (C) 1998-1999, 2001, 2003, 2009-2019 Free Software Foundation,
|
Copyright (C) 1998-1999, 2001, 2003, 2009-2023 Free Software Foundation,
|
||||||
Inc.
|
Inc.
|
||||||
Written by Jim Meyering <meyering@ascend.com>, 1998.
|
Written by Jim Meyering <meyering@ascend.com>, 1998.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This file is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU Lesser General Public License as
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
(at your option) any later version.
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This file is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
/* A generic hash table package. */
|
/* A generic hash table package. */
|
||||||
@ -27,29 +27,10 @@
|
|||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
|
|
||||||
/* The __attribute__ feature is available in gcc versions 2.5 and later.
|
# ifdef __cplusplus
|
||||||
The warn_unused_result attribute appeared first in gcc-3.4.0. */
|
extern "C" {
|
||||||
# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
|
||||||
# define _GL_ATTRIBUTE_WUR __attribute__ ((__warn_unused_result__))
|
|
||||||
# else
|
|
||||||
# define _GL_ATTRIBUTE_WUR /* empty */
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef _GL_ATTRIBUTE_DEPRECATED
|
|
||||||
/* The __attribute__((__deprecated__)) feature
|
|
||||||
is available in gcc versions 3.1 and newer. */
|
|
||||||
# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1)
|
|
||||||
# define _GL_ATTRIBUTE_DEPRECATED /* empty */
|
|
||||||
# else
|
|
||||||
# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__))
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
|
|
||||||
typedef size_t (*Hash_hasher) (const void *, size_t);
|
|
||||||
typedef bool (*Hash_comparator) (const void *, const void *);
|
|
||||||
typedef void (*Hash_data_freer) (void *);
|
|
||||||
typedef bool (*Hash_processor) (void *, void *);
|
|
||||||
|
|
||||||
struct hash_tuning
|
struct hash_tuning
|
||||||
{
|
{
|
||||||
/* This structure is mainly used for 'hash_initialize', see the block
|
/* This structure is mainly used for 'hash_initialize', see the block
|
||||||
@ -68,36 +49,208 @@ struct hash_table;
|
|||||||
|
|
||||||
typedef struct hash_table Hash_table;
|
typedef struct hash_table Hash_table;
|
||||||
|
|
||||||
/* Information and lookup. */
|
/*
|
||||||
size_t hash_get_n_buckets (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
* Information and lookup.
|
||||||
size_t hash_get_n_buckets_used (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
*/
|
||||||
size_t hash_get_n_entries (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
|
||||||
size_t hash_get_max_bucket_length (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
|
||||||
bool hash_table_ok (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
|
||||||
void hash_print_statistics (const Hash_table *, FILE *);
|
|
||||||
void *hash_lookup (const Hash_table *, const void *);
|
|
||||||
|
|
||||||
/* Walking. */
|
/* The following few functions provide information about the overall hash
|
||||||
void *hash_get_first (const Hash_table *) _GL_ATTRIBUTE_PURE;
|
table organization: the number of entries, number of buckets and maximum
|
||||||
void *hash_get_next (const Hash_table *, const void *);
|
length of buckets. */
|
||||||
size_t hash_get_entries (const Hash_table *, void **, size_t);
|
|
||||||
size_t hash_do_for_each (const Hash_table *, Hash_processor, void *);
|
|
||||||
|
|
||||||
/* Allocation and clean-up. */
|
/* Return the number of buckets in the hash table. The table size, the total
|
||||||
size_t hash_string (const char *, size_t) _GL_ATTRIBUTE_PURE;
|
number of buckets (used plus unused), or the maximum number of slots, are
|
||||||
void hash_reset_tuning (Hash_tuning *);
|
the same quantity. */
|
||||||
Hash_table *hash_initialize (size_t, const Hash_tuning *,
|
extern size_t hash_get_n_buckets (const Hash_table *table)
|
||||||
Hash_hasher, Hash_comparator,
|
;
|
||||||
Hash_data_freer) _GL_ATTRIBUTE_WUR;
|
|
||||||
void hash_clear (Hash_table *);
|
|
||||||
void hash_free (Hash_table *);
|
|
||||||
|
|
||||||
/* Insertion and deletion. */
|
/* Return the number of slots in use (non-empty buckets). */
|
||||||
bool hash_rehash (Hash_table *, size_t) _GL_ATTRIBUTE_WUR;
|
extern size_t hash_get_n_buckets_used (const Hash_table *table)
|
||||||
void *hash_insert (Hash_table *, const void *) _GL_ATTRIBUTE_WUR;
|
;
|
||||||
|
|
||||||
int hash_insert_if_absent (Hash_table *table, const void *entry,
|
/* Return the number of active entries. */
|
||||||
|
extern size_t hash_get_n_entries (const Hash_table *table)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Return the length of the longest chain (bucket). */
|
||||||
|
extern size_t hash_get_max_bucket_length (const Hash_table *table)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Do a mild validation of a hash table, by traversing it and checking two
|
||||||
|
statistics. */
|
||||||
|
extern bool hash_table_ok (const Hash_table *table)
|
||||||
|
;
|
||||||
|
|
||||||
|
extern void hash_print_statistics (const Hash_table *table, FILE *stream);
|
||||||
|
|
||||||
|
/* If ENTRY matches an entry already in the hash table, return the
|
||||||
|
entry from the table. Otherwise, return NULL. */
|
||||||
|
extern void *hash_lookup (const Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walking.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The functions in this page traverse the hash table and process the
|
||||||
|
contained entries. For the traversal to work properly, the hash table
|
||||||
|
should not be resized nor modified while any particular entry is being
|
||||||
|
processed. In particular, entries should not be added, and an entry
|
||||||
|
may be removed only if there is no shrink threshold and the entry being
|
||||||
|
removed has already been passed to hash_get_next. */
|
||||||
|
|
||||||
|
/* Return the first data in the table, or NULL if the table is empty. */
|
||||||
|
extern void *hash_get_first (const Hash_table *table)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Return the user data for the entry following ENTRY, where ENTRY has been
|
||||||
|
returned by a previous call to either 'hash_get_first' or 'hash_get_next'.
|
||||||
|
Return NULL if there are no more entries. */
|
||||||
|
extern void *hash_get_next (const Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
/* Fill BUFFER with pointers to active user entries in the hash table, then
|
||||||
|
return the number of pointers copied. Do not copy more than BUFFER_SIZE
|
||||||
|
pointers. */
|
||||||
|
extern size_t hash_get_entries (const Hash_table *table, void **buffer,
|
||||||
|
size_t buffer_size);
|
||||||
|
|
||||||
|
typedef bool (*Hash_processor) (void *entry, void *processor_data);
|
||||||
|
|
||||||
|
/* Call a PROCESSOR function for each entry of a hash table, and return the
|
||||||
|
number of entries for which the processor function returned success. A
|
||||||
|
pointer to some PROCESSOR_DATA which will be made available to each call to
|
||||||
|
the processor function. The PROCESSOR accepts two arguments: the first is
|
||||||
|
the user entry being walked into, the second is the value of PROCESSOR_DATA
|
||||||
|
as received. The walking continue for as long as the PROCESSOR function
|
||||||
|
returns nonzero. When it returns zero, the walking is interrupted. */
|
||||||
|
extern size_t hash_do_for_each (const Hash_table *table,
|
||||||
|
Hash_processor processor, void *processor_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocation and clean-up.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Return a hash index for a NUL-terminated STRING between 0 and N_BUCKETS-1.
|
||||||
|
This is a convenience routine for constructing other hashing functions. */
|
||||||
|
extern size_t hash_string (const char *string, size_t n_buckets)
|
||||||
|
;
|
||||||
|
|
||||||
|
extern void hash_reset_tuning (Hash_tuning *tuning);
|
||||||
|
|
||||||
|
typedef size_t (*Hash_hasher) (const void *entry, size_t table_size);
|
||||||
|
typedef bool (*Hash_comparator) (const void *entry1, const void *entry2);
|
||||||
|
typedef void (*Hash_data_freer) (void *entry);
|
||||||
|
|
||||||
|
/* Reclaim all storage associated with a hash table. If a data_freer
|
||||||
|
function has been supplied by the user when the hash table was created,
|
||||||
|
this function applies it to the data of each entry before freeing that
|
||||||
|
entry. */
|
||||||
|
extern void hash_free (Hash_table *table);
|
||||||
|
|
||||||
|
/* Allocate and return a new hash table, or NULL upon failure. The initial
|
||||||
|
number of buckets is automatically selected so as to _guarantee_ that you
|
||||||
|
may insert at least CANDIDATE different user entries before any growth of
|
||||||
|
the hash table size occurs. So, if have a reasonably tight a-priori upper
|
||||||
|
bound on the number of entries you intend to insert in the hash table, you
|
||||||
|
may save some table memory and insertion time, by specifying it here. If
|
||||||
|
the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
|
||||||
|
argument has its meaning changed to the wanted number of buckets.
|
||||||
|
|
||||||
|
TUNING points to a structure of user-supplied values, in case some fine
|
||||||
|
tuning is wanted over the default behavior of the hasher. If TUNING is
|
||||||
|
NULL, the default tuning parameters are used instead. If TUNING is
|
||||||
|
provided but the values requested are out of bounds or might cause
|
||||||
|
rounding errors, return NULL.
|
||||||
|
|
||||||
|
The user-supplied HASHER function, when not NULL, accepts two
|
||||||
|
arguments ENTRY and TABLE_SIZE. It computes, by hashing ENTRY contents, a
|
||||||
|
slot number for that entry which should be in the range 0..TABLE_SIZE-1.
|
||||||
|
This slot number is then returned.
|
||||||
|
|
||||||
|
The user-supplied COMPARATOR function, when not NULL, accepts two
|
||||||
|
arguments pointing to user data, it then returns true for a pair of entries
|
||||||
|
that compare equal, or false otherwise. This function is internally called
|
||||||
|
on entries which are already known to hash to the same bucket index,
|
||||||
|
but which are distinct pointers.
|
||||||
|
|
||||||
|
The user-supplied DATA_FREER function, when not NULL, may be later called
|
||||||
|
with the user data as an argument, just before the entry containing the
|
||||||
|
data gets freed. This happens from within 'hash_free' or 'hash_clear'.
|
||||||
|
You should specify this function only if you want these functions to free
|
||||||
|
all of your 'data' data. This is typically the case when your data is
|
||||||
|
simply an auxiliary struct that you have malloc'd to aggregate several
|
||||||
|
values. */
|
||||||
|
extern Hash_table *hash_initialize (size_t candidate,
|
||||||
|
const Hash_tuning *tuning,
|
||||||
|
Hash_hasher hasher,
|
||||||
|
Hash_comparator comparator,
|
||||||
|
Hash_data_freer data_freer);
|
||||||
|
|
||||||
|
/* Same as hash_initialize, but invokes xalloc_die on memory exhaustion. */
|
||||||
|
/* This function is defined by module 'xhash'. */
|
||||||
|
extern Hash_table *hash_xinitialize (size_t candidate,
|
||||||
|
const Hash_tuning *tuning,
|
||||||
|
Hash_hasher hasher,
|
||||||
|
Hash_comparator comparator,
|
||||||
|
Hash_data_freer data_freer);
|
||||||
|
|
||||||
|
/* Make all buckets empty, placing any chained entries on the free list.
|
||||||
|
Apply the user-specified function data_freer (if any) to the datas of any
|
||||||
|
affected entries. */
|
||||||
|
extern void hash_clear (Hash_table *table);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insertion and deletion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For an already existing hash table, change the number of buckets through
|
||||||
|
specifying CANDIDATE. The contents of the hash table are preserved. The
|
||||||
|
new number of buckets is automatically selected so as to _guarantee_ that
|
||||||
|
the table may receive at least CANDIDATE different user entries, including
|
||||||
|
those already in the table, before any other growth of the hash table size
|
||||||
|
occurs. If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
|
||||||
|
exact number of buckets desired. Return true iff the rehash succeeded. */
|
||||||
|
extern bool hash_rehash (Hash_table *table, size_t candidate);
|
||||||
|
|
||||||
|
/* If ENTRY matches an entry already in the hash table, return the pointer
|
||||||
|
to the entry from the table. Otherwise, insert ENTRY and return ENTRY.
|
||||||
|
Return NULL if the storage required for insertion cannot be allocated.
|
||||||
|
This implementation does not support duplicate entries or insertion of
|
||||||
|
NULL. */
|
||||||
|
extern void *hash_insert (Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
/* Same as hash_insert, but invokes xalloc_die on memory exhaustion. */
|
||||||
|
/* This function is defined by module 'xhash'. */
|
||||||
|
extern void *hash_xinsert (Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
/* Insert ENTRY into hash TABLE if there is not already a matching entry.
|
||||||
|
|
||||||
|
Return -1 upon memory allocation failure.
|
||||||
|
Return 1 if insertion succeeded.
|
||||||
|
Return 0 if there is already a matching entry in the table,
|
||||||
|
and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
|
||||||
|
to that entry.
|
||||||
|
|
||||||
|
This interface is easier to use than hash_insert when you must
|
||||||
|
distinguish between the latter two cases. More importantly,
|
||||||
|
hash_insert is unusable for some types of ENTRY values. When using
|
||||||
|
hash_insert, the only way to distinguish those cases is to compare
|
||||||
|
the return value and ENTRY. That works only when you can have two
|
||||||
|
different ENTRY values that point to data that compares "equal". Thus,
|
||||||
|
when the ENTRY value is a simple scalar, you must use
|
||||||
|
hash_insert_if_absent. ENTRY must not be NULL. */
|
||||||
|
extern int hash_insert_if_absent (Hash_table *table, const void *entry,
|
||||||
const void **matched_ent);
|
const void **matched_ent);
|
||||||
void *hash_delete (Hash_table *, const void *);
|
|
||||||
|
/* If ENTRY is already in the table, remove it and return the just-deleted
|
||||||
|
data (the user may want to deallocate its storage). If ENTRY is not in the
|
||||||
|
table, don't modify the table and return NULL. */
|
||||||
|
extern void *hash_remove (Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
/* Same as hash_remove. This interface is deprecated.
|
||||||
|
FIXME: Remove in 2022. */
|
||||||
|
extern void *hash_delete (Hash_table *table, const void *entry);
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user