Initial commit
This commit is contained in:
944
Include/ZUtil/ZSmartPointer.hpp
Normal file
944
Include/ZUtil/ZSmartPointer.hpp
Normal file
@@ -0,0 +1,944 @@
|
||||
/*
|
||||
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
|
||||
Reference in New Issue
Block a user