You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
643 lines
16 KiB
643 lines
16 KiB
#ifndef _DESHAREDPTR_HPP
|
|
#define _DESHAREDPTR_HPP
|
|
/*-------------------------------------------------------------------------
|
|
* drawElements C++ Base Library
|
|
* -----------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Shared pointer.
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "deDefs.hpp"
|
|
#include "deAtomic.h"
|
|
|
|
#include <exception>
|
|
#include <algorithm>
|
|
|
|
namespace de
|
|
{
|
|
|
|
//! Shared pointer self-test.
|
|
void SharedPtr_selfTest (void);
|
|
|
|
class DeadReferenceException : public std::exception
|
|
{
|
|
public:
|
|
DeadReferenceException (void) throw()
|
|
: std::exception()
|
|
{
|
|
}
|
|
|
|
const char* what (void) const throw()
|
|
{
|
|
return "DeadReferenceException";
|
|
}
|
|
};
|
|
|
|
struct SharedPtrStateBase
|
|
{
|
|
SharedPtrStateBase (void)
|
|
: strongRefCount (0)
|
|
, weakRefCount (0)
|
|
{
|
|
}
|
|
|
|
virtual ~SharedPtrStateBase (void) throw() {}
|
|
virtual void deletePtr (void) throw() = 0;
|
|
|
|
volatile deInt32 strongRefCount;
|
|
volatile deInt32 weakRefCount; //!< WeakPtr references + StrongPtr references.
|
|
};
|
|
|
|
template<typename Type, typename Deleter>
|
|
struct SharedPtrState : public SharedPtrStateBase
|
|
{
|
|
SharedPtrState (Type* ptr, Deleter deleter)
|
|
: m_ptr (ptr)
|
|
, m_deleter (deleter)
|
|
{
|
|
}
|
|
|
|
virtual ~SharedPtrState (void) throw()
|
|
{
|
|
DE_ASSERT(!m_ptr);
|
|
}
|
|
|
|
virtual void deletePtr (void) throw()
|
|
{
|
|
m_deleter(m_ptr);
|
|
m_ptr = DE_NULL;
|
|
}
|
|
|
|
private:
|
|
Type* m_ptr;
|
|
Deleter m_deleter;
|
|
};
|
|
|
|
template<typename T>
|
|
class SharedPtr;
|
|
|
|
template<typename T>
|
|
class WeakPtr;
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Shared pointer
|
|
*
|
|
* SharedPtr is smart pointer for managing shared ownership to a pointer.
|
|
* Multiple SharedPtrs can maintain ownership to the pointer and it is
|
|
* destructed when last SharedPtr is destroyed.
|
|
*
|
|
* SharedPtr can also be NULL.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
class SharedPtr
|
|
{
|
|
public:
|
|
SharedPtr (void);
|
|
SharedPtr (const SharedPtr<T>& other);
|
|
explicit SharedPtr (T* ptr);
|
|
|
|
template<typename Deleter>
|
|
SharedPtr (T* ptr, Deleter deleter);
|
|
|
|
template<typename Y>
|
|
explicit SharedPtr (const SharedPtr<Y>& other);
|
|
|
|
template<typename Y>
|
|
explicit SharedPtr (const WeakPtr<Y>& other);
|
|
|
|
~SharedPtr (void);
|
|
|
|
template<typename Y>
|
|
SharedPtr& operator= (const SharedPtr<Y>& other);
|
|
SharedPtr& operator= (const SharedPtr<T>& other);
|
|
|
|
template<typename Y>
|
|
SharedPtr& operator= (const WeakPtr<Y>& other);
|
|
|
|
T* get (void) const throw() { return m_ptr; } //!< Get stored pointer.
|
|
T* operator-> (void) const throw() { return m_ptr; } //!< Get stored pointer.
|
|
T& operator* (void) const throw() { return *m_ptr; } //!< De-reference pointer.
|
|
|
|
operator bool (void) const throw() { return !!m_ptr; }
|
|
|
|
void swap (SharedPtr<T>& other);
|
|
|
|
void clear (void);
|
|
|
|
template<typename Y>
|
|
operator SharedPtr<Y> (void) const;
|
|
|
|
private:
|
|
void acquire (void);
|
|
void acquireFromWeak (const WeakPtr<T>& other);
|
|
void release (void);
|
|
|
|
T* m_ptr;
|
|
SharedPtrStateBase* m_state;
|
|
|
|
friend class WeakPtr<T>;
|
|
|
|
template<typename U>
|
|
friend class SharedPtr;
|
|
};
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Weak pointer
|
|
*
|
|
* WeakPtr manages weak references to objects owned by SharedPtr. Shared
|
|
* pointer can be converted to weak pointer and vice versa. Weak pointer
|
|
* differs from SharedPtr by not affecting the lifetime of the managed
|
|
* object.
|
|
*
|
|
* WeakPtr can be converted back to SharedPtr but that operation can fail
|
|
* if the object is no longer live. In such case DeadReferenceException
|
|
* will be thrown.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
class WeakPtr
|
|
{
|
|
public:
|
|
WeakPtr (void);
|
|
WeakPtr (const WeakPtr<T>& other);
|
|
|
|
explicit WeakPtr (const SharedPtr<T>& other);
|
|
~WeakPtr (void);
|
|
|
|
WeakPtr& operator= (const WeakPtr<T>& other);
|
|
WeakPtr& operator= (const SharedPtr<T>& other);
|
|
|
|
SharedPtr<T> lock (void);
|
|
|
|
private:
|
|
void acquire (void);
|
|
void release (void);
|
|
|
|
T* m_ptr;
|
|
SharedPtrStateBase* m_state;
|
|
|
|
friend class SharedPtr<T>;
|
|
};
|
|
|
|
// SharedPtr template implementation.
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct empty shared pointer.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline SharedPtr<T>::SharedPtr (void)
|
|
: m_ptr (DE_NULL)
|
|
, m_state (DE_NULL)
|
|
{
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct shared pointer from pointer.
|
|
* \param ptr Pointer to be managed.
|
|
*
|
|
* Ownership of the pointer will be transferred to SharedPtr and future
|
|
* SharedPtr's initialized or assigned from this SharedPtr.
|
|
*
|
|
* If allocation of shared state fails. The "ptr" argument will not be
|
|
* released.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline SharedPtr<T>::SharedPtr (T* ptr)
|
|
: m_ptr (DE_NULL)
|
|
, m_state (DE_NULL)
|
|
{
|
|
try
|
|
{
|
|
m_ptr = ptr;
|
|
m_state = new SharedPtrState<T, DefaultDeleter<T> >(ptr, DefaultDeleter<T>());
|
|
m_state->strongRefCount = 1;
|
|
m_state->weakRefCount = 1;
|
|
}
|
|
catch (...)
|
|
{
|
|
// \note ptr is not released.
|
|
delete m_state;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct shared pointer from pointer.
|
|
* \param ptr Pointer to be managed.
|
|
*
|
|
* Ownership of the pointer will be transferred to SharedPtr and future
|
|
* SharedPtr's initialized or assigned from this SharedPtr.
|
|
*
|
|
* Deleter must be callable type and deleter is called with the pointer
|
|
* argument when the reference count becomes 0.
|
|
*
|
|
* If allocation of shared state fails. The "ptr" argument will not be
|
|
* released.
|
|
*
|
|
* Calling deleter or calling destructor for deleter should never throw.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
template<typename Deleter>
|
|
inline SharedPtr<T>::SharedPtr (T* ptr, Deleter deleter)
|
|
: m_ptr (DE_NULL)
|
|
, m_state (DE_NULL)
|
|
{
|
|
try
|
|
{
|
|
m_ptr = ptr;
|
|
m_state = new SharedPtrState<T, Deleter>(ptr, deleter);
|
|
m_state->strongRefCount = 1;
|
|
m_state->weakRefCount = 1;
|
|
}
|
|
catch (...)
|
|
{
|
|
// \note ptr is not released.
|
|
delete m_state;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Initialize shared pointer from another SharedPtr.
|
|
* \param other Pointer to be shared.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline SharedPtr<T>::SharedPtr (const SharedPtr<T>& other)
|
|
: m_ptr (other.m_ptr)
|
|
, m_state (other.m_state)
|
|
{
|
|
acquire();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Initialize shared pointer from another SharedPtr.
|
|
* \param other Pointer to be shared.
|
|
*
|
|
* Y* must be convertible to T*.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
template<typename Y>
|
|
inline SharedPtr<T>::SharedPtr (const SharedPtr<Y>& other)
|
|
: m_ptr (other.m_ptr)
|
|
, m_state (other.m_state)
|
|
{
|
|
acquire();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Initialize shared pointer from weak reference.
|
|
* \param other Pointer to be shared.
|
|
*
|
|
* Y* must be convertible to T*.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
template<typename Y>
|
|
inline SharedPtr<T>::SharedPtr (const WeakPtr<Y>& other)
|
|
: m_ptr (DE_NULL)
|
|
, m_state (DE_NULL)
|
|
{
|
|
acquireFromWeak(other);
|
|
}
|
|
|
|
template<typename T>
|
|
inline SharedPtr<T>::~SharedPtr (void)
|
|
{
|
|
release();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Assign from other shared pointer.
|
|
* \param other Pointer to be shared.
|
|
* \return Reference to this SharedPtr.
|
|
*
|
|
* Reference to current pointer is released and reference to new pointer is
|
|
* acquired.
|
|
*
|
|
* Y* must be convertible to T*.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
template<typename Y>
|
|
inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<Y>& other)
|
|
{
|
|
if (m_state == other.m_state)
|
|
return *this;
|
|
|
|
// Release current reference.
|
|
release();
|
|
|
|
// Copy from other and acquire reference.
|
|
m_ptr = other.m_ptr;
|
|
m_state = other.m_state;
|
|
|
|
acquire();
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Assign from other shared pointer.
|
|
* \param other Pointer to be shared.
|
|
* \return Reference to this SharedPtr.
|
|
*
|
|
* Reference to current pointer is released and reference to new pointer is
|
|
* acquired.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<T>& other)
|
|
{
|
|
if (m_state == other.m_state)
|
|
return *this;
|
|
|
|
// Release current reference.
|
|
release();
|
|
|
|
// Copy from other and acquire reference.
|
|
m_ptr = other.m_ptr;
|
|
m_state = other.m_state;
|
|
|
|
acquire();
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Assign from weak pointer.
|
|
* \param other Weak reference.
|
|
* \return Reference to this SharedPtr.
|
|
*
|
|
* Tries to acquire reference to WeakPtr, releases current reference and
|
|
* holds reference to new pointer.
|
|
*
|
|
* If WeakPtr can't be acquired, throws DeadReferenceException and doesn't
|
|
* release the current reference.
|
|
*
|
|
* If WeakPtr references same pointer as SharedPtr this call will always
|
|
* succeed.
|
|
*
|
|
* Y* must be convertible to T*.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
template<typename Y>
|
|
inline SharedPtr<T>& SharedPtr<T>::operator= (const WeakPtr<Y>& other)
|
|
{
|
|
if (m_state == other.m_state)
|
|
return *this;
|
|
|
|
{
|
|
SharedPtr<T> sharedOther(other);
|
|
*this = other;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Type conversion operator.
|
|
*
|
|
* T* must be convertible to Y*.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<class T>
|
|
template<typename Y>
|
|
inline SharedPtr<T>::operator SharedPtr<Y> (void) const
|
|
{
|
|
return SharedPtr<Y>(*this);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Compare pointers.
|
|
* \param a A
|
|
* \param b B
|
|
* \return true if A and B point to same object, false otherwise.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<class T, class U>
|
|
inline bool operator== (const SharedPtr<T>& a, const SharedPtr<U>& b) throw()
|
|
{
|
|
return a.get() == b.get();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Compare pointers.
|
|
* \param a A
|
|
* \param b B
|
|
* \return true if A and B point to different objects, false otherwise.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<class T, class U>
|
|
inline bool operator!= (const SharedPtr<T>& a, const SharedPtr<U>& b) throw()
|
|
{
|
|
return a.get() != b.get();
|
|
}
|
|
|
|
/** Swap pointer contents. */
|
|
template<typename T>
|
|
inline void SharedPtr<T>::swap (SharedPtr<T>& other)
|
|
{
|
|
using std::swap;
|
|
swap(m_ptr, other.m_ptr);
|
|
swap(m_state, other.m_state);
|
|
}
|
|
|
|
/** Swap operator for SharedPtr's. */
|
|
template<typename T>
|
|
inline void swap (SharedPtr<T>& a, SharedPtr<T>& b)
|
|
{
|
|
a.swap(b);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Set pointer to null.
|
|
*
|
|
* clear() removes current reference and sets pointer to null value.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline void SharedPtr<T>::clear (void)
|
|
{
|
|
release();
|
|
m_ptr = DE_NULL;
|
|
m_state = DE_NULL;
|
|
}
|
|
|
|
template<typename T>
|
|
inline void SharedPtr<T>::acquireFromWeak (const WeakPtr<T>& weakRef)
|
|
{
|
|
DE_ASSERT(!m_ptr && !m_state);
|
|
|
|
SharedPtrStateBase* state = weakRef.m_state;
|
|
|
|
if (!state)
|
|
return; // Empty reference.
|
|
|
|
{
|
|
deInt32 oldCount, newCount;
|
|
|
|
// Do atomic compare and increment.
|
|
do
|
|
{
|
|
oldCount = state->strongRefCount;
|
|
if (oldCount == 0)
|
|
throw DeadReferenceException();
|
|
newCount = oldCount+1;
|
|
} while (deAtomicCompareExchange32((deUint32 volatile*)&state->strongRefCount, (deUint32)oldCount, (deUint32)newCount) != (deUint32)oldCount);
|
|
|
|
deAtomicIncrement32(&state->weakRefCount);
|
|
}
|
|
|
|
m_ptr = weakRef.m_ptr;
|
|
m_state = state;
|
|
}
|
|
|
|
template<typename T>
|
|
inline void SharedPtr<T>::acquire (void)
|
|
{
|
|
if (m_state)
|
|
{
|
|
deAtomicIncrement32(&m_state->strongRefCount);
|
|
deAtomicIncrement32(&m_state->weakRefCount);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
inline void SharedPtr<T>::release (void)
|
|
{
|
|
if (m_state)
|
|
{
|
|
if (deAtomicDecrement32(&m_state->strongRefCount) == 0)
|
|
{
|
|
m_ptr = DE_NULL;
|
|
m_state->deletePtr();
|
|
}
|
|
|
|
if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
|
|
{
|
|
delete m_state;
|
|
m_state = DE_NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// WeakPtr template implementation.
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct empty weak pointer.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline WeakPtr<T>::WeakPtr (void)
|
|
: m_ptr (DE_NULL)
|
|
, m_state (DE_NULL)
|
|
{
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct weak pointer from other weak reference.
|
|
* \param other Weak reference.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline WeakPtr<T>::WeakPtr (const WeakPtr<T>& other)
|
|
: m_ptr (other.m_ptr)
|
|
, m_state (other.m_state)
|
|
{
|
|
acquire();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Construct weak pointer from shared pointer.
|
|
* \param other Shared pointer.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline WeakPtr<T>::WeakPtr (const SharedPtr<T>& other)
|
|
: m_ptr (other.m_ptr)
|
|
, m_state (other.m_state)
|
|
{
|
|
acquire();
|
|
}
|
|
|
|
template<typename T>
|
|
inline WeakPtr<T>::~WeakPtr (void)
|
|
{
|
|
release();
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Assign from another weak pointer.
|
|
* \param other Weak reference.
|
|
* \return Reference to this WeakPtr.
|
|
*
|
|
* The current weak reference is removed first and then a new weak reference
|
|
* to the object pointed by other is taken.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline WeakPtr<T>& WeakPtr<T>::operator= (const WeakPtr<T>& other)
|
|
{
|
|
if (this == &other)
|
|
return *this;
|
|
|
|
release();
|
|
|
|
m_ptr = other.m_ptr;
|
|
m_state = other.m_state;
|
|
|
|
acquire();
|
|
|
|
return *this;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*//*!
|
|
* \brief Assign from shared pointer.
|
|
* \param other Shared pointer.
|
|
* \return Reference to this WeakPtr.
|
|
*
|
|
* The current weak reference is removed first and then a new weak reference
|
|
* to the object pointed by other is taken.
|
|
*//*--------------------------------------------------------------------*/
|
|
template<typename T>
|
|
inline WeakPtr<T>& WeakPtr<T>::operator= (const SharedPtr<T>& other)
|
|
{
|
|
release();
|
|
|
|
m_ptr = other.m_ptr;
|
|
m_state = other.m_state;
|
|
|
|
acquire();
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<typename T>
|
|
inline void WeakPtr<T>::acquire (void)
|
|
{
|
|
if (m_state)
|
|
deAtomicIncrement32(&m_state->weakRefCount);
|
|
}
|
|
|
|
template<typename T>
|
|
inline void WeakPtr<T>::release (void)
|
|
{
|
|
if (m_state)
|
|
{
|
|
if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
|
|
{
|
|
delete m_state;
|
|
m_state = DE_NULL;
|
|
m_ptr = DE_NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // de
|
|
|
|
#endif // _DESHAREDPTR_HPP
|