945 lines
26 KiB
C++
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
|