#ifndef _H_JHashTable
#define _H_JHashTable

/******************************************************************************
 JHashTable.h

	Interface for the JHashTable and JHashRecord classes.

	Copyright © 1997 by Dustin Laurence.  All rights reserved.
	
	Base code generated by Codemill v0.1.0

 *****************************************************************************/

#include <jTypes.h>

#include <JHashRecord.h>
#include <JHashCursor.h>

//#include <JHashTableCursor.h>

	// This value comes from Sedgewick, should ensure less than five probes on average
	// for a search miss and fewer for a hit.
	const JFloat kJDefaultMaxLoadFactor = 0.8;

	const JFloat kJDefaultMinFillFactor = 0.1;
	const JSize  kJDefaultLgMinTableSize = 5;

template <class V>
class JHashTable
{
//	friend class JHashTableCursor<V>;
	friend class JConstHashCursor<V>;
	friend class JHashCursor<V>;

public:

	JHashTable(const JSize lgSize = kJDefaultLgMinTableSize);
	virtual ~JHashTable();

// Useful for any hash table

	JSize GetElementCount() const;

// Statistics

	JSize GetLgSize() const;
	JSize GetLoadCount() const;
	JSize GetTableSize() const;

	JFloat GetFillFactor() const;
	JFloat GetLoadFactor() const;

// Should this really be part of the *public* interface?!?
	JBoolean GetResizeEnabled() const;
	void     SetResizeEnabled(const JBoolean enabled);

	JFloat GetMaxLoadFactor() const;
	void   SetMaxLoadFactor(const JFloat newMax);

	JFloat GetMinFillFactor() const;
	void   SetMinFillFactor(const JFloat newMin);

	JSize  GetMinTableSize() const;
	void   SetMinTableSize(const JSize newMin);

	JBoolean IsOK() const;

protected:

// Cursor control
	void AllowCursors();
	void DisallowCursors();

	JHashCursor<V>*      GetCursor();
	JConstHashCursor<V>* GetCursor() const;

// Key manipulation functions
	void SetKeyComparison(JBoolean (* const keysEqual)(const V&, const V&) );
	void GetKeyComparison( JBoolean (**keysEqual)(const V&, const V&) ) const;

	// Predefined comparison functions
	static JBoolean AssertReturnTrue(const V& value1, const V& value2);
	static JBoolean ReturnTrue(const V& value1, const V& value2);

	void SetHashFunction(JHashValue (* const hashFunction)(const V&) );
	void GetHashFunction(JHashValue (**hashFunction)(const V&) ) const;

	// Predefined hash functions
	static JHashValue Abort(const V& key);

// Get... values
	const JHashRecord<V>& GetRecord(const JSize index) const;

	JHashRecordT::State GetState(const JSize index) const;
	JBoolean            IsEmpty(const JSize index) const;
	JBoolean            IsDeleted(const JSize index) const;
	JBoolean            IsFull(const JSize index) const;

	JHashValue          GetHashValue(const JSize index) const;

	const V&            GetValue(const JSize index) const;

// Set values
	void Set(const JSize index, const JHashRecord<V>& record);
	void Set(const JSize index, const JHashValue hash, const V& value);
	void Set(const JSize index, const V& value);
	void SetHash(const JSize index, const V& value);

	void Remove(const JSize index);
	void MarkEmpty(const JSize index);
	void MarkAllEmpty();


// Low-level resizing interface--useful when overriding FitToLimits
	JBoolean TryResizeTable(const JSize lgSize);
	void ResizeTable(const JSize lgTrialSize);

// Main resize function
	virtual JBoolean FitToLimits(const JSize required = 0,
	                             const JBoolean force = kFalse);

// For use by cursors
	JSize HashToIndex(JHashValue hash) const;

private:

	JSize             itsLgSize;
	JSize             itsMaxIndex;
	JHashRecord<V>* itsArray;

	JHashCursor<V>* itsCursor;

	JSize itsElementCount; // Number that are full, different than the array size!
	JSize itsLoadCount;

	JBoolean itsResizeFlag;
	JFloat   itsMaxLoadFactor;
	JFloat   itsMinFillFactor;
	JSize    itsLgMinTableSize;

	JBoolean (*itsEqual)(const V&, const V&);
	JHashValue (*itsHashFunction)(const V&);

	JBoolean itsAllowCursorFlag;

private:

	void     _MarkAllEmpty();
	JBoolean TryInsert(const JHashRecord<V>& record);
	JBoolean TryInsertAll(const JHashTable<V>* source);

	// not allowed

	JHashTable(const JHashTable& source);
	const JHashTable& operator=(const JHashTable& source);
};

