/* hashtree.h - hash table decls
*
****************************************************************
* Copyright (C) 1998, 2000 Thomas Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#ifndef INCLUDE__HASH__HASHTREE_H
#define INCLUDE__HASH__HASHTREE_H
#include "hackerlab/bitsets/bitset.h"
/************************************************************************
*(h2 "Hashtree Data Structures")
*
*/
/*(menu)
*/
/************************************************************************
*(h3 "How Hashtrees Work")
*
* A hash tree is an associative data structure mapping "keys" to
* "values". Both keys and values are stored as pointers of type
* `void *' and may point to any type of value.
*
* When creating a new hash table, programs specify how parts of the
* hash table will be allocated and freed. For example, programs
* might simply use `malloc' and `free', or they might use allocation
* from a size-limited pool, or they might arrange so that parts of
* the hashtree don't have to be allocated at all because they are
* stored in hashtree keys.
*
* Programs also specify, in advance, how keys are compared for
* equality.
*
* Programs do not specify in advance how hash values are computed for
* keys. Instead, when storing or looking up keys in a hash table,
* programs first compute a hash value for the key and then call
* either `hashtree_find' or `hashtree_store'. Hash values are
* `unsigned long' integers.
*
* Internally, hashtrees are stored as trees. Each tree node has 16
* children. The children of leaf nodes are lists of key/value pairs.
* At each level of the tree, four bits from the hash value are used
* to select a child. The minimum depth of the tree is two: a root
* node at level 0, lists of key/value pairs at level 1. The maximum
* depth of the tree is:
*
* (2 * sizeof (unsigned long))
*
* If a list of key/value pairs grows too long (more than 5 elements),
* and the node containing that list is not a maximum-depth node, the
* node "overflows". When overflow occurs, the leaf node is made an
* internal node with 16 subtrees. Each of those subtrees is a new
* leaf node. All of the key/value pairs from the overflowing node
* are redistributed among the new leaf nodes.
*
* This style of hash tree makes reasonably efficient use of memory
* for both small and moderately large numbers of key/value pairs.
* Access times are determined by the depth of the tree and are
* usually limited by the maximum depth. In the exceptional
* circumstance that a maximum-depth node contains a very large number
* of key/value pairs (indicating a poor distribution of hash values),
* access times for keys in that node grow linearly with the number of
* keys in that node.
*
* The cost of adding an element (possibly causing overflow) is most
* commonly the same as the cost of adding an element. The cost of
* overflow is determined by the number of key/value pairs that must
* be redistributed. That number is limited by the number of
* key/value pairs in a leaf node at not-maximal depth (64 == 16 lists
* of key/value pairs * 4 pairs per list). Once again, in the
* exceptional circumstance of a maximum depth node with many
* key/value pairs, the cost of inserting a key grows linearly with
* the number of keys in that node.
*
*
* \WARNINGS:/
*
* Hashtrees are not a panacea.
*
* If you know advance roughly how many key/value pairs
* a hash table will contain, you can obtain better memory use and
* better access times by using a flat, fixed-size hash table.
*
* Hashtrees are most useful when the number of key/value pairs may
* vary over a wide range, when it is important that tables with only
* a few key/value pairs remain small, and when the cost of adding
* an element (possibly causing overflow), must remain small.
*
* Hashtrees are also a reasonable default choice when good hash-table
* performance is desirable but optimal performance is not necessary.
* In most situations, hashtrees will give at least good performance.
*/
/************************************************************************
*(h3 "Types for Hashtrees")
*
*
*
*/
/*(c hashtree :category type)
* struct hashtree;
*
* A `struct hashtree' represents a hash table. It is an opaque
* structure that should be allocated by `hashtree_new' or else
* initialized by being filled with 0 bytes.
*/
struct hashtree
{
int refs;
struct hashtree * parent;
bitset_subset nested_p;
/* polymorphic: trees for internal nodes, items for leaf nodes */
void ** children[16];
};
/*(c hashtree_item :category type)
* struct hashtree_item
*
* A `struct hashtree_item' represents one key-value pair stored in a
* hash table. It contains (at least) the fields:
*
* void * key;
* void * binding;
*
* It is safe to modify either field, but modifications must not
* change either the hash value of the key or its equality
* to other keys.
*/
struct hashtree_item
{
struct hashtree_item * next_same_hash;
struct hashtree * table;
unsigned long hash;
void * key;
void * binding;
};
struct hashtree_rules;
/*(c hashtree_rules :category type)
* struct hashtree_rules;
*
* A `struct hashtree_rules' contains function pointers, and an
* allocation limits.
*
* It has these fields, in this order:
*
* // a function to compare keye:
* hashtree_eq_fn eq;
*
* // a function to allocate tree nodes
* hash_alloc_fn hash_alloc;
*
* // a function to free tree nodes:
* free_hashtree_fn free_hash;
*
* // a function to allocate key/value pairs:
* hashtree_alloc_item_fn hash_item_alloc;
*
* // a function to free key/value pairs:
* free_hashtree_item_fn free_hash_item;
*
* // allocation limits that apply to hash tables
* // using these rules:
* alloc_limits limits;
*
*
insert*/
typedef int
(*hashtree_eq_fn) (void * key1,
void * key2,
struct hashtree_rules * rules);
/*end-insert
*
* `hashtree_eq_fn' compares two keys for equality. It returns 1 if they
* are equal, 0 otherwise.
*
insert*/
typedef struct hashtree *
(*hashtree_alloc_fn) (struct hashtree_rules * rules);
/*end-insert
*
* `hashtree_alloc_fn' allocates a new hash table tree node. Hash tables
* are nested to form trees; this function allocates one node of such
* a tree. This function may return 0 if allocation fails.
*
insert*/
typedef void
(*free_hashtree_fn) (struct hashtree * node,
struct hashtree_rules * rules);
/*end-insert
*
* `free_hashtree_fn' frees an empty hash table tree node.
*
insert*/
typedef struct hashtree_item *
(*hashtree_alloc_item_fn) (void * key, struct hashtree_rules * rules);
/*end-insert
*
* `hashtree_alloc_item_fn' allocates a hash table item (key/value
* pair) for the indicated key. It may return 0 if allocation fails.
*
* `hashtree_alloc_item_fn' must fill in the `key' and `binding'
* fields of the `struct hashtree_item' that it returns. Typically,
* the field `key' is set equal to the parameter `key', and the field
* `binding' is initialized to 0, indicating that the key initially
* has no binding.
*
* Sometimes, if a key will be stored in at most one hashtree, a
* useful optimization is to store a `struct hashtree_item' within
* each key. In that case, `hashtree_alloc_item_fn' doesn't have to
* allocate memory at all: it can return a pointer to the `struct
* hashtree_item' in the key.
*
insert*/
typedef void
(*free_hashtree_item_fn) (struct hashtree_item * node,
struct hashtree_rules * rules);
/*end-insert
*
* `free_hashtree_item_fn' frees a hash table item (key/value pair).
*
*
* The field `limits' points to allocation limits which are used
* by the default implementations of these functions. By convention,
* non-default implementations should also use `limits' when performing
* allocations.
*
* Defaults are provided for the functions in a `struct
* hashtree_rules'. If any particular function pointer is 0 or if the
* `struct hashtree_rules *' passed to `hashtree_alloc' is 0, the
* default implementations are used.
*
* The default functions perform allocations by calling `lim_malloc'
* with the allocation limits stored in the field `limits'. (See
* xref:"Allocation With Limitations".) If `limits' is 0, or if the
* `struct hashtree_rules *' pointer is 0, the allocation limits
* `lim_use_must_malloc' is used. In that case, if allocation fails,
* the process is exitted by calling `panic'.
*
* The default implementation of `eq' compares pointers to keys using
* `=='.
*
*/
struct hashtree_rules
{
hashtree_eq_fn eq;
hashtree_alloc_fn hash_alloc;
free_hashtree_fn free_hash;
hashtree_alloc_item_fn hash_item_alloc;
free_hashtree_item_fn free_hash_item;
alloc_limits limits;
};
typedef void (*hashtree_free_data_fn) (struct hashtree_item * it,
struct hashtree_rules * rules);
typedef void (*hashtree_fold_fn) (struct hashtree_item * it,
void *user_data,
struct hashtree_rules * rules);
/* automatically generated __STDC__ prototypes */
extern struct hashtree_rules * hashtree_make_rules (alloc_limits limits);
extern void hashtree_init_rules (struct hashtree_rules * rules,
hashtree_eq_fn eq,
hashtree_alloc_fn hash_alloc,
free_hashtree_fn free_hash,
hashtree_alloc_item_fn hash_item_alloc,
free_hashtree_item_fn free_hash_item,
alloc_limits limits);
extern void hashtree_free_limit_rules (struct hashtree_rules * rules);
extern struct hashtree * hashtree_alloc (struct hashtree_rules * rules);
extern void hashtree_free (struct hashtree * it,
hashtree_free_data_fn freefn,
struct hashtree_rules * rules);
extern void hashtree_free_static (struct hashtree * tab,
hashtree_free_data_fn freefn,
struct hashtree_rules * rules);
extern struct hashtree_item * hashtree_find (struct hashtree * table,
unsigned long hash,
void * key,
struct hashtree_rules * rules);
extern struct hashtree_item * hashtree_store (struct hashtree * table,
unsigned long hash,
void * key,
struct hashtree_rules * rules);
extern void hashtree_delete (struct hashtree_item * it, struct hashtree_rules * rules);
extern void hashtree_fold (struct hashtree *table, hashtree_fold_fn foldfn,
void *user_data, struct hashtree_rules * rules);
#endif /* INCLUDE__HASH__HASHTREE_H */
syntax highlighted by Code2HTML, v. 0.9.1