| #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 |