/*
	ZSmartPointer.hpp
	Author: James Russell
	Created: 08/12/2011

	Purpose:	
	
	Smart pointer implementation for the ZEngine.  Frees up the programmer from having to
	worry too hard about the minutiae of memory management for allocated objects.  Not to 
	use on arrays; use ZArray for dynamic array management.
				
	Uses atomic operations to enable the smart pointer to work across threads.

	Don't pass these things around by pointer or reference unless you really know what you
	are doing.  You won't like the results.

	License: 

	TODO

*/

#pragma once

#ifndef _ZSMARTPOINTER_H
#define _ZSMARTPOINTER_H

#include <SST/SST_Atomic.h>
#include <SST/SST_Concurrency.h>

#include <ZUtil/ZUtilBuild.hpp>
#include <ZUtil/ZAlloc.hpp>
#include <ZUtil/ZAssert.hpp>
#include <ZUtil/ZReferenceCounter.hpp>

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

//Shorthand used for ZSmartPointer
#define ZPtr ZSmartPointer

/*
Default deallocator functor for ZSmartPointer, which is responsible for deallocating
the managed object.  This default version uses 'zdelete'.

The template parameter T is the type of object pointed to by the smart pointer.

The unary functor takes a single argument of type T*, which is the object to be deallocated.
*/
template <typename T>
struct ZSmartPointerDeallocator {
	void operator () (T* _object) {
		zdelete _object;
	}
};

/*
NULL deallocator functor for ZSmartPointer, which doesn't actually deallocate anything.

The template parameter T is the type of object pointed to by the smart pointer.

The unary functor takes a single argument of type T*, which is destroyed.
*/
template <typename T>
struct ZSmartPointerNullDeallocator {
	void operator() (T* _object) {
		URFP(_object);
	}
};

/*
Smart pointer class, used to share a references to an allocated object.  This smart pointer
uses atomic operations to ensure that the reference count is maintained properly even when
the object is shared among threads.

The template parameter T is the type of the object pointed to.

The template parameter DF is the type of object deallocator functor to use.

The template parameter R is the type of reference counter allocator to use.
*/
template <typename T, typename DF = ZSmartPointerDeallocator<T>, typename R = ZReferenceCounterAllocator >
class ZSmartPointer
{
protected:
	//The pointed to object
	T* Object;

	//Object Deallocator
	DF ObjDeallocator;

	//Reference Counter Allocator
	R RefAllocator;

	//Reference Counter for the pointer (also contains the pointer)
	ZReferenceCounter* Ref;

	//Checks to see if we need a reference counter, allocates if so, and increments the strong 
	//reference count
	inline void ReferenceGained()
	{
		if (Object == NULL)
			return;

		if (Ref == NULL)
		{
			Ref = RefAllocator.AllocateCounter();

			ZASSERT_RUNTIME(Ref != NULL, "ZSmartPointer: Reference counter allocator returned NULL!");
		}

		Ref->GainStrongRef();
	}

	//Checks to see if we can delete the reference and lowers the count
	inline void ReferenceLost()
	{
		if (Ref == NULL)
		{
			ZASSERT_UTIL(Object == NULL, "ZSmartPointer: Reference lost with no reference counter, but object is still present!");
			return;
		}

		ZASSERT_UTIL(Ref->GetStrongRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deallocated!");

		uint32_t combinedCount = Ref->LoseStrongRef();					//Decrement our strong count and get the combined count

		//Check if we lost the last strong ref
		if ((combinedCount & ZREFCOUNTER_STRONG_MASK) == 0)			//Note we don't use the EXTRACT_STRONG_REF() since 0 bitshifted is still 0
		{
			Ref->SignalDeallocateObject();							//Signal object deallocation

			ObjDeallocator(Object);									//Deallocate the object

			//Check if we lost the last weak reference
			if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0)		//Note we don't use the EXTRACT_WEAK_REF() since 0 bitshifted is still 0
			{
				RefAllocator.DeallocateCounter(Ref);				//Deallocate the counter
			}
		}

		//We lost our reference, so we don't need these
		Object = NULL;
		Ref = NULL;
	}

public:
	/*
	Default constructor.  Sets the reference to NULL and does not allocate a reference
	counter.
	*/
	ZSmartPointer()
		: Object(NULL), Ref(NULL) 
	{ }