/******************************************************************************
 GetElementCount

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::GetElementCount() const
{
	return itsElementCount;
}

/******************************************************************************
 GetLgSize

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::GetLgSize() const
{
	return itsLgSize;
}

/******************************************************************************
 GetLoadCount

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::GetLoadCount() const
{
	return itsLoadCount;
}

/******************************************************************************
 GetTableSize

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::GetTableSize() const
{
	return itsMaxIndex + 1;
}

/******************************************************************************
 GetFillFactor

 *****************************************************************************/

template <class V>
inline JFloat
JHashTable<V>::GetFillFactor() const
{
	return ( (JFloat) GetElementCount())/GetTableSize();
}

/******************************************************************************
 GetLoadFactor

 *****************************************************************************/

template <class V>
inline JFloat
JHashTable<V>::GetLoadFactor() const
{
	return ( (JFloat) GetLoadCount())/GetTableSize();
}

/******************************************************************************
 GetResizeEnabled

 *****************************************************************************/

template <class V>
inline JBoolean
JHashTable<V>::GetResizeEnabled() const
{
	return itsResizeFlag;
}

/******************************************************************************
 GetMaxLoadFactor

 *****************************************************************************/

template <class V>
inline JFloat
JHashTable<V>::GetMaxLoadFactor() const
{
	return itsMaxLoadFactor;
}

/******************************************************************************
 GetMinFillFactor

 *****************************************************************************/

template <class V>
inline JFloat
JHashTable<V>::GetMinFillFactor() const
{
	return itsMinFillFactor;
}

/******************************************************************************
 GetMinTableSize

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::GetMinTableSize() const
{
	return (1 << itsLgMinTableSize);
}

/******************************************************************************
 GetKeyComparison

 *****************************************************************************/

template <class V>
inline void
JHashTable<V>::GetKeyComparison
	(
	JBoolean (**keysEqual)(const V&, const V&)
	)
	const
{
	*keysEqual = itsEqual;
}

/******************************************************************************
 GetHashFunction

 *****************************************************************************/

template <class V>
inline void
JHashTable<V>::GetHashFunction
	(
	JHashValue (**hashFunction)(const V&)
	)
	const
{
	*hashFunction = itsHashFunction;
}

/******************************************************************************
 AllowCursors (protected)

 *****************************************************************************/

template <class V>
inline void
JHashTable<V>::AllowCursors()
{
	itsAllowCursorFlag = kTrue;
}

/******************************************************************************
 DisallowCursors (protected)

 *****************************************************************************/

template <class V>
inline void
JHashTable<V>::DisallowCursors()
{
	itsAllowCursorFlag = kFalse;
}

/******************************************************************************
 GetCursor (protected)

 *****************************************************************************/

template <class V>
inline JHashCursor<V>*
JHashTable<V>::GetCursor()
{
	return itsCursor;
}

template <class V>
inline JConstHashCursor<V>*
JHashTable<V>::GetCursor() const
{
	return itsCursor;
}

/******************************************************************************
 GetRecord (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline const JHashRecord<V>&
JHashTable<V>::GetRecord
	(
	const JSize index
	)
	const
{
	return itsArray[index];
}

/******************************************************************************
 GetState (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline JHashRecordT::State
JHashTable<V>::GetState
	(
	const JSize index
	)
	const
{
	return itsArray[index].GetState();
}

/******************************************************************************
 IsEmpty (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline JBoolean
JHashTable<V>::IsEmpty
	(
	const JSize index
	)
	const
{
	return itsArray[index].IsEmpty();
}

/******************************************************************************
 IsDeleted (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline JBoolean
JHashTable<V>::IsDeleted
	(
	const JSize index
	)
	const
{
	return itsArray[index].IsDeleted();
}

/******************************************************************************
 IsFull (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline JBoolean
JHashTable<V>::IsFull
	(
	const JSize index
	)
	const
{
	return itsArray[index].IsFull();
}

/******************************************************************************
 GetHashValue (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline JHashValue
JHashTable<V>::GetHashValue
	(
	const JSize index
	)
	const
{
	return itsArray[index].GetHashValue();
}

/******************************************************************************
 GetValue (protected)

	Warning: no bounds checking, and the argument must be an index because it
	is not wrapped to the tablesize!

 *****************************************************************************/

template <class V>
inline const V&
JHashTable<V>::GetValue
	(
	const JSize index
	)
	const
{
	return itsArray[index].GetValue();
}

/******************************************************************************
 HashToIndex (protected)

 *****************************************************************************/

template <class V>
inline JSize
JHashTable<V>::HashToIndex
	(
	JHashValue hash
	)
	const
{
	return hash & itsMaxIndex;
}

#endif
