chiark / gitweb /
REORG Delete everything that's not innduct or build system or changed for innduct
[innduct.git] / lib / hashtab.c
diff --git a/lib/hashtab.c b/lib/hashtab.c
deleted file mode 100644 (file)
index ce0fa74..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-/*  $Id: hashtab.c 6135 2003-01-19 01:15:40Z rra $
-**
-**  Generic hash table implementation.
-**
-**  Written by Russ Allbery <rra@stanford.edu>
-**  This work is hereby placed in the public domain by its author.
-**
-**  This is a generic hash table implementation with linear probing.  It
-**  takes a comparison function and a hashing function and stores void *.
-**
-**  Included for the use of callers is the hash function LOOKUP2 by Bob
-**  Jenkins, taken from <http://burtleburtle.net/bob/hash/>; see that web
-**  page for analysis and performance comparisons.  The performance of this
-**  hash is slightly worse than the standard sum and modulus hash function
-**  seen in many places but it produces fewer collisions.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "inn/hashtab.h"
-#include "libinn.h"
-
-/* Magic values for empty and deleted hash table slots. */
-#define HASH_EMPTY      ((void *) 0)
-#define HASH_DELETED    ((void *) 1)
-
-struct hash {
-    size_t size;                /* Allocated size. */
-    size_t mask;                /* Used to resolve a hash to an index. */
-    size_t nelements;           /* Total elements, including deleted. */
-    size_t ndeleted;            /* Number of deleted elements. */
-
-    unsigned long searches;     /* Count of lookups (for debugging). */
-    unsigned long collisions;   /* Count of collisions (for debugging). */
-    unsigned long expansions;   /* Count of hash resizes needed. */
-
-    hash_func hash;             /* Return hash of a key. */
-    hash_key_func key;          /* Given an element, returns its key. */
-    hash_equal_func equal;      /* Whether a key matches an element. */
-    hash_delete_func delete;    /* Called when a hash element is deleted. */
-
-    void **table;               /* The actual elements. */
-};
-
-
-/*
-**  Given a target table size, return the nearest power of two that's
-**  greater than or equal to that size, with a minimum size of four.  The
-**  minimum must be at least four to ensure that there is always at least
-**  one empty slot in the table given hash_find_slot's resizing of the table
-**  if it as least 75% full.  Otherwise, it would be possible for
-**  hash_find_slot to go into an infinite loop.
-*/
-static size_t
-hash_size(size_t target)
-{
-    int n;
-    size_t size;
-
-    size = target - 1;
-    for (n = 0; size > 0; n++)
-        size >>= 1;
-    size = 1 << n;
-    return (size < 4) ? 4 : size;
-}
-
-
-/*
-**  Create a new hash table.  The given size is rounded up to the nearest
-**  power of two for speed reasons (it greatly simplifies the use of the
-**  hash function).
-*/
-struct hash *
-hash_create(size_t size, hash_func hash_f, hash_key_func key_f,
-            hash_equal_func equal_f, hash_delete_func delete_f)
-{
-    struct hash *hash;
-
-    hash = xcalloc(1, sizeof(struct hash));
-    hash->hash = hash_f;
-    hash->key = key_f;
-    hash->equal = equal_f;
-    hash->delete = delete_f;
-    hash->size = hash_size(size);
-    hash->mask = hash->size - 1;
-    hash->table = xcalloc(hash->size, sizeof(void *));
-    return hash;
-}
-
-
-/*
-**  Free a hash and all resources used by it, and call the delete function
-**  on every element.
-*/
-void
-hash_free(struct hash *hash)
-{
-    size_t i;
-    void *entry;
-
-    for (i = 0; i < hash->size; i++) {
-        entry = hash->table[i];
-        if (entry != HASH_EMPTY && entry != HASH_DELETED)
-            (*hash->delete)(entry);
-    }
-    free(hash->table);
-    free(hash);
-}
-
-
-/*
-**  Internal search function used by hash_expand.  This is an optimized
-**  version of hash_find_slot that returns a pointer to the first empty
-**  slot, not trying to call the equality function on non-empty slots and
-**  assuming there are no HASH_DELETED slots.
-*/
-static void **
-hash_find_empty(struct hash *hash, const void *key)
-{
-    size_t slot;
-
-    slot = (*hash->hash)(key) & hash->mask;
-    while (1) {
-        if (hash->table[slot] == HASH_EMPTY)
-            return &hash->table[slot];
-
-        slot++;
-        if (slot >= hash->size)
-            slot -= hash->size;
-    }
-}
-
-
-/*
-**  Expand the hash table to be approximately 50% empty based on the number
-**  of elements in the hash.  This is done by allocating a new table and
-**  then calling hash_find_empty for each element in the previous table,
-**  recovering the key by calling hash->key on the element.
-*/
-static void
-hash_expand(struct hash *hash)
-{
-    void **old, **slot;
-    size_t i, size;
-
-    old = hash->table;
-    size = hash->size;
-    hash->size = hash_size((hash->nelements - hash->ndeleted) * 2);
-    hash->mask = hash->size - 1;
-    hash->table = xcalloc(hash->size, sizeof(void *));
-
-    hash->nelements = 0;
-    hash->ndeleted = 0;
-    for (i = 0; i < size; i++)
-        if (old[i] != HASH_EMPTY && old[i] != HASH_DELETED) {
-            slot = hash_find_empty(hash, (*hash->key)(old[i]));
-            *slot = old[i];
-            hash->nelements++;
-        }
-
-    hash->expansions++;
-    free(old);
-}
-
-
-/*
-**  Find a slot in the hash for a given key.  This is used both for
-**  inserting and deleting elements from the hash, as well as looking up
-**  entries.  Returns a pointer to the slot.  If insert is true, return the
-**  first empty or deleted slot.  If insert is false, return NULL if the
-**  element could not be found.
-**
-**  This function assumes that there is at least one empty slot in the
-**  hash; otherwise, it can loop infinitely.  It attempts to ensure this by
-**  always expanding the hash if it is at least 75% full; this will ensure
-**  that property for any hash size of 4 or higher.
-*/
-static void **
-hash_find_slot(struct hash *hash, const void *key, bool insert)
-{
-    void **deleted_slot = NULL;
-    void *entry;
-    size_t slot;
-
-    if (insert && hash->nelements * 4 >= hash->size * 3)
-        hash_expand(hash);
-
-    hash->searches++;
-
-    slot = (*hash->hash)(key) & hash->mask;
-    while (1) {
-        entry = hash->table[slot];
-        if (entry == HASH_EMPTY) {
-            if (!insert)
-                return NULL;
-
-            if (deleted_slot != NULL) {
-                *deleted_slot = HASH_EMPTY;
-                hash->ndeleted--;
-                return deleted_slot;
-            }
-            hash->nelements++;
-            return &hash->table[slot];
-        } else if (entry == HASH_DELETED) {
-            if (insert)
-                deleted_slot = &hash->table[slot];
-        } else if ((*hash->equal)(key, entry)) {
-            return &hash->table[slot];
-        }
-
-        hash->collisions++;
-        slot++;
-        if (slot >= hash->size)
-            slot -= hash->size;
-    }
-}
-
-
-/*
-**  Given a key, return the entry corresponding to that key or NULL if that
-**  key isn't present in the hash table.
-*/
-void *
-hash_lookup(struct hash *hash, const void *key)
-{
-    void **slot;
-
-    slot = hash_find_slot(hash, key, false);
-    return (slot == NULL) ? NULL : *slot;
-}
-
-
-/*
-**  Insert a new key/value pair into the hash, returning true if the
-**  insertion was successful and false if there is already a value in the
-**  hash with that key.
-*/
-bool
-hash_insert(struct hash *hash, const void *key, void *datum)
-{
-    void **slot;
-
-    slot = hash_find_slot(hash, key, true);
-    if (*slot != HASH_EMPTY)
-        return false;
-    *slot = datum;
-    return true;
-}
-
-
-/*
-**  Replace an existing hash value with a new data value, calling the delete
-**  function for the old data.  Returns true if the replacement was
-**  successful or false (without changing the hash) if the key whose value
-**  should be replaced was not found in the hash.
-*/
-bool
-hash_replace(struct hash *hash, const void *key, void *datum)
-{
-    void **slot;
-
-    slot = hash_find_slot(hash, key, false);
-    if (slot == NULL)
-        return false;
-    (*hash->delete)(*slot);
-    *slot = datum;
-    return true;
-}
-
-
-/*
-**  Delete a key out of the hash.  Returns true if the deletion was
-**  successful, false if the key could not be found in the hash.
-*/
-bool
-hash_delete(struct hash *hash, const void *key)
-{
-    bool result;
-
-    result = hash_replace(hash, key, HASH_DELETED);
-    if (result)
-        hash->ndeleted++;
-    return result;
-}
-
-
-/*
-**  For each element in the hash table, call the provided function, passing
-**  it the element and the opaque token that's passed to this function.
-*/
-void
-hash_traverse(struct hash *hash, hash_traverse_func callback, void *data)
-{
-    size_t i;
-    void *entry;
-
-    for (i = 0; i < hash->size; i++) {
-        entry = hash->table[i];
-        if (entry != HASH_EMPTY && entry != HASH_DELETED)
-            (*callback)(entry, data);
-    }
-}
-
-
-/*
-**  Returns a count of undeleted elements in the hash.
-*/
-unsigned long
-hash_count(struct hash *hash)
-{
-    return hash->nelements - hash->ndeleted;
-}
-
-
-/*
-**  Accessor functions for the debugging statistics.
-*/
-unsigned long
-hash_searches(struct hash *hash)
-{
-    return hash->searches;
-}
-
-unsigned long
-hash_collisions(struct hash *hash)
-{
-    return hash->collisions;
-}
-
-unsigned long
-hash_expansions(struct hash *hash)
-{
-    return hash->expansions;
-}
-
-
-/*
-**  Mix three 32-bit values reversibly.  This is the internal mixing
-**  function for the hash function.
-**
-**  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() takes 36 machine instructions, but only 18 cycles on a superscalar
-**  machine (like a Pentium or a Sparc).  No faster mixer seems to work,
-**  that's the result of my brute-force search.  There were about 2^68
-**  hashes to choose from.  I (Bob Jenkins) only tested about a billion of
-**  those.
-*/
-#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) >> 13);     \
-        (a) -= (b); (a) -= (c); (a) ^= ((c) >> 12);     \
-        (b) -= (c); (b) -= (a); (b) ^= ((a) << 16);     \
-        (c) -= (a); (c) -= (b); (c) ^= ((b) >> 5);      \
-        (a) -= (b); (a) -= (c); (a) ^= ((c) >> 3);      \
-        (b) -= (c); (b) -= (a); (b) ^= ((a) << 10);     \
-        (c) -= (a); (c) -= (b); (c) ^= ((b) >> 15);     \
-    }
-
-
-/*
-**  Hash a variable-length key into a 32-bit value.
-**
-**  Takes byte sequence to hash and returns a 32-bit value.  A partial
-**  result can be passed as the third parameter so that large amounts of
-**  data can be hashed by subsequent calls, passing in the result of the
-**  previous call each time.  Every bit of the key affects every bit of the
-**  return value.  Every 1-bit and 2-bit delta achieves avalanche.  About
-**  (36 + 6n) instructions.
-**
-**  The best hash table sizes are powers of 2.  There is no need to mod with
-**  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 & ((1 << 10) - 1);
-**
-**  In which case, the hash table should have 2^10 elements.
-**
-**  Based on code by Bob Jenkins <bob_jenkins@burtleburtle.net>, originally
-**  written in 1996.  The original license was:
-**
-**      By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use
-**      this code any way you wish, private, educational, or commercial.
-**      It's free.
-**
-**  See <http://burlteburtle.net/bob/hash/evahash.html> for discussion of
-**  this hash function.  Use for hash table lookup, or anything where one
-**  collision in 2^32 is acceptable.  Do NOT use for cryptographic purposes.
-*/
-unsigned long
-hash_lookup2(const char *key, size_t length, unsigned long partial)
-{
-    uint32_t a, b, c, len;
-
-    /* Set up the internal state.  a and b are initialized to a golden
-       ratio, an arbitrary value intended to avoid mapping all zeroes to all
-       zeroes. */
-    len = length;
-    a = b = 0x9e3779b9;
-    c = partial;
-
-#define S0(c)   ((uint32_t)(c))
-#define S1(c)   ((uint32_t)(c) << 8)
-#define S2(c)   ((uint32_t)(c) << 16)
-#define S3(c)   ((uint32_t)(c) << 24)
-
-    /* Handle most of the key. */
-    while (len >= 12) {
-        a += S0(key[0]) + S1(key[1]) + S2(key[2])  + S3(key[3]);
-        b += S0(key[4]) + S1(key[5]) + S2(key[6])  + S3(key[7]);
-        c += S0(key[8]) + S1(key[9]) + S2(key[10]) + S3(key[11]);
-        MIX(a, b, c);
-        key += 12;
-        len -= 12;
-   }
-
-    /* Handle the last 11 bytes.  All of the cases fall through. */
-    c += length;
-    switch (len) {
-    case 11: c += S3(key[10]);
-    case 10: c += S2(key[9]);
-    case  9: c += S1(key[8]);
-        /* The first byte of c is reserved for the length. */
-    case  8: b += S3(key[7]);
-    case  7: b += S2(key[6]);
-    case  6: b += S1(key[5]);
-    case  5: b += S0(key[4]);
-    case  4: a += S3(key[3]);
-    case  3: a += S2(key[2]);
-    case  2: a += S1(key[1]);
-    case  1: a += S0(key[0]);
-        /* case 0: nothing left to add. */
-    }
-    MIX(a, b, c);
-    return c;
-}
-
-
-/*
-**  A hash function for nul-terminated strings using hash_lookup2, suitable
-**  for passing to hash_create.
-*/
-unsigned long
-hash_string(const void *key)
-{
-    return hash_lookup2(key, strlen(key), 0);
-}