	/*
	Constructor.  Explicit to ensure we don't accidentally take ownership of
	a pointer.  Allocates a reference counter from the reference counter allocator.

	@param _ptr - pointer to be managed
	*/
	explicit ZSmartPointer(T* _ptr)
		: Object(_ptr), Ref(NULL)
	{
		ReferenceGained();
	}

	/*
	Copy constructor.

	@param _other - the other smart pointer
	*/
	ZSmartPointer(const ZSmartPointer<T, DF, R>& _other)
		: Object(_other.Pointer()), Ref(_other.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Conversion constructor.  Used to auto up-cast derived classes or other
	classes that can be converted.

	@param D - the typename of the derived class
	@param EF - the deallocator functor type of the other class
	@param S - the reference counter allocator type of the other class
	@param _other - the other smart pointer
	*/
	template <typename D, typename EF, typename S>
	ZSmartPointer(const ZSmartPointer<D, EF, S>& _other)
		: Object(static_cast<T*>(_other.Pointer())), Ref(_other.Counter())
	{
		ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZSmartPointer: Copy constructor called from smart pointer with invalid reference counter!");

		ReferenceGained();
	}

	/*
	Destructor.  Causes a strong reference to be lost.
	*/
	~ZSmartPointer()
	{	
		ReferenceLost();
	}

	/*
	= operator overload.  Sets this smart pointer to be the owner of the provided pointer,
	which may require allocation of a reference counter.

	@param _ptr - the pointer to the object to own
	@return (ZSmartPointer<T, DF, R>&) - this smart pointer
	*/
	ZSmartPointer<T, DF, R>& operator = (T* _ptr)
	{
		if (Object == _ptr)
			return *this;

		if (_ptr == NULL)
		{
			ReferenceLost();		//Ditch our reference

			Object = NULL;			//Nullify our object pointer
			Ref = NULL;				//Nullify our counter
		}
		else
		{
			if (Object != NULL)
				ReferenceLost();	//Lose our reference to the valid object

			Object = _ptr;			//Own it
			Ref = NULL;				//Make sure Ref is set to NULL

			ReferenceGained();		//Create a new reference counter

		}

		return *this;
	}

	/*
	= operator overload.  Sets this smart pointer to provide a strong reference to the same object
	managed by the other smart pointer.

	@param _other - the other smart pointer
	@return (ZSmartPointer<T, DF, R>&) - this smart pointer
	*/
	ZSmartPointer<T, DF, R>& operator = (const ZSmartPointer<T, DF, R>& _other)
	{
		if (*this == _other || Ref == _other.Counter())
			return *this;
	
		ReferenceLost();				//Lose a reference to our current object

		Object = _other.Pointer();		//Own the new one
		Ref = _other.Counter();			//Get our new reference counter

		ReferenceGained();				//Increment the reference


		return *this;
	}

	/*
	= operator overload.  Used to assign to derived classes and classes that can 
	be converted to T.

	@param D - the type held by the other smart pointer
	@param EF - the deallocator type of the other smart pointer
	@param S - the reference counter allocator type of the other smart pointer
	@param _other - the other smart pointer
	@return (ZSmartPointer<T, DF, R>&) - this smart pointer
	*/
	template <typename D, typename EF, typename S>
	ZSmartPointer<T, DF, R>& operator = (const ZSmartPointer<D, EF, S>& _other)
	{
		T* testCast = static_cast<T*>(_other.Pointer()); ((void)testCast);	//This will fail to compile if T* cannot static cast to D*

		return *this = static_cast< ZSmartPointer<T, DF, R> >(_other);
	}

	/*
	== operator overload.  Checks to see if this smart pointer owns the provided raw pointer.

	@param _ptr - the pointer to check
	@return (bool) - true if the pointer is managed by this smart pointer, false otherwise
	*/
	bool operator == (const T* _ptr) const
	{
		return Object == _ptr;
	}

	/*
	== operator overload.  Checks to see if these pointers reference the same object.

	@param _other - the other smart pointer
	@return (bool) - true if equal, false otherwise
	*/
	bool operator == (const ZSmartPointer<T, DF, R>& _other) const
	{
		return Object == _other.Object;
	}

	/*
	== operator overload.  Used to compare with smart pointers referencing derived 
	classes or a class that can be converted to T.

	@param _other - the other smart pointer
	@return (bool) - true if equal, false otherwise
	*/
	template <typename D, typename EF, typename S>
	bool operator == (const ZSmartPointer<D, EF, S>& _other) const
	{
		return Object == static_cast<T*>( _other.Pointer());
	}

	/*
	!= operator overload.  Checks to see if this smart pointer does not 
	own the provided raw pointer.

	@param _ptr - the pointer to check
	@return (bool) - true if this smart pointer does not reference the provided, false otherwise
	*/
	bool operator != (const T* _ptr) const
	{
		return !(*this == _ptr);
	}

	/*
	!= operator overload.  Checks to see if the smart pointers reference different objects.

	@param _other - the other smart pointer
	@return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise
	*/
	bool operator != (const ZSmartPointer<T, DF, R>& _other) const
	{
		return !(*this == _other);
	}

	/*
	!= operator overload.  Checks to see if these pointers reference different objects.  Used
	to compare with derived classes.

	@param D - the type contained by the other smart pointer
	@param EF - the allocator used by the other smart pointer
	@param S - the reference counter allocator type used by the other smart pointer
	@param _other - the other smart pointer
	@return (bool) - true if this smart pointer and the other do not reference the same object, false otherwise
	*/
	template <typename D, typename EF, typename S>
	bool operator != (const ZSmartPointer<D, EF, S>& _other) const
	{
		return !(*this == _other);
	}

	/*
	-> operator overload.  Allows this to be accessed as a T* would be.

	@return (T*) - raw pointer to the object
	@assert - if the pointer is NULL
	*/
	T* operator -> () const
	{
		ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");

		return Object;
	}

	/*
	'*' operator overload.  Allows this to be dereferenced as a T* would be.

	@return (T&) - reference to the object
	@assert - if the object is NULL
	*/
	T& operator * () const
	{
		ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");

		return *Object;
	}

	/*
	public ZSmartPointer<T, DF, R>::CounterAllocator
	
	Gets the reference counter allocator for this smart pointer.

	@return (R&) - the reference counter allocator
	*/
	R& CounterAllocator() const
	{
		return RefAllocator;
	}

	/*
	public ZSmartPointer<T, DF, R>::Cast

	Used to cast this smart pointer into another type.  This will construct an
	additional smart pointer that also references the object.  The owned 
	object must be convertible to type C* via static_cast.

	@param C - the type contained by the other type
	@return (ZSmartPointer<C, DF, R>) - this smart pointer as another type
	*/
	template <typename C>
	ZSmartPointer<C, DF, R> Cast()
	{
		return static_cast< ZSmartPointer<C, DF, R> >(*this);
	}

	/*
	public ZSmartPointer<T, DF, R>::Counter

	Gets the ZRefrenceCounter instance used by this smart pointer.

	@return (ZReferenceCounter*)- ZRefCounter instance
	*/
	ZReferenceCounter* Counter() const 
	{ 
		return Ref; 
	}

	/*
	public ZSmartPointer<T, DF, R>::Deallocator

	Gets the object deallocator for this smart pointer.

	@return (DF&) - reference to the object deallocator
	*/
	DF& Deallocator() const
	{
		return ObjDeallocator;
	}

	/*
	public ZSmartPointer<T, DF, R>::Detach

	Detaches the pointer from memory management by the smart pointer.  Should only be 
	called if there	is a single strong reference to the object, otherwise it will return
	NULL.  Weak references will be nullified as if the object has been deallocated.
	
	@return (T*) - raw pointer detached from this smart pointer, or NULL if more 
				   than one reference and unable to detach
	*/
	T* Detach()
	{
		if (Object == NULL || Ref == NULL || Ref->GetStrongRefCount() != 1)
			return NULL;
		else
		{
			uint32_t combinedCount = Ref->LoseStrongRef();			//Notify everyone we are losing this strong reference

			Ref->SignalDeallocateObject();						//Signal that we are deallocating the object

			if ((combinedCount & ZREFCOUNTER_WEAK_MASK) == 0)
				RefAllocator.DeallocateCounter(Ref);			//Deallocate our reference counter

			T* ptr;

			ptr = Object;		//Detach the pointer

			Object = NULL;		//Nullify our object reference
			Ref = NULL;			//Nullify our reference counter

			return ptr;
		}
	}

	/*
	public ZSmartPointer<T, DF, R>::Pointer

	Gets the smart pointer as a raw pointer.  Buyer beware.

	@return (T*) - raw pointer that this smart pointer manages
	*/
	T* Pointer() const 
	{ 
		return Object; 
	}
};

////////////////////////////////////////
/* ZArray Containment Specializations */
////////////////////////////////////////

//Helper function used to nullify references in a range
template <typename T, typename DF, typename R>
void ZSmartPointerArrayNullify(ZSmartPointer<T, DF, R>* _array, size_t _start, size_t _end)
{
	for (size_t i = _start; i < _end; i++)
		_array[i] = NULL;
}

//Specialization for ZArray_ClearImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_ClearImpl< ZSmartPointer<T, DF, R>, A> {

	inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self) 
	{
		//Nullify references
		ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize);

		//Reset size and check integrity
		_self.ArraySize = 0;
		_self.CheckIntegrity();
	}

	inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, size_t _newCapacity) 
	{
		//Nullify references
		ZSmartPointerArrayNullify(_self.Array, 0, _self.ArraySize);

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!");
		#endif

		//Reallocate if needed, drop our size to zero, and check integrity
		if (_newCapacity > _self.ArrayCapacity)
		{
			_self.Deallocate(_self.Array, _self.ArrayCapacity);
			_self.ArrayCapacity = _newCapacity;
			_self.Allocate(_self.ArrayCapacity);
		}

		_self.ArraySize = 0;
		_self.CheckIntegrity();
	}

};

//Specialization for ZArray_EraseImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_EraseImpl< ZSmartPointer<T, DF, R>, A> {

	inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, size_t _index) 
	{
		size_t index = _self.BoundsCheck(_index, _self.ArraySize);

		//Grab the currently held element, shift the array down, reduce size, and check integrity
		ZSmartPointer<T, DF, R> element = _self.Array[index];

		for (size_t i = index; i + 1 < _self.ArraySize; i++)
			_self.Array[i] = _self.Array[i + 1];

		_self.ArraySize--;
		_self.CheckIntegrity();

		//Nullify reference
		ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);

		return element;
	}

	inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _start, const size_t _end) 
	{
		size_t start = _self.BoundsCheck(_start, _self.ArraySize);
		size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1);

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!");
		#endif

		//Copy the elements down, compute new size, and check integrity
		for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++)
			_self.Array[idx] = _self.Array[idx + (end - start)];

		_self.ArraySize = _self.ArraySize - (end - start);
		_self.CheckIntegrity();

		//Nullify references (where we moved from)
		ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start));
	}
};

