/* ZWeakPointer.hpp Author: James Russell 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 /* 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 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 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& _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 ZWeakPointer(const ZWeakPointer& _other) : Object(static_cast(_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 ZWeakPointer(const ZSmartPointer& _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 ZWeakPointer(const ZSmartPointer& _host) : Object(static_cast(_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&) - this weak pointer @assert - if _null is not the value NULL */ ZWeakPointer& 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&)- this weak pointer */ ZWeakPointer& operator = (const ZWeakPointer& _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&) - this weak pointer */ template ZWeakPointer& operator = (const ZWeakPointer& _other) { T* testCast = static_cast(_other.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D* return *this = static_cast< ZWeakPointer >(_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&) - this weak pointer */ template ZWeakPointer& operator = (const ZSmartPointer& _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&) - this weak pointer */ template ZWeakPointer& operator = (const ZSmartPointer& _host) { T* testCast = static_cast(_host.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D* return *this = static_cast< ZSmartPointer >(_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& _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 bool operator == (const ZWeakPointer& _other) { CheckReferences(); return Object == static_cast(_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 bool operator == (const ZSmartPointer& _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 bool operator == (const ZSmartPointer& _other) { return Object == static_cast(_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& _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 bool operator != (const ZWeakPointer& _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 bool operator != (const ZSmartPointer& _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 bool operator != (const ZSmartPointer& _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::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) - the casted weak pointer */ template ZWeakPointer Cast() { CheckReferences(); return static_cast< ZWeakPointer >(*this); } /* public ZWeakPointer::Counter Gets the reference counter used by this weak pointer. @return (ZSmartPointerRefCounter*) - reference counter instance */ ZReferenceCounter* Counter() const { return Ref; } /* public ZWeakPointer::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 void ZWeakPointerArrayNullify(ZWeakPointer* _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 struct ZArray_ClearImpl< ZWeakPointer, A> { inline static void Call(ZArray, 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, 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 struct ZArray_EraseImpl< ZWeakPointer, A> { inline static ZWeakPointer Call(ZArray, 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 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, 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 struct ZArray_PopBackImpl< ZWeakPointer, A> { inline static ZWeakPointer Call(ZArray, A>& _self) { #if !ZSTL_DISABLE_RUNTIME_CHECKS ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!"); #endif ZWeakPointer 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 struct ZArray_PopFrontImpl< ZWeakPointer, A> { inline static ZWeakPointer Call(ZArray, 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 struct ZArray_ResizeImpl< ZWeakPointer, A> { inline static void Call(ZArray, 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, A>& _self, const size_t _size, const ZWeakPointer& _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 struct ZList_ClearImpl < ZWeakPointer, A> { inline static void Call(ZList, A>& _self, ZListIterator< ZWeakPointer >& _itr) { ZListNode >* next; ZListNode >* 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 struct ZList_EraseImpl < ZWeakPointer, A> { inline static ZWeakPointer Call(ZList, A>& _self, ZListIterator< ZWeakPointer >& _itr) { ZWeakPointer elem; ZListNode< ZWeakPointer > *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, A>& _self, ZListIterator< ZWeakPointer >& _start, const ZListIterator< ZWeakPointer >& _end) { ZListNode< ZWeakPointer > *nodeStart = _start.GetNode(); ZListNode< ZWeakPointer > *nodeEnd = _end.GetNode(); ZListNode< ZWeakPointer > *curNode; ZListNode< ZWeakPointer > *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 struct ZList_PopBackImpl < ZWeakPointer, A> { inline static ZWeakPointer Call(ZList, A>& _self) { ZWeakPointer elem; ZListNode< ZWeakPointer > *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 struct ZList_PopFrontImpl < ZWeakPointer, A> { inline static ZWeakPointer Call(ZList, A>& _self) { ZWeakPointer elem; ZListNode< ZWeakPointer > *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 struct ZRingBuffer_ClearImpl < ZWeakPointer, P, A> { inline static void Call( ZRingBuffer< ZWeakPointer, P, A>& _self ) { // set to null to remove references for (size_t i = 0; i < _self.BufferSize; i++) _self.At(i) = ZWeakPointer(NULL); _self.BufferSize = 0; _self.FrontIndex = 0; _self.BackIndex = 0; } inline static void Call( ZRingBuffer< ZWeakPointer, 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(NULL); _self.Buffer.Resize(_newCapacity); _self.BufferSize = 0; _self.FrontIndex = 0; _self.BackIndex = 0; } }; //Specialization for ZRingBuffer_EraseImpl containing ZWeakPointer template struct ZRingBuffer_EraseImpl < ZWeakPointer, P, A> { inline static T Call( ZRingBuffer< ZWeakPointer, 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 ret = _self.Buffer.At(_index); _self.Buffer.At(_index) = ZWeakPointer(NULL); return ret; } inline static void Call( ZRingBuffer< ZWeakPointer, 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(NULL); _self.Buffer.Erase(_i, _j); } }; //Specialization for ZRingBuffer_PopBackImpl containing ZWeakPointer template struct ZRingBuffer_PopBackImpl < ZWeakPointer, P, A> { inline static T Call( ZRingBuffer< ZWeakPointer, 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 ret = _self.Buffer.At(index); _self.Buffer.At(index) = ZWeakPointer(NULL); return ret; } }; //Specialization for ZRingBuffer_PopFrontImpl containing ZWeakPointer template struct ZRingBuffer_PopFrontImpl < ZWeakPointer, P, A> { inline static T Call( ZRingBuffer< ZWeakPointer, 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 ret = _self.Buffer.At(index); _self.Buffer.At(index) = ZWeakPointer(NULL); return ret; } }; #endif