blob: c6b5c93788a590c886d528e375cc131d63fdadbc [file] [log] [blame]
#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"; }
};
template<bool threadSafe>
struct ReferenceCount;
template<> struct ReferenceCount<true> { typedef volatile int Type; };
template<> struct ReferenceCount<false> { typedef int Type; };
template<class Deleter, bool threadSafe>
struct SharedPtrState
{
SharedPtrState (Deleter deleter_)
: strongRefCount (0)
, weakRefCount (0)
, deleter (deleter_)
{
}
typename ReferenceCount<threadSafe>::Type strongRefCount;
typename ReferenceCount<threadSafe>::Type weakRefCount; //!< WeakPtr references + StrongPtr references.
Deleter deleter;
};
template<typename DstDeleterType, typename SrcDeleterType, bool threadSafe>
SharedPtrState<DstDeleterType, threadSafe>* sharedPtrStateCast (SharedPtrState<SrcDeleterType, threadSafe>* state)
{
return reinterpret_cast<SharedPtrState<DstDeleterType, threadSafe>*>(state);
}
template<typename T, class Deleter, bool threadSafe>
class SharedPtr;
template<typename T, class Deleter, bool threadSafe>
class WeakPtr;
/*--------------------------------------------------------------------*//*!
* \brief Shared pointer
*
* SharedPtr is smart pointer for managing shared ownership to a pointer.
* Multiple SharedPtr's can maintain ownership to the pointer and it is
* destructed when last SharedPtr is destroyed.
*
* Shared pointers can be assigned (or initialized using copy constructor)
* and in such case the previous reference is first freed and then a new
* reference to the new pointer is acquired.
*
* SharedPtr can also be empty.
*
* If threadSafe template parameter is set to true, it is safe to share
* data using SharedPtr across threads. SharedPtr object itself is not
* thread safe and should not be mutated from multiple threads simultaneously.
*
* \todo [2012-10-26 pyry] Add custom deleter.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter = DefaultDeleter<T>, bool threadSafe = true>
class SharedPtr
{
public:
SharedPtr (void);
SharedPtr (const SharedPtr<T, Deleter, threadSafe>& other);
template<typename Y>
explicit SharedPtr (Y* ptr, Deleter deleter = Deleter());
template<typename Y, class DeleterY>
explicit SharedPtr (const SharedPtr<Y, DeleterY, threadSafe>& other);
template<typename Y, class DeleterY>
explicit SharedPtr (const WeakPtr<Y, DeleterY, threadSafe>& other);
~SharedPtr (void);
template<typename Y, class DeleterY>
SharedPtr& operator= (const SharedPtr<Y, DeleterY, threadSafe>& other);
SharedPtr& operator= (const SharedPtr<T, Deleter, threadSafe>& other);
template<typename Y, class DeleterY>
SharedPtr& operator= (const WeakPtr<Y, DeleterY, threadSafe>& 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, Deleter, threadSafe>& other);
void clear (void);
template<typename Y, class DeleterY>
operator SharedPtr<Y, DeleterY, threadSafe> (void) const;
private:
void acquire (void);
void acquireFromWeak (const WeakPtr<T, Deleter, threadSafe>& other);
void release (void);
T* m_ptr;
SharedPtrState<Deleter, threadSafe>* m_state;
friend class WeakPtr<T, Deleter, threadSafe>;
template<typename U, class DeleterU, bool threadSafeU>
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.
*
* \todo [2012-10-26 pyry] Add custom deleter.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter = DefaultDeleter<T>, bool threadSafe = true>
class WeakPtr
{
public:
WeakPtr (void);
WeakPtr (const WeakPtr<T, Deleter, threadSafe>& other);
explicit WeakPtr (const SharedPtr<T, Deleter, threadSafe>& other);
~WeakPtr (void);
WeakPtr& operator= (const WeakPtr<T, Deleter, threadSafe>& other);
WeakPtr& operator= (const SharedPtr<T, Deleter, threadSafe>& other);
SharedPtr<T, Deleter, threadSafe> lock (void);
private:
void acquire (void);
void release (void);
T* m_ptr;
SharedPtrState<Deleter, threadSafe>* m_state;
friend class SharedPtr<T, Deleter, threadSafe>;
};
// SharedPtr template implementation.
/*--------------------------------------------------------------------*//*!
* \brief Construct empty shared pointer.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
inline SharedPtr<T, Deleter, threadSafe>::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.
*
* Y* must be convertible to T*.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
template<typename Y>
inline SharedPtr<T, Deleter, threadSafe>::SharedPtr (Y* ptr, Deleter deleter)
: m_ptr (DE_NULL)
, m_state (DE_NULL)
{
try
{
m_ptr = ptr;
m_state = new SharedPtrState<Deleter, threadSafe>(deleter);
m_state->strongRefCount = 1;
m_state->weakRefCount = 1;
}
catch (...)
{
delete m_ptr;
delete m_state;
throw;
}
}
/*--------------------------------------------------------------------*//*!
* \brief Initialize shared pointer from another SharedPtr.
* \param other Pointer to be shared.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
inline SharedPtr<T, Deleter, threadSafe>::SharedPtr (const SharedPtr<T, Deleter, threadSafe>& 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, class Deleter, bool threadSafe>
template<typename Y, class DeleterY>
inline SharedPtr<T, Deleter, threadSafe>::SharedPtr (const SharedPtr<Y, DeleterY, threadSafe>& other)
: m_ptr (other.m_ptr)
, m_state (sharedPtrStateCast<Deleter>(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, class Deleter, bool threadSafe>
template<typename Y, class DeleterY>
inline SharedPtr<T, Deleter, threadSafe>::SharedPtr (const WeakPtr<Y, DeleterY, threadSafe>& other)
: m_ptr (DE_NULL)
, m_state (DE_NULL)
{
acquireFromWeak(other);
}
template<typename T, class Deleter, bool threadSafe>
inline SharedPtr<T, Deleter, threadSafe>::~SharedPtr (void)
{
release();
}
/*--------------------------------------------------------------------*//*!
* \brief Assign from other shared pointer.
* \param other Pointer to be shared.
* \return Reference to this SharedPtr.
*
* Reference to current pointer (if any) will be released first. Then a new
* reference to the pointer managed by other will be acquired.
*
* Y* must be convertible to T*.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
template<typename Y, class DeleterY>
inline SharedPtr<T, Deleter, threadSafe>& SharedPtr<T, Deleter, threadSafe>::operator= (const SharedPtr<Y, DeleterY, threadSafe>& other)
{
if (*this == other)
return *this;
// Release current reference.
release();
// Copy from other and acquire reference.
m_ptr = other.m_ptr;
m_state = sharedPtrStateCast<Deleter>(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 (if any) will be released first. Then a new
* reference to the pointer managed by other will be acquired.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
inline SharedPtr<T, Deleter, threadSafe>& SharedPtr<T, Deleter, threadSafe>::operator= (const SharedPtr<T, Deleter, threadSafe>& other)
{
if (*this == other)
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.
*
* Reference to current pointer (if any) will be released first. Then a
* reference to pointer managed by WeakPtr is acquired if the pointer
* is still live (eg. there's at least one strong reference).
*
* If pointer is no longer live, DeadReferenceException is thrown.
*
* Y* must be convertible to T*.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
template<typename Y, class DeleterY>
inline SharedPtr<T, Deleter, threadSafe>& SharedPtr<T, Deleter, threadSafe>::operator= (const WeakPtr<Y, DeleterY, threadSafe>& other)
{
// Release current reference.
release();
m_ptr = DE_NULL;
m_state = DE_NULL;
acquireFromWeak(other);
return *this;
}
/*--------------------------------------------------------------------*//*!
* \brief Type conversion operator.
*
* T* must be convertible to Y*. Since resulting SharedPtr will share the
* ownership destroying Y* must be equal to destroying T*.
*//*--------------------------------------------------------------------*/
template<class T, class Deleter, bool threadSafe>
template<typename Y, class DeleterY>
inline SharedPtr<T, Deleter, threadSafe>::operator SharedPtr<Y, DeleterY, threadSafe> (void) const
{
return SharedPtr<Y, DeleterY, threadSafe>(*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 DeleterT, bool threadSafeT, class U, class DeleterU, bool threadSafeU>
inline bool operator== (const SharedPtr<T, DeleterT, threadSafeT>& a, const SharedPtr<U, DeleterU, threadSafeU>& 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 DeleterT, bool threadSafeT, class U, class DeleterU, bool threadSafeU>
inline bool operator!= (const SharedPtr<T, DeleterT, threadSafeT>& a, const SharedPtr<U, DeleterU, threadSafeU>& b) throw()
{
return a.get() != b.get();
}
/** Swap pointer contents. */
template<typename T, class Deleter, bool threadSafe>
inline void SharedPtr<T, Deleter, threadSafe>::swap (SharedPtr<T, Deleter, threadSafe>& other)
{
using std::swap;
swap(m_ptr, other.m_ptr);
swap(m_state, other.m_state);
}
/** Swap operator for SharedPtr's. */
template<typename T, class Deleter, bool threadSafe>
inline void swap (SharedPtr<T, Deleter, threadSafe>& a, SharedPtr<T, Deleter, threadSafe>& b)
{
a.swap(b);
}
/*--------------------------------------------------------------------*//*!
* \brief Set pointer to null.
*
* clear() removes current reference and sets pointer to null value.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
inline void SharedPtr<T, Deleter, threadSafe>::clear (void)
{
release();
m_ptr = DE_NULL;
m_state = DE_NULL;
}
template<typename T, class Deleter, bool threadSafe>
inline void SharedPtr<T, Deleter, threadSafe>::acquireFromWeak (const WeakPtr<T, Deleter, threadSafe>& weakRef)
{
DE_ASSERT(!m_ptr && !m_state);
SharedPtrState<Deleter, threadSafe>* state = weakRef.m_state;
if (!state)
return; // Empty reference.
if (threadSafe)
{
int 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);
}
else
{
if (state->strongRefCount == 0)
throw DeadReferenceException();
state->strongRefCount += 1;
state->weakRefCount += 1;
}
m_ptr = weakRef.m_ptr;
m_state = state;
}
template<typename T, class Deleter, bool threadSafe>
inline void SharedPtr<T, Deleter, threadSafe>::acquire (void)
{
if (m_state)
{
if (threadSafe)
{
deAtomicIncrement32((deInt32 volatile*)&m_state->strongRefCount);
deAtomicIncrement32((deInt32 volatile*)&m_state->weakRefCount);
}
else
{
m_state->strongRefCount += 1;
m_state->weakRefCount += 1;
}
}
}
template<typename T, class Deleter, bool threadSafe>
inline void SharedPtr<T, Deleter, threadSafe>::release (void)
{
if (m_state)
{
if (threadSafe)
{
if (deAtomicDecrement32(&m_state->strongRefCount) == 0)
{
m_state->deleter(m_ptr);
m_ptr = DE_NULL;
}
if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
{
delete m_state;
m_state = DE_NULL;
}
}
else
{
m_state->strongRefCount -= 1;
m_state->weakRefCount -= 1;
DE_ASSERT(m_state->strongRefCount >= 0 && m_state->weakRefCount >= 0);
if (m_state->strongRefCount == 0)
{
m_state->deleter(m_ptr);
m_ptr = DE_NULL;
}
if (m_state->weakRefCount == 0)
{
delete m_state;
m_state = DE_NULL;
}
}
}
}
// WeakPtr template implementation.
/*--------------------------------------------------------------------*//*!
* \brief Construct empty weak pointer.
*//*--------------------------------------------------------------------*/
template<typename T, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>::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, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>::WeakPtr (const WeakPtr<T, Deleter, threadSafe>& 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, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>::WeakPtr (const SharedPtr<T, Deleter, threadSafe>& other)
: m_ptr (other.m_ptr)
, m_state (other.m_state)
{
acquire();
}
template<typename T, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>::~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, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>& WeakPtr<T, Deleter, threadSafe>::operator= (const WeakPtr<T, Deleter, threadSafe>& 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, class Deleter, bool threadSafe>
inline WeakPtr<T, Deleter, threadSafe>& WeakPtr<T, Deleter, threadSafe>::operator= (const SharedPtr<T, Deleter, threadSafe>& other)
{
release();
m_ptr = other.m_ptr;
m_state = other.m_state;
acquire();
return *this;
}
template<typename T, class Deleter, bool threadSafe>
inline void WeakPtr<T, Deleter, threadSafe>::acquire (void)
{
if (m_state)
{
if (threadSafe)
deAtomicIncrement32(&m_state->weakRefCount);
else
m_state->weakRefCount += 1;
}
}
template<typename T, class Deleter, bool threadSafe>
inline void WeakPtr<T, Deleter, threadSafe>::release (void)
{
if (m_state)
{
if (threadSafe)
{
if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
{
delete m_state;
m_state = DE_NULL;
m_ptr = DE_NULL;
}
}
else
{
m_state->weakRefCount -= 1;
DE_ASSERT(m_state->weakRefCount >= 0);
if (m_state->weakRefCount == 0)
{
delete m_state;
m_state = DE_NULL;
m_ptr = DE_NULL;
}
}
}
}
} // de
#endif // _DESHAREDPTR_HPP