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

945 lines
26 KiB
C++

/*
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