//Specialization for ZArray_PopBackImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_PopBackImpl< ZSmartPointer<T, DF, R>, A> {

	inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self) 
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
		#endif

		ZSmartPointer<T, DF, R> ptr = _self.Array[--(_self.ArraySize)];

		//Nullify reference
		ZSmartPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);

		//Grab the last element in the array and decrease our array size
		return ptr;
	}

};

//Specialization for ZArray_PopFrontImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_PopFrontImpl< ZSmartPointer<T, DF, R>, A> {

	inline static ZSmartPointer<T, DF, R> Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self) 
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
		#endif

		//This will nullify the reference
		return _self.Erase(0);
	}

};

//Specialization for ZArray_ResizeImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZArray_ResizeImpl< ZSmartPointer<T, DF, R>, A> {

	inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _size) 
	{
		//Nullify references if needed
		if (_size < _self.ArraySize)
			ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize);

		//Check to see if we need more space, change our size, and check integrity
		if (_size > _self.ArrayCapacity)
			_self.Reserve(_size);

		_self.ArraySize = _size;
		_self.CheckIntegrity();
	}

	inline static void Call(ZArray<ZSmartPointer<T, DF, R>, A>& _self, const size_t _size, const ZSmartPointer<T, DF, R>& _value) 
	{
		//Nullify references if needed
		if (_size < _self.ArraySize)
			ZSmartPointerArrayNullify(_self.Array, _size, _self.ArraySize);

		//See if we need more space, copy in the new value, change our size, and check integrity
		if (_size > _self.ArrayCapacity)
			_self.Reserve(_size);

		for (size_t i = _self.ArraySize; i < _size; i++)
			_self.Array[i] = _value;

		_self.ArraySize = _size;
		_self.CheckIntegrity();
	}

};

