/*
	ZHashMap.hpp
	Author: James Russell <jcrussell@762studios.com>
	Created: 12/24/2011

	Purpose: 

	Templated hash map implementation.

	License:

	This program is free software. It comes without any warranty, to
	the extent permitted by applicable law. You can redistribute it
	and/or modify it under the terms of the Do What The Fuck You Want
	To Public License, Version 2, as published by Sam Hocevar. See
	http://sam.zoy.org/wtfpl/COPYING for more details.

*/

#pragma once

#ifndef _ZHASHMAP_HPP
#define _ZHASHMAP_HPP

#include <ZSTL/ZPair.hpp>
#include <ZSTL/ZArray.hpp>
#include <ZSTL/ZList.hpp>

//Default number of buckets
#ifndef ZHASHMAP_DEFAULT_BUCKETS
#define ZHASHMAP_DEFAULT_BUCKETS (31)
#endif

//Default load factor for the HashMap (expressed as an integer percentage LF / 100)
#ifndef ZHASHMAP_DEFAULT_LOADFACTOR
#define ZHASHMAP_DEFAULT_LOADFACTOR (75)
#endif

//Factor by which HashMap grows when loadfactor is exceeded
#ifndef ZHASHMAP_DEFAULT_GROWFACTOR
#define ZHASHMAP_DEFAULT_GROWFACTOR (2.0)
#endif

//Number of nodes for the lists stored locally (safe since we never splice)
#ifndef ZHASHMAP_DEFAULT_LOCAL_NODES
#define ZHASHMAP_DEFAULT_LOCAL_NODES (10)
#endif

//Forward Declaration of ZHashMap
template < typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA >
class ZHashMap;

//Forward Declaration of ZHashMapIterator
template <typename K, typename V, typename HT>
class ZHashMapIterator;

/* 
Forward Declaration of ZHashMap Method Implementation Structures 

Existence of these structures allows for template specialization of 
individual methods of the ZHashMap class.  In order to specialize
a single method of ZHashMap, simply specialize the corresponding
method implementation structure.
*/

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Clear struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_ClearImpl {
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::ContainsKey struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_ContainsKeyImpl {
	inline static bool Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::ContainsValue struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_ContainsValueImpl {
	inline static bool Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const V& _value);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Empty struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_EmptyImpl {
	inline static bool Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Erase struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_EraseImpl {
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key);
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, ZHashMapIterator<K, V, HT>& _itr);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Get struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_GetImpl {
	inline static V& Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Put struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_PutImpl {
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key);
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key, const V& _value);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Resize struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_ResizeImpl {
	inline static void Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, size_t _buckets);
};

//Forward Declaration of ZHashMap<K, V, HT, H, LF, LA, AA>::Size struct
template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
struct ZHashMap_SizeImpl {
	inline static size_t Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self);
};

///////////////////////////////////////
/* Hash Comparator, Hasher, HashNode */
///////////////////////////////////////

/*
Hash comparator class, which compares elements with the == operator.
*/
template <typename T>
struct ZHashComparator
{
	ZHashComparator() { } //Silence Sun C++ warnings about uninitialized structs

	//operator overload which returns true if equivalent (as per ==), false otherwise
	bool operator () (const T& _a, const T& _b) const
	{
		if ((T)_a == (T)_b)
			return true;
		else
			return false;
	}
};

/*
Hasher class, which produces hash values of objects for use in ZHashMap.

The template parameter T is the type we will be hashing.
The template parameter HT is the hash type that is computed.
*/
template <typename T, typename HT>
class ZHasher
{
public:
	//Comparator for use with equals and less than
	ZHashComparator<T> Comp;

	//Default hash function, which attempts to cast the object as a hash value
	HT Hash(const T& _obj) const
	{
		return (HT)(uintptr_t)_obj; //Since 'HT' may be 32-bit, but '_obj' may be a pointer, this can cause compile errors.
	}

	//Default comparison function, which compares objects (should return 0 if not equal, !0 otherwise)
	int Equals(const T& _first, const T& _second) const
	{
		return Comp(_first, _second);
	}
};

/*
Hash node structure, which contains a key, a value, and the pre-computed hash for 
the key as well as the hash mod (bucket).  This node is stored within a ZListNode
for hash chaining.

The template parameter K is the key type.
The template parameter V is the value type.
The template parameter HT is the hash type.
*/
template <typename K, typename V, typename HT>
struct ZHashNode
{
	ZHashNode() { }	//Silence Sun C++ warnings about uninitialized structs

