Files
libsst/Include/ZUtil/ZWeakPointer.hpp
2026-04-03 00:22:39 -05:00

1025 lines
28 KiB
C++

/*
ZWeakPointer.hpp
Author: James Russell <jcrussell@762studios.com>
Created: 08/12/2011
Purpose:
TODO
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 _ZWEAKPOINTER_H
#define _ZWEAKPOINTER_H
#include <ZUtil/ZSmartPointer.hpp>
/*
DeallocLock macro, used to lock a weak pointer when in use to prevent
deallocation. Using this ensures that the ZReferenceCounter functions
SignalInUse / SignalUnused are respected.
Usage:
ZWeakPointer<Object> ptr;
DeallocLock(ptr) {
... code to execute using ptr ...
}
*/
#define DeallocLock(weakPointer) if (ZWeakPointerDeallocLock dealloc_lock##__LINE__ = weakPointer())
/*
Struct used to ensure (via RAII and scoped construction and destruction) that while weak pointers
are in use, the object will not be deallocated by the owning smart pointer.
*/
struct ZWeakPointerDeallocLock {
//Indicates whether or not we successfully obtained the lock on our reference counter
bool bLockObtained;
//The reference counter we attempt to lock
ZReferenceCounter* Ref;
/*
Default constructor. Calls the SignalInUse function on _counter and stores the
result of the call.
@param _counter - the reference counter struct to signal
*/
ZWeakPointerDeallocLock(ZReferenceCounter* _counter)
: bLockObtained(_counter != NULL && _counter->SignalInUse()), Ref(_counter)
{ }
/*
Destructor. If the lock was successfully obtained, will signal the object no longer
in use.
*/
~ZWeakPointerDeallocLock()
{
if (bLockObtained && Ref != NULL)
Ref->SignalUnused();
}
/*
operator bool override. Returns whether or not the lock was successful.
@return (bool) - true if the lock succeeded, false otherwise
*/
operator bool ()
{
return bLockObtained;
}
};
/*
Weak pointer class, used to maintain a weak reference to an object that has a reference
whose lifetime is maintained by instances of ZSmartPointer.
@param T - the type of object referenced by the weak pointer
@param R - the reference counter allocator type to use
*/
template <typename T, typename R = ZReferenceCounterAllocator >
class ZWeakPointer
{
private:
//Managed Pointer
T* Object;
//Reference Counter Allocator, used to deallocate the ref counter
R RefAllocator;
//Reference Counter for the pointer
ZReferenceCounter* Ref;
//Checks to see if the object has lost all strong references and is deleted
inline void CheckReferences()
{
if (Ref != NULL && Ref->GetStrongRefCount() == 0)
{
//There is an edge case here wherein the strong count is zero, the deallocation flag
//on the reference counter has been set, but the object is in use (by us)
if (Ref->State != ZREFCOUNTER_DEALLOC_BIT)
return;
ReferenceLost();
Object = NULL;
Ref = NULL;
}
}
//Checks to see if the counter is NULL because the pointer is NULL and increments the count
inline void ReferenceGained()
{
if (Ref != NULL)
Ref->GainWeakRef();
}
//Checks to see if we can delete the reference and lowers the count
inline void ReferenceLost()
{
//This can be NULL in the case of a default constructed (NULL) pointer
if (Ref == NULL)
return;
ZASSERT_UTIL(Ref->GetWeakRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deleted!");
uint32_t combinedCount = Ref->LoseWeakRef();
if(combinedCount == 0) //If we by losing the weak reference we've reached zero on both weak/strong, deallocate the counter
{
//Deallocate the counter
RefAllocator.DeallocateCounter(Ref);
}
//We lost our reference, so we don't need these
Object = NULL;
Ref = NULL;
}
public:
/*
Default constructor. Sets the reference to NULL.
*/
ZWeakPointer()
: Object(NULL), Ref(NULL)
{ }
/*
Copy constructor.
@param _other - the other weak pointer
*/
ZWeakPointer(const ZWeakPointer<T, R>& _other)
: Object(_other.Pointer()), Ref(_other.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");
ReferenceGained();
}
/*
Conversion constructor. Used to auto up-cast derived classes, or a
class/object convertible to T.
@param D - the type contained by the other weak pointer
@param S - the reference counter allocator type used by the other weak pointer
@param _other - the other weak pointer
*/
template <typename D, typename S>
ZWeakPointer(const ZWeakPointer<D, S>& _other)
: Object(static_cast<T*>(_other.Pointer())), Ref(_other.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");
ReferenceGained();
}
/*
Constructor. Takes a ZSmartPointer instance to create a weak pointer.
@param DF - the deallocation functor type used by the smart pointer
@param _host - the host smart pointer used to initialize this weak pointer
*/
template <typename DF>
ZWeakPointer(const ZSmartPointer<T, DF, R>& _host)
: Object(_host.Pointer()), Ref(_host.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");
ReferenceGained();
}
/*
Conversion constructor. Used to construct from a ZSmartPointer of a derived class,
or a class/object convertible to T.
@param D - the type contained by the other weak pointer
@param DF - the deallocation functor type used by the smart pointer
@param S - the reference counter allocator type used by the other weak pointer
@param _host - the host smart pointer used to initialize this weak pointer
*/
template <typename D, typename DF, typename S>
ZWeakPointer(const ZSmartPointer<D, DF, S>& _host)
: Object(static_cast<T*>(_host.Pointer())), Ref(_host.Counter())
{
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");
ReferenceGained();
}
/*
Destructor. Causes a weak reference to be lost.
*/
~ZWeakPointer()
{
ReferenceLost();
}
/*
= operator overload. This version is used only to assign to NULL and nullify
the reference.
@param _null - the NULL value
@return (ZWeakPointer<T, R>&) - this weak pointer
@assert - if _null is not the value NULL
*/
ZWeakPointer<T, R>& operator = (int _null)
{
ZASSERT_RUNTIME(_null == 0, "ZWeakPointer: Assignment operator to int can only be used to assign to NULL!");
ReferenceLost(); //Lose a weak reference
Object = NULL; //Nullify our object pointer
Ref = NULL; //Nullify our reference counter
return *this;
}
/*
= operator overload. Constructs this weak pointer from another weak pointer,
incrementing the weak reference count on the object.
@param _other - the other weak pointer
@return (ZWeakPointer<T, R>&)- this weak pointer
*/
ZWeakPointer<T, R>& operator = (const ZWeakPointer<T, R>& _other)
{
if (*this == _other || Ref == _other.Counter())
return *this;
ReferenceLost(); //Lose a reference to our current object
Ref = _other.Counter(); //Get our new reference counter
ReferenceGained(); //Increment the reference
Object = _other.Pointer(); //Reference It
return *this;
}
/*
= operator overload. Used to assign to derived classes or classes that
can be converted.
@param D - the type contained by the other weak pointer
@param S - the reference counter allocator type used by the other weak pointer
@param _other - the other smart pointer
@return (ZWeakPointer<T, R>&) - this weak pointer
*/
template <typename D, typename S>
ZWeakPointer<T, R>& operator = (const ZWeakPointer<D, 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< ZWeakPointer<T, R> >(_other);
}
/*
= operator overload. Used to set the weak pointer from a host smart pointer.
@param DF - the deallocation functor type used by the smart pointer
@param _host - the host smart pointer used to initialize this weak pointer
@return (ZWeakPointer<T, R>&) - this weak pointer
*/
template <typename DF>
ZWeakPointer<T, R>& operator = (const ZSmartPointer<T, DF, R>& _host)
{
if (*this == _host || Ref == _host.Counter())
return *this;
ReferenceLost(); //Lose a reference to our current object
Object = _host.Pointer(); //Reference It
Ref = _host.Counter(); //Get our new reference counter
ReferenceGained(); //Increment the reference
return *this;
}
/*
= operator overload. Used to set the weak pointer from a host smart pointer of
a derived type or a type that can be converted.
@param D - the type contained by the other weak pointer
@param DF - the deallocation functor type used by the smart pointer
@param S - the reference counter allocator type used by the other weak pointer
@param _host - the host smart pointer used to initialize this weak pointer
@return (ZWeakPointer<T, R>&) - this weak pointer
*/
template <typename D, typename DF, typename S>
ZWeakPointer<T, R>& operator = (const ZSmartPointer<D, DF, S>& _host)
{
T* testCast = static_cast<T*>(_host.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D*
return *this = static_cast< ZSmartPointer<T, DF, R> >(_host);
}
/*
== operator overload. Checks to see if this weak pointer references the provided
raw pointer.
@param _ptr - the pointer to check
@return (bool) - true if the pointer is referenced by the weak pointer, false otherwise
*/
bool operator == (const T* _ptr)
{
CheckReferences();
return Object == _ptr;
}
/*
== operator overload. Checks to see if these pointers reference the same object.
@param _other - the other weak pointer
@return (bool) - true if they reference the same object, false otherwise
*/
bool operator == (const ZWeakPointer<T, R>& _other)
{
CheckReferences();
return Object == _other.Pointer();
}
/*
== operator overload. Used to compare with weak pointers containing objects of a
derived type or a type that can be converted to T.
@param D - the type contained by the other weak pointer
@param S - the reference counter allocator type used by the other weak pointer
@param _other - the other smart pointer
@return (bool) - true if equal, false otherwise
*/
template <typename D, typename S>
bool operator == (const ZWeakPointer<D, S>& _other)
{
CheckReferences();
return Object == static_cast<T*>(_other.Pointer());
}
/*
== operator overload. Used to determine if this weak pointer and a smart pointer
reference the same object.
@param DF - the deallocator functor used by the smart pointer
@param _other - the other smart pointer
@return (bool) - true if they reference the same object, false otherwise.
*/
template <typename DF>
bool operator == (const ZSmartPointer<T, DF, R>& _other)
{
CheckReferences();
return Object == _other.Pointer();
}
/*
== operator overload. Used to compare to determine if this weak pointer and a smart
pointer with different template types reference the same object.
@param D - the type contained by the smart pointer
@param DF - the deallocator functor used by the smart pointer
@param S - the reference counter allocator type used by the other smart pointer
@param _other - the other smart pointer
@return -this weak pointer
*/
template <typename D, typename DF, typename S>
bool operator == (const ZSmartPointer<D, DF, S>& _other)
{
return Object == static_cast<T*>(_other.Pointer());
}
/*
!= operator overload. Checks to see if this weak pointer does not
reference the provided raw pointer.
@param _ptr - the pointer to check
@return (bool) - false if equal, true otherwise
*/
bool operator != (const T* _ptr)
{
return !(*this == _ptr);
}
/*
!= operator overload. Checks to see if these pointers reference different
objects.
@param _other - the other smart pointer
@return (bool) - false if equal, true otherwise
*/
bool operator != (const ZWeakPointer<T, R>& _other)
{
return !(*this == _other);
}
/*
!= operator overload. Checks to see if these pointers reference different
objects.
@param D - the type contained by the other weak pointer
@param S - the reference counter allocator type for the other weak pointeR
@param _other - the other smart pointer
@return (bool) - false if equal, true otherwise
*/
template <typename D, typename S>
bool operator != (const ZWeakPointer<D, S>& _other)
{
return !(*this == _other);
}
/*
!= operator overload. Used to determine if this weak pointer and the given smart
pointer reference the same object.
@param DF - the deallocator functor type for the smart pointer
@param _other - the other smart pointer
@return (bool) - false if equal, true otherwise
*/
template <typename DF>
bool operator != (const ZSmartPointer<T, DF, R>& _other)
{
return !(*this == _other);
}
/*
!= operator overload. Used to determine if this weak pointer and the given smart
pointer with different template arguments reference the same object.
@param D - the type referenced by the other smart pointer
@param DF - the deallocator functor type for the smart pointer
@param S - the reference counter deallocator type for the smart pointer
@param _other - the other smart pointer
@return (bool) - false if equal, true otherwise
*/
template <typename D, typename DF, typename S>
bool operator != (const ZSmartPointer<D, DF, S>& _other)
{
return !(*this == _other);
}
/*
-> operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
@return - the managed pointer
@assert - if the pointer is NULL
*/
T* operator -> ()
{
CheckReferences();
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
return Object;
}
/*
'*' operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
@return - reference to the managed object
@assert - if the object is NULL
*/
T& operator * ()
{
CheckReferences();
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
return *Object;
}
/*
Operator override which enables use of the DeallocLock macro. ZWeakPointer instances
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
@return (ZWeakPointerDeallocLock) - dealloc lock
*/
ZWeakPointerDeallocLock operator () ()
{
CheckReferences();
return ZWeakPointerDeallocLock(Ref);
}
/*
public ZWeakPointer<C, R>::Cast
Used to cast this weak pointer into another type. This will construct an
additional weak pointer that also references the object. The referenced
object must be convertible to type C* via static_cast.
@param C - the type we should cast this weak pointer to
@return (ZWeakPointer<C, R>) - the casted weak pointer
*/
template <typename C>
ZWeakPointer<C, R> Cast()
{
CheckReferences();
return static_cast< ZWeakPointer<C, R> >(*this);
}
/*
public ZWeakPointer<T, A>::Counter
Gets the reference counter used by this weak pointer.
@return (ZSmartPointerRefCounter*) - reference counter instance
*/
ZReferenceCounter* Counter() const
{
return Ref;
}
/*
public ZWeakPointer<T, A>::Pointer
Gets the weak 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 R>
void ZWeakPointerArrayNullify(ZWeakPointer<T, R>* _array, size_t _start, size_t _end)
{
for (size_t i = _start; i < _end; i++)
_array[i] = NULL;
}
//Specialization for ZArray_ClearImpl containing ZWeakPointer
template <typename T, typename A, typename R>
struct ZArray_ClearImpl< ZWeakPointer<T, R>, A> {
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self)
{
//Nullify references
ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize);
//Reset size and check integrity
_self.ArraySize = 0;
_self.CheckIntegrity();
}
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, size_t _newCapacity)
{
//Nullify references
ZWeakPointerArrayNullify(_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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZArray_EraseImpl< ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, 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
ZWeakPointer<T, 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
ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);
return element;
}
inline static void Call(ZArray<ZWeakPointer<T, 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)
ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start));
}
};
//Specialization for ZArray_PopBackImpl containing ZWeakPointer
template <typename T, typename A, typename R>
struct ZArray_PopBackImpl< ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self)
{
#if !ZSTL_DISABLE_RUNTIME_CHECKS
ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
#endif
ZWeakPointer<T, R> ptr = _self.Array[--(_self.ArraySize)];
//Nullify reference
ZWeakPointerArrayNullify(_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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZArray_PopFrontImpl< ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, 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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZArray_ResizeImpl< ZWeakPointer<T, R>, A> {
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _size)
{
//Nullify references if needed
if (_size < _self.ArraySize)
ZWeakPointerArrayNullify(_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<ZWeakPointer<T, R>, A>& _self, const size_t _size, const ZWeakPointer<T, R>& _value)
{
//Nullify references if needed
if (_size < _self.ArraySize)
ZWeakPointerArrayNullify(_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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZList_ClearImpl < ZWeakPointer<T, R>, A> {
inline static void Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr) {
ZListNode<ZWeakPointer<T, R> >* next;
ZListNode<ZWeakPointer<T, 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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZList_EraseImpl < ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr)
{
ZWeakPointer<T, R> elem;
ZListNode< ZWeakPointer<T, 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<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _start, const ZListIterator< ZWeakPointer<T, R> >& _end)
{
ZListNode< ZWeakPointer<T, R> > *nodeStart = _start.GetNode();
ZListNode< ZWeakPointer<T, R> > *nodeEnd = _end.GetNode();
ZListNode< ZWeakPointer<T, R> > *curNode;
ZListNode< ZWeakPointer<T, 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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZList_PopBackImpl < ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {
ZWeakPointer<T, R> elem;
ZListNode< ZWeakPointer<T, 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 ZWeakPointer
template <typename T, typename A, typename R>
struct ZList_PopFrontImpl < ZWeakPointer<T, R>, A> {
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {
ZWeakPointer<T, R> elem;
ZListNode< ZWeakPointer<T, 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 ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_ClearImpl < ZWeakPointer<T, R>, P, A> {
inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
{
// set to null to remove references
for (size_t i = 0; i < _self.BufferSize; i++)
_self.At(i) = ZWeakPointer<T, R>(NULL);
_self.BufferSize = 0;
_self.FrontIndex = 0;
_self.BackIndex = 0;
}
inline static void Call( ZRingBuffer< ZWeakPointer<T, 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) = ZWeakPointer<T, R>(NULL);
_self.Buffer.Resize(_newCapacity);
_self.BufferSize = 0;
_self.FrontIndex = 0;
_self.BackIndex = 0;
}
};
//Specialization for ZRingBuffer_EraseImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_EraseImpl < ZWeakPointer<T, R>, P, A> {
inline static T Call( ZRingBuffer< ZWeakPointer<T, 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
ZWeakPointer<T, R> ret = _self.Buffer.At(_index);
_self.Buffer.At(_index) = ZWeakPointer<T, R>(NULL);
return ret;
}
inline static void Call( ZRingBuffer< ZWeakPointer<T, 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) = ZWeakPointer<T, R>(NULL);
_self.Buffer.Erase(_i, _j);
}
};
//Specialization for ZRingBuffer_PopBackImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_PopBackImpl < ZWeakPointer<T, R>, P, A> {
inline static T Call( ZRingBuffer< ZWeakPointer<T, 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
ZWeakPointer<T, R> ret = _self.Buffer.At(index);
_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
return ret;
}
};
//Specialization for ZRingBuffer_PopFrontImpl containing ZWeakPointer
template <typename T, typename P, typename A, typename R>
struct ZRingBuffer_PopFrontImpl < ZWeakPointer<T, R>, P, A> {
inline static T Call( ZRingBuffer< ZWeakPointer<T, 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
ZWeakPointer<T, R> ret = _self.Buffer.At(index);
_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
return ret;
}
};
#endif