/*
 * Copyright (C) 2006 iptelorg GmbH
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _str_hashs_h
#define _str_hashs_h

#include "str.h"
#include "hashes.h"
#include "mem/mem.h"
#include "clist.h"
#include <string.h>


/* generic, simple str keyed hash */

struct str_hash_entry
{
	struct str_hash_entry *next;
	struct str_hash_entry *prev;
	str key;
	unsigned int flags;
	union
	{
		void *p;
		char *s;
		int n;
		char data[sizeof(void *)];
	} u;
};


struct str_hash_head
{
	struct str_hash_entry *next;
	struct str_hash_entry *prev;
};


struct str_hash_table
{
	struct str_hash_head *table;
	int size;
};


/* returns 0 on success, <0 on failure */
inline static int str_hash_alloc(struct str_hash_table *ht, int size)
{
	ht->table = (struct str_hash_head *)pkg_mallocxz(
			sizeof(struct str_hash_head) * size);
	if(ht->table == 0) {
		PKG_MEM_ERROR;
		return -1;
	}
	ht->size = size;
	return 0;
}


inline static void str_hash_init(struct str_hash_table *ht)
{
	int r;

	for(r = 0; r < ht->size; r++)
		clist_init(&(ht->table[r]), next, prev);
}


inline static void str_hash_add(
		struct str_hash_table *ht, struct str_hash_entry *e)
{
	int h;

	h = get_hash1_raw(e->key.s, e->key.len) % ht->size;
	clist_insert(&ht->table[h], e, next, prev);
}


inline static struct str_hash_entry *str_hash_get(
		struct str_hash_table *ht, const char *key, int len)
{
	int h;
	struct str_hash_entry *e;

	h = get_hash1_raw(key, len) % ht->size;
	clist_foreach(&ht->table[h], e, next)
	{
		if((e->key.len == len) && (memcmp(e->key.s, key, len) == 0))
			return e;
	}
	return 0;
}

inline static void str_hash_case_add(
		struct str_hash_table *ht, struct str_hash_entry *e)
{
	int h;

	h = get_hash1_case_raw(e->key.s, e->key.len) % ht->size;
	clist_insert(&ht->table[h], e, next, prev);
}


inline static struct str_hash_entry *str_hash_case_get(
		struct str_hash_table *ht, const char *key, int len)
{
	int h;
	struct str_hash_entry *e;

	h = get_hash1_case_raw(key, len) % ht->size;
	clist_foreach(&ht->table[h], e, next)
	{
		if((e->key.len == len) && (strncasecmp(e->key.s, key, len) == 0))
			return e;
	}
	return 0;
}

#define str_hash_del(e) clist_rm(e, next, prev)

#endif