	K			Key;		//The contained key
	V			Value;		//The contained value
	HT			Hash;		//The hash of the key
	size_t		HashMod;	//The hash mod number of buckets (gives bucket)
};

///////////////////////
/* ZHashMap Iterator */
///////////////////////

/*
Iterator for ZHashMap.

The template parameter K is the key type.
The template parameter V is the value type.
The template parameter HT is the hash type.
*/
template <typename K, typename V, typename HT>
class ZHashMapIterator
{
private:
	//The current node we are pointing to
	ZListNode< ZHashNode<K, V, HT> > *Node;

	//The end node of the map
	ZListNode< ZHashNode<K, V, HT> > *EndNode;

public:
	/*
	Default Constructor.
	*/
	ZHashMapIterator() 
		: Node(NULL), EndNode(NULL) { }

	/*
	Useful constructor.

	@param _node - the node we are to begin iterating at
	*/
	ZHashMapIterator(ZListNode< ZHashNode<K, V, HT> >* _node, ZListNode< ZHashNode<K, V, HT> >* _endNode) 
		: Node(_node), EndNode(_endNode) { }

	/*	
	Copy Constructor.

	@param _other - the other iterator
	*/
	ZHashMapIterator(const ZHashMapIterator& _other) 
		: Node(_other.Node), EndNode(_other.EndNode) { }
	
	/*
	public ZHashMapIterator<K, V, HT>::CheckNodeCurrent
	
	Node check function that does not allow the current node to point to NULL.
	
	@return (void)
	*/
	void CheckNodeCurrent() const
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(Node != NULL, "ZHashMap Iterator Invalid!");
		#endif
	}

	/*
	public ZHashMapIterator<K, V, HT>::CheckNodeNext
	
	Node check function that does not allow Node to be 'End'
	
	@return (void)
	*/
	void CheckNodeNext() const
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(Node != NULL && Node != EndNode, "ZHashMap Iterator Next Invalid!");
		#endif
	}

	/*
	public ZHashMapIterator<K, V, HT>::CheckNodePrevious
	
	Node check function that does not allow Node to be 'Begin'
	
	@return (void)
	*/
	void CheckNodePrevious() const
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(Node != NULL && Node->Previous != EndNode, "ZHashMap Iterator Previous Invalid!");
		#endif
	}
	
	/*
	public ZHashMapIterator<K, V, HT>::GetNode
	
	Gets the node that this iterator is currently pointed at.
	
	@return (ZListNode<T>*) - the node we are currently pointed at
	*/
	ZListNode< ZHashNode<K, V, HT> >* GetNode() const								
		{ return Node; }

	/*
	public ZHashMapIterator<K, V, HT>::SetNode
	
	Sets the current node for this iterator.  Useful for when the 
	underlying list changes state.
	
	@param _node - the node to point this iterator at
	@return (void)
	*/
	void SetNode(ZListNode< ZHashNode<K, V, HT> >* _node)							
		{ Node = _node; }

	/*
	public ZHashMapIterator<K, V, HT>::GetKey
	
	Gets the key this iterator points to.
	
	@return (const K&) - the key pointed to
	*/
	const K& GetKey() const										
		{ CheckNodeCurrent(); return Node->Element.Key; }

	/*
	public ZHashMapIterator<K, V, HT>::GetValue

	Gets the value this iterator points to.

	@return (V&) - the value pointed to
	*/
	V& GetValue() const
		{ CheckNodeCurrent(); return Node->Element.Value; }

	/*
	public ZHashMapIterator<K, V, HT>::HasCurrent
	
	Determines if this iterator currently points to a valid element.
	
	@return (bool) - true if element at current position
	*/
	bool HasCurrent() const								
		{ return Node != NULL && Node != EndNode; }

	/*
	public ZHashMapIterator<K, V, HT>::HasNext
	
	Determines if this iterator has a valid element after the current element.
	
	@return (bool) - true if element after current, false otherwise
	*/
	bool HasNext() const								
		{ return Node != NULL && Node != EndNode && Node->Next != EndNode; }

	/*
	public ZHashMapIterator<K, V, HT>::HasPrev
	
	Determines if this iterator has a valid element before the current element.
	
	@return (bool) - true if element before current, false otherwise
	*/
	bool HasPrev() const								
		{ return Node != NULL && Node->Previous != EndNode; }

	/*
	public ZHashMapIterator<K, V, HT>::Next
	
	Advances this iterator to the next element.
	
	@return (void)
	@assert - if this would advance past end
	*/
	void Next()											
		{ ++(*this); }

	/*
	public ZHashMapIterator<K, V, HT>::Prev
	
	Returns this iterator to the previous element.
	
	@return (void)
	@assert - if this would advance past begin
	*/
	void Prev()									
		{ --(*this); }

	/*
	public ZHashMapIterator<K, V, HT>::SetValue

	Sets the value mapped to the given key.

	@return (void)
	@assert - if this is the end node
	*/
	void SetValue(const V& _value)
		{  CheckNodeCurrent(); Node->Element.Value = _value; }


	//Operator overrides
	ZHashMapIterator& operator ++ ()								{ CheckNodeNext(); Node = Node->Next; return *this; }
	ZHashMapIterator  operator ++ (int)								{ ZListNode< ZHashNode<K, V, HT> > *node = Node; CheckNodeNext(); Node = Node->Next; return ZHashMapIterator(node, EndNode); }
	ZHashMapIterator  operator +  (int _value)						{ ZHashMapIterator itr(*this); for (int i = 0; i < _value; i++) ++itr; return itr; }
	ZHashMapIterator& operator += (int _value)						{ for (int i = 0; i < _value; i++) ++(*this); return *this; }
	
	ZHashMapIterator& operator -- ()								{ CheckNodePrevious(); Node = Node->Previous; return *this; }
	ZHashMapIterator  operator -- (int)								{ ZListNode< ZHashNode<K, V, HT> > *node = Node; CheckNodePrevious(); Node = Node->Previous; return ZHashMapIterator(node, EndNode); }
	ZHashMapIterator  operator -  (int _value)						{ ZHashMapIterator itr(*this); for (int i = _value; i > 0; i--) --itr; return itr; }
	ZHashMapIterator& operator -= (int _value)						{ for (int i = 0; i < _value; i--) --(*this); return *this; }

	ZHashMapIterator& operator = (const ZHashMapIterator &_other)	{ Node = _other.Node; EndNode = _other.EndNode; return *this; }
	bool operator == (const ZHashMapIterator& _other) const			{ return (Node == _other.Node) && (EndNode == _other.EndNode); }
	bool operator != (const ZHashMapIterator& _other) const			{ return !( (*this)==_other ); }

	const ZHashNode<K, V, HT>& operator * () const					{ CheckNodeCurrent(); return Node->Element; }
};

