/*
 * Simple hash table implementation.
 *
 * Nickolai Zeldovich <kolya@MIT.EDU>
 * September 2001
 */

#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>

#include "hashtab.h"

static u_char
hash_hval(const u_char *key_data, int key_len)
{
    u_char hashvalue = 0;
    int i;

    for (i=0; i<key_len; i++)
	hashvalue ^= key_data[i];
    return hashvalue;
}

static struct hashtab_ent *
hash_find(struct hashtab *h, const u_char *key_data, int key_len)
{
    u_char hashvalue = hash_hval(key_data, key_len);
    struct hashtab_ent **htep = &h->ent[hashvalue];
    struct hashtab_ent *hte;

    while (*htep) {
	hte = *htep;
	if (hte->keylen == key_len && 0 == memcmp(key_data, hte->key, key_len))
	    return hte;
	htep = &hte->next;
    }

    *htep = malloc(sizeof *hte);
    hte = *htep;

    memcpy((u_char *) hte->key, key_data, key_len);
    hte->keylen = key_len;
    hte->value = 0;
    hte->next = NULL;
    hte->iter_next = h->iter;
    h->iter = hte;
    h->keycount++;

    return hte;
}

struct hashtab *
hash_alloc()
{
    struct hashtab *h;
    int i;

    h = malloc(sizeof *h);
    for (i=0; i<HASHTAB_ENTRIES; i++)
	h->ent[i] = NULL;
    h->iter = NULL;
    h->keycount = 0;
    return h;
}

void
hash_free(struct hashtab *ht)
{
    int i;

    for (i=0; i<HASHTAB_ENTRIES; i++) {
	struct hashtab_ent *next;

	while (ht->ent[i]) {
	    next = ht->ent[i]->next;
	    free(ht->ent[i]);
	    ht->ent[i] = next;
	}
    }
    free(ht);
}

int
hash_get(struct hashtab *h, const u_char *key_data, int key_len)
{
    struct hashtab_ent *hte = hash_find(h, key_data, key_len);
    return hte->value;
}

void
hash_put(struct hashtab *h, const u_char *key_data, int key_len, int value)
{
    struct hashtab_ent *hte = hash_find(h, key_data, key_len);
    hte->value = value;
}

int
hash_keycount(struct hashtab *h)
{
    return h->keycount;
}

void *
hash_get_iter(struct hashtab *h)
{
    return h->iter;
}

void *
hash_get_iter_next(void *opaque)
{
    struct hashtab_ent *hte = (struct hashtab_ent *) opaque;
    return hte->iter_next;
}

const u_char *
hash_get_iter_key(void *opaque)
{
    struct hashtab_ent *hte = (struct hashtab_ent *) opaque;
    return hte->key;
}

int
hash_get_iter_key_len(void *opaque)
{
    struct hashtab_ent *hte = (struct hashtab_ent *) opaque;
    return hte->keylen;
}
