/*
 * Copyright (c) 2003, 2004 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 *	$Id: bht-int.h,v 1.12 2005/06/16 00:09:34 ca Exp $
 */

/*
**  This file may be included multiple times! Do NOT protect against that.
*/

#include "sm/types.h"
#include "sm/error.h"

/* Structure of one hash table entry. */
typedef struct sm_bht_entry_S sm_bht_entry_T, *sm_bht_entry_P;

struct sm_bht_entry_S
{
	/*
	**  Notice: we don't copy keys (or value)!
	**	These are just pointers to the original data.
	**	Hence they must be "persistent".
	**  Question: do we want to add an option to make a copy?
	*/

	char		*bhe_key;	/* lookup key */
	uint		 bhe_len;	/* key length */
	void		*bhe_value;	/* associated value */

	/* XXX should we use something from queue.h? */
	sm_bht_entry_P	 bhe_next;	/* colliding entry */
	sm_bht_entry_P	 bhe_prev;	/* colliding entry */
#if SM_TWO_KEYS
	char		*bhe_key2;	/* lookup key */
	uint		 bhe_len2;	/* key length */
	sm_bht_entry_P	 bhe_next2;	/* colliding entry */
	sm_bht_entry_P	 bhe_prev2;	/* colliding entry */
#endif /* SM_TWO_KEYS */
};

/* Structure of one hash table. */
typedef struct sm_bht_S sm_bht_T, *sm_bht_P;
struct sm_bht_S
{
	uint		 bht_size;	/* length of entries array */
	uint		 bht_used;	/* number of entries in table */
	uint		 bht_limit;	/* max number of entries */
#if SM_BHT_PERF
	/* performance (statistics) data */
	ulong		 bht_adds;	/* */
	ulong		 bht_lookups;	/* */
	ulong		 bht_deletes;	/* */
	ulong		 bht_acollisions;	/* */
	ulong		 bht_lcollisions;	/* */
	ulong		 bht_dcollisions;	/* */
	uint		 bht_grows;	/* */
	uint		 bht_chainlen;	/* */
	uint		 bht_chainmax;	/* */
#endif /* SM_BHT_PERF */
	sm_bht_entry_P	*bht_data;	/* entries array, auto-resized */
#if SM_TWO_KEYS
	sm_bht_entry_P	*bht_data2;	/* entries array, auto-resized */
#endif /* SM_TWO_KEYS */
};

/*
**  bhfree_F should get both keys for the TWO_KEY case...
**  or none at all (which makes some it harder for some applications
**  that don't store the key in the value (struct)).
*/

typedef void		 (*sm_bhfree_F)(void *_value, void *_key, void *_ctx);
typedef sm_ret_T	 (*sm_bhwalk_F)(sm_bht_entry_P, void *);

sm_bht_P	 sm_bht_new(uint _size, uint _limit);
sm_ret_T	 sm_bht_create(sm_bht_P *_ptable);
sm_ret_T	 sm_bht_setopt(sm_bht_P _table, uint _htsize, uint _limit);
sm_ret_T	 sm_bht_getopt(sm_bht_P _table, uint *_phtsize, uint *_plimit);
sm_ret_T	 sm_bht_open(sm_bht_P *_ptable);

sm_ret_T	 sm_bht_add(sm_bht_P _bht, char *_key, uint _len,
#if SM_TWO_KEYS
				char *_key2, uint _len2,
#endif /* SM_TWO_KEYS */
				void *_value, sm_bht_entry_P *_entry);

sm_bht_entry_P	 sm_bht_locate(sm_bht_P _bht, const char *_key, uint _len);

void	*sm_bht_find(sm_bht_P _bht, const char *_key, uint _len);

void	 sm_bht_rm(sm_bht_P _bht, const char *_key, uint _len,
				sm_bhfree_F _free_fn, void *_ctx);

void	 sm_bht_rm_all(sm_bht_P _bht, const char *_key, uint _len,
				sm_bhfree_F _free_fn, void *_ctx);

void	 sm_bht_destroy(sm_bht_P _bht, sm_bhfree_F _free_fn, void *_ctx);

sm_ret_T sm_bht_walk(sm_bht_P _bht, sm_bhwalk_F _fn, void *);

#if 0
sm_bht_entry_P	*sm_bht_list(sm_bht_P _bht);
#endif /* 0 */

void	 sm_bht_stats(sm_bht_P _bht, char *_out, uint _len);

#ifndef SM_BHT_INT_H
#define SM_BHT_INT_H
/* For external access to the list */
#define bht_entry_next(bhe)	((bhe)->bhe_next)
#define bht_entry_prev(bhe)	((bhe)->bhe_prev)

#define bht_entry_key(bhe)	((bhe)->bhe_key)
#define bht_entry_keylen(bhe)	((bhe)->bhe_len)
#define bht_entry_value(bhe)	((bhe)->bhe_value)

#if SM_BHT_PERF
# define bhtincradd(table)	((table)->bht_adds++)
# define bhtincrlu(table)	((table)->bht_lookups++)
# define bhtincrdel(table)	((table)->bht_deletes++)
# define bhtincracol(table)	((table)->bht_acollisions++)
# define bhtincrlcol(table)	((table)->bht_lcollisions++)
# define BHTINCRDCOL(table, elem)	do {	\
	if ((elem)->bhe_next != NULL || (elem)->bhe_prev != NULL)	\
			(table)->bht_dcollisions++;			\
	} while (0)
# define bhtincrgrows(table)	((table)->bht_grows++)
# define bhtinitchain(table)	(table)->bht_chainlen = 0
# define BHTINCRCHAIN(table)	do {	\
					if (++(table)->bht_chainlen >	\
					    (table)->bht_chainmax)	\
						(table)->bht_chainmax =	\
							(table)->bht_chainlen;\
				} while (0)
# define BHTCHAINLEN(table, elem) do {	\
					sm_bht_entry_P h;		\
					(table)->bht_chainlen = 0;	\
					h = elem;			\
					while (h != NULL)		\
					{				\
						++(table)->bht_chainlen;\
						h = h->bhe_next;	\
					}				\
					if ((table)->bht_chainlen >	\
					    (table)->bht_chainmax)	\
						(table)->bht_chainmax =	\
							(table)->bht_chainlen;\
				} while (0)
#else /* SM_BHT_PERF */
# define bhtincradd(table)
# define bhtincrlu(table)
# define bhtincrdel(table)
# define bhtincracol(table)
# define bhtincrlcol(table)
# define BHTINCRDCOL(table, elem)
# define bhtincrgrows(table)
# define bhtinitchain(table)
# define BHTINCRCHAIN(table)
# define BHTCHAINLEN(table, elem)
#endif /* SM_BHT_PERF */

#endif /* SM_BHT_INT_H */


syntax highlighted by Code2HTML, v. 0.9.1