/////////////////////////////
/* ZHashMap Implementation */
/////////////////////////////

/*
Templated dynamic hash map implementation.  Uses chained hashing and (optional) load factor
balancing to ensure it behaves gracefully even under heavy load.  This implementation does
not maintain order between keys.

The template parameter K is the key type, which must be hashable.

The template parameter V is the value type, which need not be hashable.

The template parameter HT is the hash type.  This should generally correspond to something
like a 32-bit or 64-bit unsigned integer.  It must be compatible with the modulo operator.

The template parameter H is the hasher type, which defaults to the ZHasher for K using hash type
HT.  The hasher must expose the same methods as ZHasher (Hash, Equals).

The template parameter LF is the load factor of the hash map given as an integral value between
0 (hashmap will not resize) and 100.  Load factor is then computed as (double)(LF / 100).  Whenever 
the current load factor exceeds this value, the number of buckets is increased (map is resized).

The template parameter LA is the allocator type to use for list nodes.  It must allocate ZListNode
instances containing type ZHashNode<K, V, HT>.

The template parameter AA is the allocator type to pass along to the contained ZArray.  It must allocate
arrays of type ZListNode< ZHashNode< K, V > >*.
*/
template <typename K, typename V, 
		  typename HT = ZHashValue, typename H = ZHasher<K, HT>, size_t LF = ZHASHMAP_DEFAULT_LOADFACTOR,
		  typename LA = ZListPooledAllocator< ZHashNode<K, V, HT>, ZHASHMAP_DEFAULT_LOCAL_NODES >,
		  typename AA = ZArrayAllocator< ZListNode< ZHashNode<K, V, HT> >*, ZHASHMAP_DEFAULT_BUCKETS> >
class ZHashMap
{
friend struct ZHashMap_ClearImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_ContainsKeyImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_ContainsValueImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_EmptyImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_EraseImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_GetImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_PutImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_ResizeImpl<K, V, HT, H, LF, LA, AA>;
friend struct ZHashMap_SizeImpl<K, V, HT, H, LF, LA, AA>;

private:
	H		Hasher;			//The hasher for our keys
	LA		NodeAllocator;	//Allocator for chained hashing
	size_t	ElementCount;	//The element count