///////////////////////////////////////
/* ZList Containment Specializations */
///////////////////////////////////////

//Specialization for ZList_ClearImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_ClearImpl < ZSmartPointer<T, DF, R>, A> {

	inline static void Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _itr) {

		ZListNode<ZSmartPointer<T, DF, R> >* next;
		ZListNode<ZSmartPointer<T, DF, R> >* current = _itr.GetNode();

		_self.CheckIntegrity();

		//Early out
		if (_self.Empty())
			return;

		//If we are the starting node, be sure to reset the EmptyNode.Next pointer
		if (current == _self.EmptyNode.Next)
			_self.EmptyNode.Next = &_self.EmptyNode;

		//This is always true
		_self.EmptyNode.Previous = current->Previous;
		current->Previous->Next = &_self.EmptyNode;

		//Iterate and deallocate the nodes
		while (current != &_self.EmptyNode)
		{
			next = current->Next;
			current->Element = NULL;		//This is the specialization
			_self.DeallocateNode(current);
			current = next;
		}

		//Set the node on the iterator equal to the end node
		_itr.SetNode(&_self.EmptyNode);

		_self.CheckIntegrity();
	}

};

//Specialization for ZList_EraseImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_EraseImpl < ZSmartPointer<T, DF, R>, A> {

	inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _itr)
	{
		ZSmartPointer<T, DF, R> elem;
		ZListNode< ZSmartPointer<T, DF, R> > *node = _itr.GetNode();

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!");
		ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!");
		#endif

		//Increment the iterator to the next list node to keep the iterator valid
		++_itr;
		
		//Rearrange the pointers
		node->Previous->Next = node->Next;
		node->Next->Previous = node->Previous;

		elem = node->Element;
		node->Element = NULL;			//This is the specialization

		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}

	inline static void Call(ZList<ZSmartPointer<T, DF, R>, A>& _self, ZListIterator< ZSmartPointer<T, DF, R> >& _start, const ZListIterator< ZSmartPointer<T, DF, R> >& _end)
	{

		ZListNode< ZSmartPointer<T, DF, R> > *nodeStart = _start.GetNode();
		ZListNode< ZSmartPointer<T, DF, R> > *nodeEnd = _end.GetNode();

		ZListNode< ZSmartPointer<T, DF, R> > *curNode;
		ZListNode< ZSmartPointer<T, DF, R> > *prevNode;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!");
		ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!");
		#endif

		//Rearrange the pointers
		nodeStart->Previous->Next = nodeEnd;
		nodeEnd->Previous = nodeStart->Previous;

		//Erase each element between from and to
		curNode = nodeStart;
		prevNode = NULL;

		while (curNode != nodeEnd)
		{
			#if !ZSTL_DISABLE_RUNTIME_CHECKS
			ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!");
			#endif

			prevNode = curNode;
			curNode = curNode->Next;

			prevNode->Element = NULL;			//This is the specialization
			_self.DeallocateNode(prevNode);
		}

		_start = _end;
	}

};

//Specialization for ZList_PopBackImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_PopBackImpl  < ZSmartPointer<T, DF, R>, A> {
	inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self) {

		ZSmartPointer<T, DF, R> elem;
		ZListNode< ZSmartPointer<T, DF, R> > *node;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!");
		#endif

		//Grab the element at the back of the list
		node = _self.EmptyNode.Previous;
		
		//Remove the node from the list
		node->Previous->Next = &_self.EmptyNode;	
		_self.EmptyNode.Previous = node->Previous;

		//Get the element value and lose our reference
		elem = node->Element;
		node->Element = NULL;

		//Deallocate and then return
		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}
};

