#ifndef HASH_H
# define HASH_H
# ifndef GPK_STD_H
#  include <gpk_std.h>
# endif
# include <assert.h>

template<class K, class V>
class hashitem	{
	BOOL full;
	K Key;
	V Value; 
	public:
	hashitem() : full(FALSE)	{}
	~hashitem()	{}
	BOOL filled() C	{return full;}
	hashitem<K,V> *set(C K& k, C V& v)
		{ if(!full) {Key = k; full=TRUE;} Value=v; return this;}
	hashitem<K,V> *set(C V& v)	{ assert(full); Value = v; return this;}
	void unset()	{full = FALSE;}
	C K& key() C	{assert(full); return Key;}
	C V& value() C	{assert(full); return Value;}
	V& value() {assert(full); return Value;}
	};

template<class K, class V>
class hash_iterator;

template<class K, class V>
class hashtable	{
	protected:
	int getidx(C K & k) C;
	hashitem<K,V> *tbl;

	private:
	void steal_from(hashtable<K,V> *p);
	hashtable();
	hashtable(C hashtable<K,V>&);
	operator=(C hashtable<K,V>&);
	friend class hash_iterator<K,V>;

	int (*hashfunction)(C K&, int);
	int n;

	public:
	hashtable(int nn, int(*hashf)(C K&,int));
	virtual ~hashtable()	{delete [] tbl;}
	C hashitem<K,V> * getptr(C K& k) C;
	BOOL check(C K& k) C	{ return getptr(k)!=0;}
	C V& get(C K& k) C;
	/* BOOL unset(C K& k); */
	hashitem<K,V> *set(C K& k, C V& color);
	int size() C {return n;}
	int count() C;
	BOOL rehash(int nn);
	};


template<class K, class V>
class hash_iterator	{
	C hashtable<K,V> *p;
	C hashitem<K,V> *pi, *pbot, *ptop;
	hash_iterator();

	public:
	hash_iterator(C hashtable<K,V>& a);
	operator int() C	{return pi-pbot;}
	void next();
	void previous();
	BOOL valid() C	{return pi<ptop && pi>=pbot && pi->filled();}
	void reset();
	void end();
	C K& key() C	{return pi->key();}
	C V& value() C	{return pi->value();}
	C hashitem<K,V> *item() C	{return pi;}
	};

/* A double hash is tightly constrained -- it's a 1:1 mapping;
	no two keys may be equal and no two values may be equal. */
template<class K, class V>
class doublehash : public hashtable<K,V>	{
	private:
	doublehash();
	doublehash(C doublehash<K,V>&);
	operator=(C doublehash<K,V>&);
	int r_getidx(C V& k) C;
	hashitem<K,V> **rtbl;
	int (*reversehash)(C V&, int);

	public:
	doublehash(int nn, int (*hashf)(C K&, int), int (*rhash)(C V&, int));
	virtual ~doublehash()	{delete [] rtbl;}
	BOOL r_check(C V& k) C	{return r_getptr(k)!=0;}
	C K& r_get(C V& k) C;
	C hashitem<K,V> * r_getptr(C V& k) C;
	C hashitem<K,V> *set(C K& k, C V& color);
	/* BOOL r_unset(C V& v); */
	int size() C	{return rtbl ? hashtable<K,V>::size() : 0;}
	int count() C	{return rtbl ? hashtable<K,V>::count() : 0;}
	};


#endif