	ZArray< ZListNode< ZHashNode<K, V, HT> >*, AA>	Map;		//The map
	ZListNode< ZHashNode<K, V, HT> >				EmptyNode;	//The end node for the hash map

	//Resizes and copies the HashMap if we exceed LoadFactor (LF of 0 indicates we should not resize)
	inline void CheckLoadFactor()
	{
		//This will evaluate to false if LF == 0, true if LF > 0 (done to avoid C4127)
		if ((void)LF,LF)
		{
			double currentLoadFactor = LoadFactor();

			if (currentLoadFactor > ((double)LF / (double)100.0))
				Resize((size_t)((double)Map.Size() * ZHASHMAP_DEFAULT_GROWFACTOR));
		}
	}

	//Gets a bucket given a hash code
	inline size_t GetBucket(HT _hash) const
	{
		return _hash % Map.Size();
	}

public:
	/*
	Iterator type for ZHashMap.  Allows ZHashMap::Iterator notation.
	*/
	typedef ZHashMapIterator< K, V, HT > Iterator;

	/*
	Default Constructor.
	*/
	ZHashMap()
		: ElementCount(0), Map(ZHASHMAP_DEFAULT_BUCKETS)
	{
		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;

		Map.Resize(ZHASHMAP_DEFAULT_BUCKETS, NULL);
	}