//Specialization for ZList_PopFrontImpl containing ZSmartPointer
template <typename T, typename A, typename DF, typename R>
struct ZList_PopFrontImpl < ZSmartPointer<T, DF, R>, A> {
	inline static ZSmartPointer<T, DF, R> Call(ZList<ZSmartPointer<T, DF, R>, A>& _self) {

		ZSmartPointer<T, DF, R> elem;
		ZListNode< ZSmartPointer<T, DF, R> > *node;

		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!");
		#endif

		//Grab the element at the front of the list
		node = _self.EmptyNode.Next;

		//Remove the node from the list
		node->Next->Previous = node->Previous;
		node->Previous->Next = node->Next;

		//Get the element value and lose our reference
		elem = node->Element;
		node->Element = NULL;

		//Deallocate and then return
		_self.DeallocateNode(node);

		_self.CheckIntegrity();

		return elem;
	}
};

/////////////////////////////////////////////
/* ZRingBuffer Containment Specializations */
/////////////////////////////////////////////

//Specialization for ZRingBuffer_ClearImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_ClearImpl  < ZSmartPointer<T, DF, R>, P, A> {
	inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
	{
		// set to null to remove references
		for (size_t i = 0; i < _self.BufferSize; i++)
			_self.At(i) = ZSmartPointer<T,DF,R>(NULL);

		_self.BufferSize = 0;
		_self.FrontIndex = 0;
		_self.BackIndex = 0;
	}
	inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _newCapacity )
	{
		// set to null to remove references
		for (size_t i = 0; i < _self.BufferSize; i++)
			_self.At(i) = ZSmartPointer<T,DF,R>(NULL);

		_self.Buffer.Resize(_newCapacity);

		_self.BufferSize = 0;
		_self.FrontIndex = 0;
		_self.BackIndex = 0;
	}
};

//Specialization for ZRingBuffer_EraseImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_EraseImpl < ZSmartPointer<T, DF, R>, P, A> {
	inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _index)
	{
		//We are going to do this in a very naive fashion, as this container is not intended for these
		//kinds of operations anyhow.  Anyone who wishes to optimize this at a later date is welcome.

		_self.AlignBuffer();

		_self.BufferSize--;
		_self.BackIndex--;

		// set to null to remove references
		ZSmartPointer<T, DF, R> ret = _self.Buffer.At(_index);
		_self.Buffer.At(_index) = ZSmartPointer<T, DF, R>(NULL);
		return ret;

	}
	inline static void Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self, size_t _i, size_t _j )
	{
		//We are going to do this in a very naive fashion, as this container is not intended for these
		//kinds of operations anyhow.  Anyone who wishes to optimize this at a later date is welcome.

		size_t count;

		_self.AlignBuffer();

		count = (size_t)(_j - _i);

		_self.BufferSize = _self.BufferSize - count;
		_self.BackIndex = _self.BackIndex - count;

		// set to null to remove references
		for( size_t i = _i; i < _j; i++)
			_self.Buffer.At(i) = ZSmartPointer<T, DF, R>(NULL);

		_self.Buffer.Erase(_i, _j);
	}
};

//Specialization for ZRingBuffer_PopBackImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_PopBackImpl < ZSmartPointer<T, DF, R>, P, A> {
	inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!");
		#endif

		size_t index = _self.BackIndex;

		_self.DecrementBack();

		_self.CheckIntegrity();

		// set to NULL to fix ref count issues
		ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index);
		_self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL);
		return ret;
	}
};

//Specialization for ZRingBuffer_PopFrontImpl containing ZSmartPointer
template <typename T, typename P, typename A, typename DF, typename R>
struct ZRingBuffer_PopFrontImpl < ZSmartPointer<T, DF, R>, P, A> {
	inline static T Call( ZRingBuffer< ZSmartPointer<T, DF, R>, P, A>& _self )
	{
		#if !ZSTL_DISABLE_RUNTIME_CHECKS
		ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!");
		#endif

		size_t index = _self.FrontIndex;

		_self.IncrementFront();

		_self.CheckIntegrity();

		// set to NULL to fix ref count issues
		ZSmartPointer< T, DF, R > ret = _self.Buffer.At(index);
		_self.Buffer.At(index) = ZSmartPointer< T, DF, R>(NULL);
		return ret;
	}
};

#endif
