1025 lines
28 KiB
C++
1025 lines
28 KiB
C++
/*
|
|
ZWeakPointer.hpp
|
|
Author: James Russell <jcrussell@762studios.com>
|
|
Created: 08/12/2011
|
|
|
|
Purpose:
|
|
|
|
TODO
|
|
|
|
Don't pass these things around by pointer or reference unless you really know what you
|
|
are doing. You won't like the results.
|
|
|
|
License:
|
|
|
|
TODO
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef _ZWEAKPOINTER_H
|
|
#define _ZWEAKPOINTER_H
|
|
|
|
#include <ZUtil/ZSmartPointer.hpp>
|
|
|
|
/*
|
|
DeallocLock macro, used to lock a weak pointer when in use to prevent
|
|
deallocation. Using this ensures that the ZReferenceCounter functions
|
|
SignalInUse / SignalUnused are respected.
|
|
|
|
Usage:
|
|
ZWeakPointer<Object> ptr;
|
|
|
|
DeallocLock(ptr) {
|
|
... code to execute using ptr ...
|
|
}
|
|
*/
|
|
#define DeallocLock(weakPointer) if (ZWeakPointerDeallocLock dealloc_lock##__LINE__ = weakPointer())
|
|
|
|
/*
|
|
Struct used to ensure (via RAII and scoped construction and destruction) that while weak pointers
|
|
are in use, the object will not be deallocated by the owning smart pointer.
|
|
*/
|
|
struct ZWeakPointerDeallocLock {
|
|
|
|
//Indicates whether or not we successfully obtained the lock on our reference counter
|
|
bool bLockObtained;
|
|
|
|
//The reference counter we attempt to lock
|
|
ZReferenceCounter* Ref;
|
|
|
|
/*
|
|
Default constructor. Calls the SignalInUse function on _counter and stores the
|
|
result of the call.
|
|
|
|
@param _counter - the reference counter struct to signal
|
|
*/
|
|
ZWeakPointerDeallocLock(ZReferenceCounter* _counter)
|
|
: bLockObtained(_counter != NULL && _counter->SignalInUse()), Ref(_counter)
|
|
{ }
|
|
|
|
/*
|
|
Destructor. If the lock was successfully obtained, will signal the object no longer
|
|
in use.
|
|
*/
|
|
~ZWeakPointerDeallocLock()
|
|
{
|
|
if (bLockObtained && Ref != NULL)
|
|
Ref->SignalUnused();
|
|
}
|
|
|
|
/*
|
|
operator bool override. Returns whether or not the lock was successful.
|
|
|
|
@return (bool) - true if the lock succeeded, false otherwise
|
|
*/
|
|
operator bool ()
|
|
{
|
|
return bLockObtained;
|
|
}
|
|
};
|
|
|
|
/*
|
|
Weak pointer class, used to maintain a weak reference to an object that has a reference
|
|
whose lifetime is maintained by instances of ZSmartPointer.
|
|
|
|
@param T - the type of object referenced by the weak pointer
|
|
|
|
@param R - the reference counter allocator type to use
|
|
*/
|
|
template <typename T, typename R = ZReferenceCounterAllocator >
|
|
class ZWeakPointer
|
|
{
|
|
private:
|
|
//Managed Pointer
|
|
T* Object;
|
|
|
|
//Reference Counter Allocator, used to deallocate the ref counter
|
|
R RefAllocator;
|
|
|
|
//Reference Counter for the pointer
|
|
ZReferenceCounter* Ref;
|
|
|
|
//Checks to see if the object has lost all strong references and is deleted
|
|
inline void CheckReferences()
|
|
{
|
|
if (Ref != NULL && Ref->GetStrongRefCount() == 0)
|
|
{
|
|
//There is an edge case here wherein the strong count is zero, the deallocation flag
|
|
//on the reference counter has been set, but the object is in use (by us)
|
|
if (Ref->State != ZREFCOUNTER_DEALLOC_BIT)
|
|
return;
|
|
|
|
ReferenceLost();
|
|
|
|
Object = NULL;
|
|
Ref = NULL;
|
|
}
|
|
}
|
|
|
|
//Checks to see if the counter is NULL because the pointer is NULL and increments the count
|
|
inline void ReferenceGained()
|
|
{
|
|
if (Ref != NULL)
|
|
Ref->GainWeakRef();
|
|
}
|
|
|
|
//Checks to see if we can delete the reference and lowers the count
|
|
inline void ReferenceLost()
|
|
{
|
|
//This can be NULL in the case of a default constructed (NULL) pointer
|
|
if (Ref == NULL)
|
|
return;
|
|
|
|
ZASSERT_UTIL(Ref->GetWeakRefCount() > 0 && Object != NULL, "ZSmartPointer: Reference lost but object is already deleted!");
|
|
|
|
uint32_t combinedCount = Ref->LoseWeakRef();
|
|
|
|
if(combinedCount == 0) //If we by losing the weak reference we've reached zero on both weak/strong, deallocate the counter
|
|
{
|
|
//Deallocate the counter
|
|
RefAllocator.DeallocateCounter(Ref);
|
|
}
|
|
|
|
//We lost our reference, so we don't need these
|
|
Object = NULL;
|
|
Ref = NULL;
|
|
}
|
|
|
|
public:
|
|
/*
|
|
Default constructor. Sets the reference to NULL.
|
|
*/
|
|
ZWeakPointer()
|
|
: Object(NULL), Ref(NULL)
|
|
{ }
|
|
|
|
/*
|
|
Copy constructor.
|
|
|
|
@param _other - the other weak pointer
|
|
*/
|
|
ZWeakPointer(const ZWeakPointer<T, R>& _other)
|
|
: Object(_other.Pointer()), Ref(_other.Counter())
|
|
{
|
|
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");
|
|
|
|
ReferenceGained();
|
|
}
|
|
|
|
/*
|
|
Conversion constructor. Used to auto up-cast derived classes, or a
|
|
class/object convertible to T.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param S - the reference counter allocator type used by the other weak pointer
|
|
@param _other - the other weak pointer
|
|
*/
|
|
template <typename D, typename S>
|
|
ZWeakPointer(const ZWeakPointer<D, S>& _other)
|
|
: Object(static_cast<T*>(_other.Pointer())), Ref(_other.Counter())
|
|
{
|
|
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from weak pointer with invalid reference counter!");
|
|
|
|
ReferenceGained();
|
|
}
|
|
|
|
/*
|
|
Constructor. Takes a ZSmartPointer instance to create a weak pointer.
|
|
|
|
@param DF - the deallocation functor type used by the smart pointer
|
|
@param _host - the host smart pointer used to initialize this weak pointer
|
|
*/
|
|
template <typename DF>
|
|
ZWeakPointer(const ZSmartPointer<T, DF, R>& _host)
|
|
: Object(_host.Pointer()), Ref(_host.Counter())
|
|
{
|
|
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");
|
|
|
|
ReferenceGained();
|
|
}
|
|
|
|
/*
|
|
Conversion constructor. Used to construct from a ZSmartPointer of a derived class,
|
|
or a class/object convertible to T.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param DF - the deallocation functor type used by the smart pointer
|
|
@param S - the reference counter allocator type used by the other weak pointer
|
|
@param _host - the host smart pointer used to initialize this weak pointer
|
|
*/
|
|
template <typename D, typename DF, typename S>
|
|
ZWeakPointer(const ZSmartPointer<D, DF, S>& _host)
|
|
: Object(static_cast<T*>(_host.Pointer())), Ref(_host.Counter())
|
|
{
|
|
ZASSERT_UTIL(!(Object != NULL && Ref == NULL), "ZWeakPointer: Copy constructor called from smart pointer with invalid reference counter!");
|
|
|
|
ReferenceGained();
|
|
}
|
|
|
|
/*
|
|
Destructor. Causes a weak reference to be lost.
|
|
*/
|
|
~ZWeakPointer()
|
|
{
|
|
ReferenceLost();
|
|
}
|
|
|
|
/*
|
|
= operator overload. This version is used only to assign to NULL and nullify
|
|
the reference.
|
|
|
|
@param _null - the NULL value
|
|
@return (ZWeakPointer<T, R>&) - this weak pointer
|
|
@assert - if _null is not the value NULL
|
|
*/
|
|
ZWeakPointer<T, R>& operator = (int _null)
|
|
{
|
|
ZASSERT_RUNTIME(_null == 0, "ZWeakPointer: Assignment operator to int can only be used to assign to NULL!");
|
|
|
|
ReferenceLost(); //Lose a weak reference
|
|
Object = NULL; //Nullify our object pointer
|
|
Ref = NULL; //Nullify our reference counter
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
= operator overload. Constructs this weak pointer from another weak pointer,
|
|
incrementing the weak reference count on the object.
|
|
|
|
@param _other - the other weak pointer
|
|
@return (ZWeakPointer<T, R>&)- this weak pointer
|
|
*/
|
|
ZWeakPointer<T, R>& operator = (const ZWeakPointer<T, R>& _other)
|
|
{
|
|
if (*this == _other || Ref == _other.Counter())
|
|
return *this;
|
|
|
|
ReferenceLost(); //Lose a reference to our current object
|
|
Ref = _other.Counter(); //Get our new reference counter
|
|
ReferenceGained(); //Increment the reference
|
|
|
|
Object = _other.Pointer(); //Reference It
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
= operator overload. Used to assign to derived classes or classes that
|
|
can be converted.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param S - the reference counter allocator type used by the other weak pointer
|
|
@param _other - the other smart pointer
|
|
@return (ZWeakPointer<T, R>&) - this weak pointer
|
|
*/
|
|
template <typename D, typename S>
|
|
ZWeakPointer<T, R>& operator = (const ZWeakPointer<D, S>& _other)
|
|
{
|
|
T* testCast = static_cast<T*>(_other.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D*
|
|
|
|
return *this = static_cast< ZWeakPointer<T, R> >(_other);
|
|
}
|
|
|
|
/*
|
|
= operator overload. Used to set the weak pointer from a host smart pointer.
|
|
|
|
@param DF - the deallocation functor type used by the smart pointer
|
|
@param _host - the host smart pointer used to initialize this weak pointer
|
|
@return (ZWeakPointer<T, R>&) - this weak pointer
|
|
*/
|
|
template <typename DF>
|
|
ZWeakPointer<T, R>& operator = (const ZSmartPointer<T, DF, R>& _host)
|
|
{
|
|
if (*this == _host || Ref == _host.Counter())
|
|
return *this;
|
|
|
|
ReferenceLost(); //Lose a reference to our current object
|
|
|
|
Object = _host.Pointer(); //Reference It
|
|
Ref = _host.Counter(); //Get our new reference counter
|
|
|
|
ReferenceGained(); //Increment the reference
|
|
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
= operator overload. Used to set the weak pointer from a host smart pointer of
|
|
a derived type or a type that can be converted.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param DF - the deallocation functor type used by the smart pointer
|
|
@param S - the reference counter allocator type used by the other weak pointer
|
|
@param _host - the host smart pointer used to initialize this weak pointer
|
|
@return (ZWeakPointer<T, R>&) - this weak pointer
|
|
*/
|
|
template <typename D, typename DF, typename S>
|
|
ZWeakPointer<T, R>& operator = (const ZSmartPointer<D, DF, S>& _host)
|
|
{
|
|
T* testCast = static_cast<T*>(_host.Pointer()); ((void)testCast); //This will fail to compile if T* cannot static cast to D*
|
|
|
|
return *this = static_cast< ZSmartPointer<T, DF, R> >(_host);
|
|
}
|
|
|
|
/*
|
|
== operator overload. Checks to see if this weak pointer references the provided
|
|
raw pointer.
|
|
|
|
@param _ptr - the pointer to check
|
|
@return (bool) - true if the pointer is referenced by the weak pointer, false otherwise
|
|
*/
|
|
bool operator == (const T* _ptr)
|
|
{
|
|
CheckReferences();
|
|
|
|
return Object == _ptr;
|
|
}
|
|
|
|
/*
|
|
== operator overload. Checks to see if these pointers reference the same object.
|
|
|
|
@param _other - the other weak pointer
|
|
@return (bool) - true if they reference the same object, false otherwise
|
|
*/
|
|
bool operator == (const ZWeakPointer<T, R>& _other)
|
|
{
|
|
CheckReferences();
|
|
|
|
return Object == _other.Pointer();
|
|
}
|
|
|
|
/*
|
|
== operator overload. Used to compare with weak pointers containing objects of a
|
|
derived type or a type that can be converted to T.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param S - the reference counter allocator type used by the other weak pointer
|
|
@param _other - the other smart pointer
|
|
@return (bool) - true if equal, false otherwise
|
|
*/
|
|
template <typename D, typename S>
|
|
bool operator == (const ZWeakPointer<D, S>& _other)
|
|
{
|
|
CheckReferences();
|
|
|
|
return Object == static_cast<T*>(_other.Pointer());
|
|
}
|
|
|
|
/*
|
|
== operator overload. Used to determine if this weak pointer and a smart pointer
|
|
reference the same object.
|
|
|
|
@param DF - the deallocator functor used by the smart pointer
|
|
@param _other - the other smart pointer
|
|
@return (bool) - true if they reference the same object, false otherwise.
|
|
*/
|
|
template <typename DF>
|
|
bool operator == (const ZSmartPointer<T, DF, R>& _other)
|
|
{
|
|
CheckReferences();
|
|
|
|
return Object == _other.Pointer();
|
|
}
|
|
|
|
/*
|
|
== operator overload. Used to compare to determine if this weak pointer and a smart
|
|
pointer with different template types reference the same object.
|
|
|
|
@param D - the type contained by the smart pointer
|
|
@param DF - the deallocator functor used by the smart pointer
|
|
@param S - the reference counter allocator type used by the other smart pointer
|
|
@param _other - the other smart pointer
|
|
@return -this weak pointer
|
|
*/
|
|
template <typename D, typename DF, typename S>
|
|
bool operator == (const ZSmartPointer<D, DF, S>& _other)
|
|
{
|
|
return Object == static_cast<T*>(_other.Pointer());
|
|
}
|
|
|
|
/*
|
|
!= operator overload. Checks to see if this weak pointer does not
|
|
reference the provided raw pointer.
|
|
|
|
@param _ptr - the pointer to check
|
|
@return (bool) - false if equal, true otherwise
|
|
*/
|
|
bool operator != (const T* _ptr)
|
|
{
|
|
return !(*this == _ptr);
|
|
}
|
|
|
|
/*
|
|
!= operator overload. Checks to see if these pointers reference different
|
|
objects.
|
|
|
|
@param _other - the other smart pointer
|
|
@return (bool) - false if equal, true otherwise
|
|
*/
|
|
bool operator != (const ZWeakPointer<T, R>& _other)
|
|
{
|
|
return !(*this == _other);
|
|
}
|
|
|
|
/*
|
|
!= operator overload. Checks to see if these pointers reference different
|
|
objects.
|
|
|
|
@param D - the type contained by the other weak pointer
|
|
@param S - the reference counter allocator type for the other weak pointeR
|
|
@param _other - the other smart pointer
|
|
@return (bool) - false if equal, true otherwise
|
|
*/
|
|
template <typename D, typename S>
|
|
bool operator != (const ZWeakPointer<D, S>& _other)
|
|
{
|
|
return !(*this == _other);
|
|
}
|
|
|
|
/*
|
|
!= operator overload. Used to determine if this weak pointer and the given smart
|
|
pointer reference the same object.
|
|
|
|
@param DF - the deallocator functor type for the smart pointer
|
|
@param _other - the other smart pointer
|
|
@return (bool) - false if equal, true otherwise
|
|
*/
|
|
template <typename DF>
|
|
bool operator != (const ZSmartPointer<T, DF, R>& _other)
|
|
{
|
|
return !(*this == _other);
|
|
}
|
|
|
|
/*
|
|
!= operator overload. Used to determine if this weak pointer and the given smart
|
|
pointer with different template arguments reference the same object.
|
|
|
|
@param D - the type referenced by the other smart pointer
|
|
@param DF - the deallocator functor type for the smart pointer
|
|
@param S - the reference counter deallocator type for the smart pointer
|
|
@param _other - the other smart pointer
|
|
@return (bool) - false if equal, true otherwise
|
|
*/
|
|
template <typename D, typename DF, typename S>
|
|
bool operator != (const ZSmartPointer<D, DF, S>& _other)
|
|
{
|
|
return !(*this == _other);
|
|
}
|
|
|
|
/*
|
|
-> operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances
|
|
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
|
|
|
|
@return - the managed pointer
|
|
@assert - if the pointer is NULL
|
|
*/
|
|
T* operator -> ()
|
|
{
|
|
CheckReferences();
|
|
|
|
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
|
|
|
|
return Object;
|
|
}
|
|
|
|
/*
|
|
'*' operator overload. Allows this to be dereferenced as a T* would be. ZWeakPointer instances
|
|
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
|
|
|
|
@return - reference to the managed object
|
|
@assert - if the object is NULL
|
|
*/
|
|
T& operator * ()
|
|
{
|
|
CheckReferences();
|
|
|
|
ZASSERT_RUNTIME(Object != NULL, "ZSmartPointer: Null Pointer Dereferenced!");
|
|
|
|
return *Object;
|
|
}
|
|
|
|
/*
|
|
Operator override which enables use of the DeallocLock macro. ZWeakPointer instances
|
|
should only be accessed (via -> and *) from within the scope of a DeallocLock macro.
|
|
|
|
@return (ZWeakPointerDeallocLock) - dealloc lock
|
|
*/
|
|
ZWeakPointerDeallocLock operator () ()
|
|
{
|
|
CheckReferences();
|
|
|
|
return ZWeakPointerDeallocLock(Ref);
|
|
}
|
|
|
|
/*
|
|
public ZWeakPointer<C, R>::Cast
|
|
|
|
Used to cast this weak pointer into another type. This will construct an
|
|
additional weak pointer that also references the object. The referenced
|
|
object must be convertible to type C* via static_cast.
|
|
|
|
|
|
@param C - the type we should cast this weak pointer to
|
|
@return (ZWeakPointer<C, R>) - the casted weak pointer
|
|
*/
|
|
template <typename C>
|
|
ZWeakPointer<C, R> Cast()
|
|
{
|
|
CheckReferences();
|
|
|
|
return static_cast< ZWeakPointer<C, R> >(*this);
|
|
}
|
|
|
|
/*
|
|
public ZWeakPointer<T, A>::Counter
|
|
|
|
Gets the reference counter used by this weak pointer.
|
|
|
|
@return (ZSmartPointerRefCounter*) - reference counter instance
|
|
*/
|
|
ZReferenceCounter* Counter() const
|
|
{
|
|
return Ref;
|
|
}
|
|
|
|
/*
|
|
public ZWeakPointer<T, A>::Pointer
|
|
|
|
Gets the weak pointer as a raw pointer. Buyer beware.
|
|
|
|
@return (T*) - raw pointer that this smart pointer manages
|
|
*/
|
|
T* Pointer() const
|
|
{
|
|
return Object;
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////
|
|
/* ZArray Containment Specializations */
|
|
////////////////////////////////////////
|
|
|
|
//Helper function used to nullify references in a range
|
|
template <typename T, typename R>
|
|
void ZWeakPointerArrayNullify(ZWeakPointer<T, R>* _array, size_t _start, size_t _end)
|
|
{
|
|
for (size_t i = _start; i < _end; i++)
|
|
_array[i] = NULL;
|
|
}
|
|
|
|
//Specialization for ZArray_ClearImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZArray_ClearImpl< ZWeakPointer<T, R>, A> {
|
|
|
|
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self)
|
|
{
|
|
//Nullify references
|
|
ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize);
|
|
|
|
//Reset size and check integrity
|
|
_self.ArraySize = 0;
|
|
_self.CheckIntegrity();
|
|
}
|
|
|
|
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, size_t _newCapacity)
|
|
{
|
|
//Nullify references
|
|
ZWeakPointerArrayNullify(_self.Array, 0, _self.ArraySize);
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(_newCapacity > 0, "ZArray: Cannot set capacity to zero!");
|
|
#endif
|
|
|
|
//Reallocate if needed, drop our size to zero, and check integrity
|
|
if (_newCapacity > _self.ArrayCapacity)
|
|
{
|
|
_self.Deallocate(_self.Array, _self.ArrayCapacity);
|
|
_self.ArrayCapacity = _newCapacity;
|
|
_self.Allocate(_self.ArrayCapacity);
|
|
}
|
|
|
|
_self.ArraySize = 0;
|
|
_self.CheckIntegrity();
|
|
}
|
|
|
|
};
|
|
|
|
//Specialization for ZArray_EraseImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZArray_EraseImpl< ZWeakPointer<T, R>, A> {
|
|
|
|
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self, size_t _index)
|
|
{
|
|
size_t index = _self.BoundsCheck(_index, _self.ArraySize);
|
|
|
|
//Grab the currently held element, shift the array down, reduce size, and check integrity
|
|
ZWeakPointer<T, R> element = _self.Array[index];
|
|
|
|
for (size_t i = index; i + 1 < _self.ArraySize; i++)
|
|
_self.Array[i] = _self.Array[i + 1];
|
|
|
|
_self.ArraySize--;
|
|
_self.CheckIntegrity();
|
|
|
|
//Nullify reference
|
|
ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);
|
|
|
|
return element;
|
|
}
|
|
|
|
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _start, const size_t _end)
|
|
{
|
|
size_t start = _self.BoundsCheck(_start, _self.ArraySize);
|
|
size_t end = _self.BoundsCheck(_end, _self.ArraySize + 1);
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(start <= end, "ZArray: cannot erase with start < end!");
|
|
#endif
|
|
|
|
//Copy the elements down, compute new size, and check integrity
|
|
for (size_t idx = start; idx + (end - start) < _self.ArraySize; idx++)
|
|
_self.Array[idx] = _self.Array[idx + (end - start)];
|
|
|
|
_self.ArraySize = _self.ArraySize - (end - start);
|
|
_self.CheckIntegrity();
|
|
|
|
//Nullify references (where we moved from)
|
|
ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + (end - start));
|
|
}
|
|
};
|
|
|
|
//Specialization for ZArray_PopBackImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZArray_PopBackImpl< ZWeakPointer<T, R>, A> {
|
|
|
|
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self)
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
|
|
#endif
|
|
|
|
ZWeakPointer<T, R> ptr = _self.Array[--(_self.ArraySize)];
|
|
|
|
//Nullify reference
|
|
ZWeakPointerArrayNullify(_self.Array, _self.ArraySize, _self.ArraySize + 1);
|
|
|
|
//Grab the last element in the array and decrease our array size
|
|
return ptr;
|
|
}
|
|
|
|
};
|
|
|
|
//Specialization for ZArray_PopFrontImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZArray_PopFrontImpl< ZWeakPointer<T, R>, A> {
|
|
|
|
inline static ZWeakPointer<T, R> Call(ZArray<ZWeakPointer<T, R>, A>& _self)
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(_self.ArraySize > 0, "ZArray: Cannot pop from array with no elements!");
|
|
#endif
|
|
|
|
//This will nullify the reference
|
|
return _self.Erase(0);
|
|
}
|
|
|
|
};
|
|
|
|
//Specialization for ZArray_ResizeImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZArray_ResizeImpl< ZWeakPointer<T, R>, A> {
|
|
|
|
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _size)
|
|
{
|
|
//Nullify references if needed
|
|
if (_size < _self.ArraySize)
|
|
ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize);
|
|
|
|
//Check to see if we need more space, change our size, and check integrity
|
|
if (_size > _self.ArrayCapacity)
|
|
_self.Reserve(_size);
|
|
|
|
_self.ArraySize = _size;
|
|
_self.CheckIntegrity();
|
|
}
|
|
|
|
inline static void Call(ZArray<ZWeakPointer<T, R>, A>& _self, const size_t _size, const ZWeakPointer<T, R>& _value)
|
|
{
|
|
//Nullify references if needed
|
|
if (_size < _self.ArraySize)
|
|
ZWeakPointerArrayNullify(_self.Array, _size, _self.ArraySize);
|
|
|
|
//See if we need more space, copy in the new value, change our size, and check integrity
|
|
if (_size > _self.ArrayCapacity)
|
|
_self.Reserve(_size);
|
|
|
|
for (size_t i = _self.ArraySize; i < _size; i++)
|
|
_self.Array[i] = _value;
|
|
|
|
_self.ArraySize = _size;
|
|
_self.CheckIntegrity();
|
|
}
|
|
|
|
};
|
|
|
|
///////////////////////////////////////
|
|
/* ZList Containment Specializations */
|
|
///////////////////////////////////////
|
|
|
|
//Specialization for ZList_ClearImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZList_ClearImpl < ZWeakPointer<T, R>, A> {
|
|
|
|
inline static void Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr) {
|
|
|
|
ZListNode<ZWeakPointer<T, R> >* next;
|
|
ZListNode<ZWeakPointer<T, R> >* current = _itr.GetNode();
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
//Early out
|
|
if (_self.Empty())
|
|
return;
|
|
|
|
//If we are the starting node, be sure to reset the EmptyNode.Next pointer
|
|
if (current == _self.EmptyNode.Next)
|
|
_self.EmptyNode.Next = &_self.EmptyNode;
|
|
|
|
//This is always true
|
|
_self.EmptyNode.Previous = current->Previous;
|
|
current->Previous->Next = &_self.EmptyNode;
|
|
|
|
//Iterate and deallocate the nodes
|
|
while (current != &_self.EmptyNode)
|
|
{
|
|
next = current->Next;
|
|
current->Element = NULL; //This is the specialization
|
|
_self.DeallocateNode(current);
|
|
current = next;
|
|
}
|
|
|
|
//Set the node on the iterator equal to the end node
|
|
_itr.SetNode(&_self.EmptyNode);
|
|
|
|
_self.CheckIntegrity();
|
|
}
|
|
|
|
};
|
|
|
|
//Specialization for ZList_EraseImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZList_EraseImpl < ZWeakPointer<T, R>, A> {
|
|
|
|
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _itr)
|
|
{
|
|
ZWeakPointer<T, R> elem;
|
|
ZListNode< ZWeakPointer<T, R> > *node = _itr.GetNode();
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(node != NULL, "ZList: Iterator is invalid!");
|
|
ZSTL_ASSERT(node != &_self.EmptyNode, "ZList: Cannot erase end node!");
|
|
#endif
|
|
|
|
//Increment the iterator to the next list node to keep the iterator valid
|
|
++_itr;
|
|
|
|
//Rearrange the pointers
|
|
node->Previous->Next = node->Next;
|
|
node->Next->Previous = node->Previous;
|
|
|
|
elem = node->Element;
|
|
node->Element = NULL; //This is the specialization
|
|
|
|
_self.DeallocateNode(node);
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
return elem;
|
|
}
|
|
|
|
inline static void Call(ZList<ZWeakPointer<T, R>, A>& _self, ZListIterator< ZWeakPointer<T, R> >& _start, const ZListIterator< ZWeakPointer<T, R> >& _end)
|
|
{
|
|
|
|
ZListNode< ZWeakPointer<T, R> > *nodeStart = _start.GetNode();
|
|
ZListNode< ZWeakPointer<T, R> > *nodeEnd = _end.GetNode();
|
|
|
|
ZListNode< ZWeakPointer<T, R> > *curNode;
|
|
ZListNode< ZWeakPointer<T, R> > *prevNode;
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(nodeStart != NULL && nodeEnd != NULL, "ZList: Cannot erase with invalid iterator!");
|
|
ZSTL_ASSERT(nodeStart != &_self.EmptyNode, "ZList: Cannot erase end node!");
|
|
#endif
|
|
|
|
//Rearrange the pointers
|
|
nodeStart->Previous->Next = nodeEnd;
|
|
nodeEnd->Previous = nodeStart->Previous;
|
|
|
|
//Erase each element between from and to
|
|
curNode = nodeStart;
|
|
prevNode = NULL;
|
|
|
|
while (curNode != nodeEnd)
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(curNode != &_self.EmptyNode, "ZList: Cannot erase end node!");
|
|
#endif
|
|
|
|
prevNode = curNode;
|
|
curNode = curNode->Next;
|
|
|
|
prevNode->Element = NULL; //This is the specialization
|
|
_self.DeallocateNode(prevNode);
|
|
}
|
|
|
|
_start = _end;
|
|
}
|
|
|
|
};
|
|
|
|
//Specialization for ZList_PopBackImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZList_PopBackImpl < ZWeakPointer<T, R>, A> {
|
|
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {
|
|
|
|
ZWeakPointer<T, R> elem;
|
|
ZListNode< ZWeakPointer<T, R> > *node;
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from back of empty list!");
|
|
#endif
|
|
|
|
//Grab the element at the back of the list
|
|
node = _self.EmptyNode.Previous;
|
|
|
|
//Remove the node from the list
|
|
node->Previous->Next = &_self.EmptyNode;
|
|
_self.EmptyNode.Previous = node->Previous;
|
|
|
|
//Get the element value and lose our reference
|
|
elem = node->Element;
|
|
node->Element = NULL;
|
|
|
|
//Deallocate and then return
|
|
_self.DeallocateNode(node);
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
return elem;
|
|
}
|
|
};
|
|
|
|
//Specialization for ZList_PopFrontImpl containing ZWeakPointer
|
|
template <typename T, typename A, typename R>
|
|
struct ZList_PopFrontImpl < ZWeakPointer<T, R>, A> {
|
|
inline static ZWeakPointer<T, R> Call(ZList<ZWeakPointer<T, R>, A>& _self) {
|
|
|
|
ZWeakPointer<T, R> elem;
|
|
ZListNode< ZWeakPointer<T, R> > *node;
|
|
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT(!_self.Empty(), "ZList: Cannot pop from front of empty list!");
|
|
#endif
|
|
|
|
//Grab the element at the front of the list
|
|
node = _self.EmptyNode.Next;
|
|
|
|
//Remove the node from the list
|
|
node->Next->Previous = node->Previous;
|
|
node->Previous->Next = node->Next;
|
|
|
|
//Get the element value and lose our reference
|
|
elem = node->Element;
|
|
node->Element = NULL;
|
|
|
|
//Deallocate and then return
|
|
_self.DeallocateNode(node);
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
return elem;
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////////
|
|
/* ZRingBuffer Containment Specializations */
|
|
/////////////////////////////////////////////
|
|
|
|
//Specialization for ZRingBuffer_ClearImpl containing ZWeakPointer
|
|
template <typename T, typename P, typename A, typename R>
|
|
struct ZRingBuffer_ClearImpl < ZWeakPointer<T, R>, P, A> {
|
|
inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
|
|
{
|
|
// set to null to remove references
|
|
for (size_t i = 0; i < _self.BufferSize; i++)
|
|
_self.At(i) = ZWeakPointer<T, R>(NULL);
|
|
|
|
_self.BufferSize = 0;
|
|
_self.FrontIndex = 0;
|
|
_self.BackIndex = 0;
|
|
}
|
|
inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _newCapacity )
|
|
{
|
|
// set to null to remove references
|
|
for (size_t i = 0; i < _self.BufferSize; i++)
|
|
_self.At(i) = ZWeakPointer<T, R>(NULL);
|
|
|
|
_self.Buffer.Resize(_newCapacity);
|
|
|
|
_self.BufferSize = 0;
|
|
_self.FrontIndex = 0;
|
|
_self.BackIndex = 0;
|
|
}
|
|
};
|
|
|
|
//Specialization for ZRingBuffer_EraseImpl containing ZWeakPointer
|
|
template <typename T, typename P, typename A, typename R>
|
|
struct ZRingBuffer_EraseImpl < ZWeakPointer<T, R>, P, A> {
|
|
inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _index)
|
|
{
|
|
//We are going to do this in a very naive fashion, as this container is not intended for these
|
|
//kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome.
|
|
|
|
_self.AlignBuffer();
|
|
|
|
_self.BufferSize--;
|
|
_self.BackIndex--;
|
|
|
|
// set to null to remove references
|
|
ZWeakPointer<T, R> ret = _self.Buffer.At(_index);
|
|
_self.Buffer.At(_index) = ZWeakPointer<T, R>(NULL);
|
|
return ret;
|
|
|
|
}
|
|
inline static void Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self, size_t _i, size_t _j )
|
|
{
|
|
//We are going to do this in a very naive fashion, as this container is not intended for these
|
|
//kinds of operations anyhow. Anyone who wishes to optimize this at a later date is welcome.
|
|
|
|
size_t count;
|
|
|
|
_self.AlignBuffer();
|
|
|
|
count = (size_t)(_j - _i);
|
|
|
|
_self.BufferSize = _self.BufferSize - count;
|
|
_self.BackIndex = _self.BackIndex - count;
|
|
|
|
// set to null to remove references
|
|
for( size_t i = _i; i < _j; i++)
|
|
_self.Buffer.At(i) = ZWeakPointer<T, R>(NULL);
|
|
|
|
_self.Buffer.Erase(_i, _j);
|
|
}
|
|
};
|
|
|
|
//Specialization for ZRingBuffer_PopBackImpl containing ZWeakPointer
|
|
template <typename T, typename P, typename A, typename R>
|
|
struct ZRingBuffer_PopBackImpl < ZWeakPointer<T, R>, P, A> {
|
|
inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopBack() caused underflow!");
|
|
#endif
|
|
|
|
size_t index = _self.BackIndex;
|
|
|
|
_self.DecrementBack();
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
// set to NULL to fix ref count issues
|
|
ZWeakPointer<T, R> ret = _self.Buffer.At(index);
|
|
_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
//Specialization for ZRingBuffer_PopFrontImpl containing ZWeakPointer
|
|
template <typename T, typename P, typename A, typename R>
|
|
struct ZRingBuffer_PopFrontImpl < ZWeakPointer<T, R>, P, A> {
|
|
inline static T Call( ZRingBuffer< ZWeakPointer<T, R>, P, A>& _self )
|
|
{
|
|
#if !ZSTL_DISABLE_RUNTIME_CHECKS
|
|
ZSTL_ASSERT( _self.BufferSize > 0, "ZRingBuffer::PopFront() caused underflow!");
|
|
#endif
|
|
|
|
size_t index = _self.FrontIndex;
|
|
|
|
_self.IncrementFront();
|
|
|
|
_self.CheckIntegrity();
|
|
|
|
// set to NULL to fix ref count issues
|
|
ZWeakPointer<T, R> ret = _self.Buffer.At(index);
|
|
_self.Buffer.At(index) = ZWeakPointer<T, R>(NULL);
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
|
|
#endif
|