	/*
	Parameterized Constructor.

	@param _buckets - the number of buckets the hashmap should use
	*/
	ZHashMap(size_t _buckets)
		: ElementCount(0), Map(_buckets)
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_buckets > 0, "Cannot make ZHashMap with no buckets!");
		#endif
		
		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;

		Map.Resize(_buckets, NULL);
	}

	/*
	Copy constructor.

	@param _other - the other hash map
	*/
	ZHashMap(const ZHashMap<K, V, HT, H, LF, LA, AA>& _other)
		: ElementCount(_other.Size()), Map(_other.Size())
	{
		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;

		Map.Resize(_other.Size(), NULL);

		for (typename ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator itr = _other.Begin(); itr != _other.End(); ++itr)
			Put((*itr).Key, (*itr).Value);
	}

	/*
	Copy constructor that can copy hash maps with other template types.  Key
	and Value type must be the same.

	@param _other - the other hash map
	*/
	template <typename OHT, typename OH, size_t OLF, typename OLA, typename OAA>
	ZHashMap(const ZHashMap<K, V, OHT, OH, OLF, OLA, OAA>& _other)
		: ElementCount(_other.Size()), Map(_other.Size())
	{
		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;

		Map.Resize(_other.Map.Size(), NULL);
		
		for (typename ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator itr = _other.Begin(); itr != _other.End(); ++itr)
			Put((*itr).Key, (*itr).Value);
	}

	/*
	= operator overload.  Makes a copy of another hash map.  This version is needed to
	override the default version.

	@param _other - the other hash map
	@return (ZHashMap<K, V, HT, H, LF, LA, AA>) - this hash map
	*/
	ZHashMap<K, V, HT, H, LF, LA, AA>& operator = (const ZHashMap<K, V, HT, H, LF, LA, AA>& _other) 
	{
		Clear();

		ElementCount = _other.ElementCount;
		Map.Resize(_other.Map.Size());
		
		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;
				
		for (typename ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) {
			Put((*itr).Key, (*itr).Value);
		}

		return *this;
	}
	
	/*
	= operator overload.

	@param _other - the other hash map
	@return (ZHashMap<K, V, HT, H, LF, LA, AA>) - this hash map
	*/
	template <typename OHT, typename OH, size_t OLF, typename OLA, typename OAA>
	ZHashMap<K, V, HT, H, LF, LA, AA>& operator = (const ZHashMap<K, V, OHT, OH, OLF, OLA, OAA>& _other) 
	{
		Clear();

		ElementCount = _other.ElementCount;
		Map.Resize(_other.Map.Size()());

		EmptyNode.Next = &EmptyNode;
		EmptyNode.Previous = &EmptyNode;
				
		for (typename ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator itr = _other.Begin(); itr != _other.End(); ++itr) {
			Put((*itr).Key, (*itr).Value);
		}

		return *this;
	}

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::operator[]
	
	Gets a value from the map.  Functionally resembles the 'Get' operation but will
	create a default constructed value if not assigned.
	
	@param _key - the key to lookup
	@return (V&) - the value mapped to _key
	*/
	V& operator [] (const K& _key) 
		{ if (!ContainsKey(_key)) Put(_key, V()); return Get(_key); }

	/*
	public ZHashMap<K, V, H, LF, lA, AA>::Begin

	Gets an iterator to the first element in the hash map.  Keep in mind
	that hash map elements are unordered.

	@return (ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator) - iterator to the first element
	*/
	Iterator Begin() const
		{ return ZHashMapIterator< K, V, HT >(const_cast<ZListNode< ZHashNode<K, V, HT> >* >(&EmptyNode)->Next, 
											  const_cast<ZListNode< ZHashNode<K, V, HT> >* >(&EmptyNode)); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Clear

	Clears the hash map of all keys and values.
	
	@return (void)
	*/
	void Clear() 
		{ ZHashMap_ClearImpl<K, V, HT, H, LF, LA, AA>::Call(*this);  }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::ContainsKey

	Determines if the hash map contains the given key.
	
	@param _key - the key to check
	@return (bool) - boolean indicating if the hash map contains the key
	*/
	bool ContainsKey(const K& _key) const 
		{ return ZHashMap_ContainsKeyImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _key); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::ContainsValue

	Determines if the hash map contains the given value.

	@param _value - the value to check for
	@return (bool) - boolean indicating if the hash map contains the value
	*/
	bool ContainsValue(const V& _value) const 
		{ return ZHashMap_ContainsValueImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _value); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Empty

	Indicates whether or not the hash map is empty.

	@return (bool) - boolean indicating the hash map is empty (free of keys and values)
	*/
	bool Empty() const 
		{ return ZHashMap_EmptyImpl<K, V, HT, H, LF, LA, AA>::Call(*this); }
	
	/*
	public ZHashMap<K, V, H, LF, lA, AA>::End

	Gets an iterator to the end node in the hash map.  Keep in mind
	that hash map elements are unordered.

	@return (ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator) - iterator to the end node
	*/
	Iterator End() const
		{ return ZHashMapIterator< K, V, HT >(const_cast<ZListNode< ZHashNode<K, V, HT> >* >(&EmptyNode), 
		  								 	  const_cast<ZListNode< ZHashNode<K, V, HT> >* >(&EmptyNode)); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Erase

	Removes the associated key and mapped value.

	@param _key - the key to lookup
	@return (void) - this hash map
	@assert - if the key is not mapped
	*/
	void Erase(const K& _key) 
		{ ZHashMap_EraseImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _key); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Erase

	Removes the key and mapped value given by the iterator.  This version is more
	efficient than the key-only version because no hash lookup is performed.

	@param _itr - iterator to the hash node to remove
	@return (void)
	@assert - if it is the end iterator
	*/
	void Erase(Iterator& _itr)
		{ ZHashMap_EraseImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _itr); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Find

    Returns an iterator to the element mapped to the given key.  Will return
	the End() iterator if not mapped.

	@param _key - the key to look up
	@return (ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator) - iterator to the element, 
															End() if not found
	*/
	Iterator Find(const K& _key) const
	{
		HT hash = Hasher.Hash(_key);
		size_t bucket = GetBucket(hash);

		ZListNode< ZHashNode<K, V, HT> >* node = Map.Data()[bucket]; 

		while (node != NULL && node != &EmptyNode && node->Element.HashMod == bucket)
		{
			if (node->Element.Hash == hash && Hasher.Equals(_key, node->Element.Key) != 0)
				return Iterator(node, const_cast< ZListNode< ZHashNode<K, V, HT> > *>(&EmptyNode));

			node = node->Next;
		}

		return End();
	}
	
	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Get
	
	Gets the value mapped to the given key.

	@param _key - the key to look up
	@return (V&) - the value mapped to _key
	@assert - if the key is not present in the map
	*/
	V& Get(const K& _key) const 
		{ return ZHashMap_GetImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _key); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Keys

	Gets a list of keys in the map.  Uses the method 'PushBack' to add the 
	keys.

	@param C - the container type to push the keys into, which must contain
			   type K and have a 'PushBack' method
	@param _container - the container to put the keys into
	@return - ZList containing all the keys in the map
	*/
	template <typename C>
	void Keys(C& _container) const 
	{
		Iterator itr = Begin();

		while (itr.HasCurrent()) 
		{
			_container.PushBack((*itr).Key);
			itr.Next();
		}
	}

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::LoadFactor

	Returns the current load factor of the hash map, as determined by number
	of elements over number of buckets.

	@return (double) - the load factor
	*/
	double LoadFactor() const
	{
		return (double)ElementCount / (double)Map.Size();
	}

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Mappings

	Gets a list of all the key value mappings in the hash map.  Adds pairs of
	mappings using 'PushBack'.
	
	@param C - the container type to push the keys into, which must contain
			   type ZPair<K, V> and have a 'PushBack' method
	@param _container - the container to put the keys into
	@return (ZList<ZPair<K, V>>)- list of key-value pairs
	*/
	template <typename C>
	void Mappings(C& _container) const 
	{
		Iterator itr = Begin();

		while (itr.HasCurrent()) 
		{
			_container.PushBack(ZPair<K, V>((*itr).Key, (*itr).Value));
			itr.Next();
		}
	}
	
	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Put

	Puts the given key into the map with a default constructed value of type V.

	@param _key - the key to place in the map
	*/
	void Put(const K& _key)
		{ return ZHashMap_PutImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _key); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Put

	Puts the given key and value combination into the hash map.

	@param _key - the key to associate with _value
	@param _value - the value to lookup using _key
	*/
	void Put(const K& _key, const V& _value) 
		{ return ZHashMap_PutImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _key, _value); }
	
	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Resize
	
	Sets the number of buckets the hashmap will use.  Existing elements will be re-hashed into the map.
	
	@param _buckets - number of buckets to use
	@return (ZHashMap<K, V, HT, H, LF, LA, AA>&) - this map
	*/
	void Resize(size_t _buckets) 
		{ ZHashMap_ResizeImpl<K, V, HT, H, LF, LA, AA>::Call(*this, _buckets); }

	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Size

	Returns the number of mapped key-value pairs in the map.

	@return (size_t) - the number of key value pairs
	*/
	size_t Size() const 
		{ return ZHashMap_SizeImpl<K, V, HT, H, LF, LA, AA>::Call(*this); }
	
	/*
	public ZHashMap<K, V, HT, H, LF, LA, AA>::Values

	Gets a list of values in the map.
	
	@param C - the container type to push the keys into, which must contain
			   type V and have a 'PushBack' method
	@param _container - the container to put the keys into
	@return (ZList<V>)- ZList containing all the values in the map
	*/
	template <typename C>
	void Values(C& _container) const 
	{
		Iterator itr = Begin();

		while (itr.HasCurrent())
		{
			_container.PushBack((*itr).Value);
			itr.Next();
		}
	}
};

////////////////////////////////////////////
/* Non-Specialized Method Implementations */
////////////////////////////////////////////

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_ClearImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self)
{
	ZListNode< ZHashNode<K, V, HT> >* node = _self.EmptyNode.Next;
	
	while (node != &_self.EmptyNode)
	{
		node = node->Next;
		_self.NodeAllocator.Deallocate(node->Previous);
	} 

	for (size_t i = 0; i < _self.Map.Size(); i++)
		_self.Map.Data()[i] = NULL;

	_self.EmptyNode.Next = &_self.EmptyNode;
	_self.EmptyNode.Previous = &_self.EmptyNode;

	_self.ElementCount = 0;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
bool ZHashMap_ContainsKeyImpl<K, V, HT, H, LF, LA, AA>::Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key)
{
	HT hash = _self.Hasher.Hash(_key);
	size_t bucket = _self.GetBucket(hash);

	ZListNode< ZHashNode<K, V, HT> >* node = _self.Map.Data()[bucket]; 

	while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket)
	{
		if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0)
			return true;

		node = node->Next;
	}
	
	return false;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
bool ZHashMap_ContainsValueImpl<K, V, HT, H, LF, LA, AA>::Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const V& _value)
{
	typename ZHashMap<K, V, HT, H, LF, LA, AA>::Iterator itr = _self.Begin();

	while (itr.HasCurrent()) 
	{
		if ((*itr).Value == _value)
			return true;
		
		itr.Next();
	}

	return false;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
bool ZHashMap_EmptyImpl<K, V, HT, H, LF, LA, AA>::Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self)
{
	return _self.ElementCount == 0;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_EraseImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key)
{
	HT hash = _self.Hasher.Hash(_key);
	size_t bucket = _self.GetBucket(hash);
	
	ZListNode< ZHashNode<K, V, HT> >* node = _self.Map.Data()[bucket]; 

	while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket)
	{
		if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0)
		{
			ZListNode< ZHashNode<K, V, HT> >* prevNode = node->Previous;
			ZListNode< ZHashNode<K, V, HT> >* nextNode = node->Next;

			prevNode->Next = nextNode;
			nextNode->Previous = prevNode;

			//If the bucket maps to this node, it must change (either Next or NULL)
			if (_self.Map.Data()[bucket] == node) 
			{
				if (nextNode->Element.HashMod == bucket)
					_self.Map.Data()[bucket] = nextNode;
				else
					_self.Map.Data()[bucket] = NULL;
			}

			_self.NodeAllocator.Deallocate(node);
			_self.ElementCount--;

			return;
		}

		node = node->Next;
	}
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_EraseImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, ZHashMapIterator<K, V, HT>& _itr)
{
	#if !ZSTL_DISABLE_RUNTIME_CHECKS
	ZSTL_ASSERT(_itr != _self.End(), "ZHashMap: Cannot Erase End iterator!");
	#endif

	ZListNode< ZHashNode<K, V, HT> >* node = _itr.GetNode();
	ZListNode< ZHashNode<K, V, HT> >* prevNode = node->Previous;
	ZListNode< ZHashNode<K, V, HT> >* nextNode = node->Next;

	size_t bucket = node->Element.HashMod;

	prevNode->Next = nextNode;
	nextNode->Previous = prevNode;

	//If the bucket maps to this node, it must change (either Next or NULL)
	if (_self.Map.Data()[node->Element.HashMod] == node) 
	{
		if (nextNode->Element.HashMod == bucket)
			_self.Map.Data()[bucket] = nextNode;
		else
			_self.Map.Data()[bucket] = NULL;
	}

	_self.NodeAllocator.Deallocate(node);
	_self.ElementCount--;
}


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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
V& ZHashMap_GetImpl<K, V, HT, H, LF, LA, AA>::Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key)
{
	HT hash = _self.Hasher.Hash(_key);
	size_t bucket = _self.GetBucket(hash);
	
	ZListNode< ZHashNode<K, V, HT> >* node = _self.Map.Data()[bucket]; 

	while (node != NULL && node != &_self.EmptyNode && node->Element.HashMod == bucket)
	{
		if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0)
			return node->Element.Value;

		node = node->Next;
	}

	#if !ZSTL_DISABLE_RUNTIME_CHECKS
	ZSTL_ERROR("ZHashMap: Get could not find value!");
	#endif

	//If the runtime assert is ignored and we continue, return ref to a static local variable
	//This is effectively 'undefined' behavior
	static V val;

	return val;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_PutImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key)
{
	_self.CheckLoadFactor();

	HT hash = _self.Hasher.Hash(_key);
	size_t bucket = _self.GetBucket(hash);

	ZListNode< ZHashNode<K, V, HT> >* node = _self.Map.Data()[bucket]; 

	if (node == NULL)
	{
		//Empty bucket, so search for the next node
		for (size_t i = bucket + 1; i < _self.Map.Size(); i++)
		{
			node = _self.Map.Data()[i];

			if (node != NULL)
				break;
		}

		//No node was found, so use the empty node
		if (node == NULL)
			node = &_self.EmptyNode;
	}
	else
	{
		//Non-empty bucket, so see if we are already mapped
		while (node->Element.HashMod == bucket)
		{
			if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0)
				return;

			node = node->Next;
		}
	}

	//Not mapped, so insert (node is currently one past where we should be)
	ZListNode< ZHashNode<K, V, HT> >* newNode = _self.NodeAllocator.Allocate();

	#if !ZSTL_DISABLE_RUNTIME_CHECKS
	ZSTL_ASSERT(newNode != NULL, "ZHashMap: Unable to allocate hash node!");
	#endif

	//If the bucket has NULL linkage, set it
	if (_self.Map.Data()[bucket] == NULL)
		_self.Map.Data()[bucket] = newNode;

	newNode->Next = node;
	newNode->Previous = node->Previous;
	newNode->Element.Key = _key;
	newNode->Element.Value = V();		//Be sure to default construct the value instance
	newNode->Element.Hash = hash;
	newNode->Element.HashMod = bucket;

	newNode->Previous->Next = newNode;
	newNode->Next->Previous = newNode;	

	_self.ElementCount++;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_PutImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, const K& _key, const V& _value)
{
	_self.CheckLoadFactor();
	
	HT hash = _self.Hasher.Hash(_key);
	size_t bucket = _self.GetBucket(hash);
	
	ZListNode< ZHashNode<K, V, HT> >* node = _self.Map.Data()[bucket]; 

	if (node == NULL)
	{
		//Empty bucket, so search for the next node
		for (size_t i = bucket + 1; i < _self.Map.Size(); i++)
		{
			node = _self.Map.Data()[i];

			if (node != NULL)
				break;
		}

		//No node was found, so use the empty node
		if (node == NULL)
			node = &_self.EmptyNode;
	}
	else
	{
		//Non-empty bucket, so see if we are already mapped
		while (node->Element.HashMod == bucket)
		{
			if (node->Element.Hash == hash && _self.Hasher.Equals(_key, node->Element.Key) != 0)
			{
				node->Element.Value = _value;
				return;
			}

			node = node->Next;
		}
	}
	
	//Not mapped, so insert (node is currently one past where we should be)
	ZListNode< ZHashNode<K, V, HT> >* newNode = _self.NodeAllocator.Allocate();
	
	#if !ZSTL_DISABLE_RUNTIME_CHECKS
	ZSTL_ASSERT(newNode != NULL, "ZHashMap: Unable to allocate hash node!");
	#endif
	
	//If the bucket has NULL linkage, set it
	if (_self.Map.Data()[bucket] == NULL)
		_self.Map.Data()[bucket] = newNode;
	
	newNode->Next = node;
	newNode->Previous = node->Previous;
	newNode->Element.Key = _key;
	newNode->Element.Value = _value;
	newNode->Element.Hash = hash;
	newNode->Element.HashMod = bucket;

	newNode->Previous->Next = newNode;
	newNode->Next->Previous = newNode;	
	
	_self.ElementCount++;
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
void ZHashMap_ResizeImpl<K, V, HT, H, LF, LA, AA>::Call(ZHashMap<K, V, HT, H, LF, LA, AA>& _self, size_t _buckets)
{
	#if !ZSTL_DISABLE_RUNTIME_CHECKS
	ZSTL_ASSERT(_buckets > 0, "ZHashMap: Unable to resize to zero buckets!");
	#endif	
	
	//Get a pointer to the first non-empty element (which may itself be the empty element)
	ZListNode< ZHashNode<K, V, HT> >* node = _self.EmptyNode.Next;

	//Clear out the map completely 
	for (size_t i = 0; i < _self.Map.Size(); i++)
		_self.Map.Data()[i] = NULL;

	_self.EmptyNode.Next = &_self.EmptyNode;
	_self.EmptyNode.Previous = &_self.EmptyNode;

	_self.Map.Resize(_buckets, NULL);

	//Loop through our previous nodes and place them back in the map in their new spots
	while (node != &_self.EmptyNode)
	{
		//Compute new bucket
		node->Element.HashMod = node->Element.Hash % _buckets;
		
		//Determine where we should be placing this node
		ZListNode< ZHashNode<K, V, HT> >* curNode = node;
		ZListNode< ZHashNode<K, V, HT> >* nextNode = _self.Map.Data()[node->Element.HashMod];

		//Get the next node to place now, before we scribble the pointers
		node = curNode->Next;

		//If the bucket has NULL linkage, next node
		if (nextNode == NULL)
		{			
			//Empty bucket, so search for the next nextNode
			for (size_t i = curNode->Element.HashMod + 1; i < _self.Map.Size(); i++)
			{
				nextNode = _self.Map.Data()[i];

				if (nextNode != NULL)
					break;
			}

			//No nextNode was found, so use the empty nextNode
			if (nextNode == NULL)
				nextNode = &_self.EmptyNode;
		}
	
		//Reestablish linkage
		curNode->Next = nextNode;
		curNode->Previous = nextNode->Previous;

		curNode->Previous->Next = curNode;
		curNode->Next->Previous = curNode;	
		
		//Since we are pushing front, this always means we set the pointer
		_self.Map.Data()[curNode->Element.HashMod] = curNode;
	}
}

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

template <typename K, typename V, typename HT, typename H, size_t LF, typename LA, typename AA>
size_t ZHashMap_SizeImpl<K, V, HT, H, LF, LA, AA>::Call(const ZHashMap<K, V, HT, H, LF, LA, AA>& _self)
{
	return _self.ElementCount;
}

#endif
