Home | History | Annotate | Download | only in decpp
      1 #ifndef _DESHAREDPTR_HPP
      2 #define _DESHAREDPTR_HPP
      3 /*-------------------------------------------------------------------------
      4  * drawElements C++ Base Library
      5  * -----------------------------
      6  *
      7  * Copyright 2014 The Android Open Source Project
      8  *
      9  * Licensed under the Apache License, Version 2.0 (the "License");
     10  * you may not use this file except in compliance with the License.
     11  * You may obtain a copy of the License at
     12  *
     13  *      http://www.apache.org/licenses/LICENSE-2.0
     14  *
     15  * Unless required by applicable law or agreed to in writing, software
     16  * distributed under the License is distributed on an "AS IS" BASIS,
     17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     18  * See the License for the specific language governing permissions and
     19  * limitations under the License.
     20  *
     21  *//*!
     22  * \file
     23  * \brief Shared pointer.
     24  *//*--------------------------------------------------------------------*/
     25 
     26 #include "deDefs.hpp"
     27 #include "deAtomic.h"
     28 
     29 #include <exception>
     30 #include <algorithm>
     31 
     32 namespace de
     33 {
     34 
     35 //! Shared pointer self-test.
     36 void SharedPtr_selfTest (void);
     37 
     38 class DeadReferenceException : public std::exception
     39 {
     40 public:
     41 				DeadReferenceException	(void) throw()
     42 		: std::exception()
     43 	{
     44 	}
     45 
     46 	const char*	what					(void) const throw()
     47 	{
     48 		return "DeadReferenceException";
     49 	}
     50 };
     51 
     52 struct SharedPtrStateBase
     53 {
     54 	SharedPtrStateBase (void)
     55 		: strongRefCount	(0)
     56 		, weakRefCount		(0)
     57 	{
     58 	}
     59 
     60 	virtual				~SharedPtrStateBase	(void) throw() {}
     61 	virtual void		deletePtr			(void) throw() = 0;
     62 
     63 	volatile deInt32	strongRefCount;
     64 	volatile deInt32	weakRefCount;		//!< WeakPtr references + StrongPtr references.
     65 };
     66 
     67 template<typename Type, typename Deleter>
     68 struct SharedPtrState : public SharedPtrStateBase
     69 {
     70 	SharedPtrState (Type* ptr, Deleter deleter)
     71 		: m_ptr		(ptr)
     72 		, m_deleter	(deleter)
     73 	{
     74 	}
     75 
     76 	virtual ~SharedPtrState (void) throw()
     77 	{
     78 		DE_ASSERT(!m_ptr);
     79 	}
     80 
     81 	virtual void deletePtr (void) throw()
     82 	{
     83 		m_deleter(m_ptr);
     84 		m_ptr = DE_NULL;
     85 	}
     86 
     87 private:
     88 	Type*		m_ptr;
     89 	Deleter		m_deleter;
     90 };
     91 
     92 template<typename T>
     93 class SharedPtr;
     94 
     95 template<typename T>
     96 class WeakPtr;
     97 
     98 /*--------------------------------------------------------------------*//*!
     99  * \brief Shared pointer
    100  *
    101  * SharedPtr is smart pointer for managing shared ownership to a pointer.
    102  * Multiple SharedPtrs can maintain ownership to the pointer and it is
    103  * destructed when last SharedPtr is destroyed.
    104  *
    105  * SharedPtr can also be NULL.
    106  *//*--------------------------------------------------------------------*/
    107 template<typename T>
    108 class SharedPtr
    109 {
    110 public:
    111 								SharedPtr			(void);
    112 								SharedPtr			(const SharedPtr<T>& other);
    113 	explicit					SharedPtr			(T* ptr);
    114 
    115 	template<typename Deleter>
    116 								SharedPtr			(T* ptr, Deleter deleter);
    117 
    118 	template<typename Y>
    119 	explicit					SharedPtr			(const SharedPtr<Y>& other);
    120 
    121 	template<typename Y>
    122 	explicit					SharedPtr			(const WeakPtr<Y>& other);
    123 
    124 								~SharedPtr			(void);
    125 
    126 	template<typename Y>
    127 	SharedPtr&					operator=			(const SharedPtr<Y>& other);
    128 	SharedPtr&					operator=			(const SharedPtr<T>& other);
    129 
    130 	template<typename Y>
    131 	SharedPtr&					operator=			(const WeakPtr<Y>& other);
    132 
    133 	T*							get					(void) const throw() { return m_ptr;	}	//!< Get stored pointer.
    134 	T*							operator->			(void) const throw() { return m_ptr;	}	//!< Get stored pointer.
    135 	T&							operator*			(void) const throw() { return *m_ptr;	}	//!< De-reference pointer.
    136 
    137 	operator					bool				(void) const throw() { return !!m_ptr;	}
    138 
    139 	void						swap				(SharedPtr<T>& other);
    140 
    141 	void						clear				(void);
    142 
    143 	template<typename Y>
    144 	operator SharedPtr<Y>		(void) const;
    145 
    146 private:
    147 	void						acquire				(void);
    148 	void						acquireFromWeak		(const WeakPtr<T>& other);
    149 	void						release				(void);
    150 
    151 	T*							m_ptr;
    152 	SharedPtrStateBase*			m_state;
    153 
    154 	friend class WeakPtr<T>;
    155 
    156 	template<typename U>
    157 	friend class SharedPtr;
    158 };
    159 
    160 /*--------------------------------------------------------------------*//*!
    161  * \brief Weak pointer
    162  *
    163  * WeakPtr manages weak references to objects owned by SharedPtr. Shared
    164  * pointer can be converted to weak pointer and vice versa. Weak pointer
    165  * differs from SharedPtr by not affecting the lifetime of the managed
    166  * object.
    167  *
    168  * WeakPtr can be converted back to SharedPtr but that operation can fail
    169  * if the object is no longer live. In such case DeadReferenceException
    170  * will be thrown.
    171  *//*--------------------------------------------------------------------*/
    172 template<typename T>
    173 class WeakPtr
    174 {
    175 public:
    176 						WeakPtr		(void);
    177 						WeakPtr		(const WeakPtr<T>& other);
    178 
    179 	explicit			WeakPtr		(const SharedPtr<T>& other);
    180 						~WeakPtr	(void);
    181 
    182 	WeakPtr&			operator=	(const WeakPtr<T>& other);
    183 	WeakPtr&			operator=	(const SharedPtr<T>& other);
    184 
    185 	SharedPtr<T>		lock		(void);
    186 
    187 private:
    188 	void				acquire		(void);
    189 	void				release		(void);
    190 
    191 	T*					m_ptr;
    192 	SharedPtrStateBase*	m_state;
    193 
    194 	friend class SharedPtr<T>;
    195 };
    196 
    197 // SharedPtr template implementation.
    198 
    199 /*--------------------------------------------------------------------*//*!
    200  * \brief Construct empty shared pointer.
    201  *//*--------------------------------------------------------------------*/
    202 template<typename T>
    203 inline SharedPtr<T>::SharedPtr (void)
    204 	: m_ptr		(DE_NULL)
    205 	, m_state	(DE_NULL)
    206 {
    207 }
    208 
    209 /*--------------------------------------------------------------------*//*!
    210  * \brief Construct shared pointer from pointer.
    211  * \param ptr Pointer to be managed.
    212  *
    213  * Ownership of the pointer will be transferred to SharedPtr and future
    214  * SharedPtr's initialized or assigned from this SharedPtr.
    215  *
    216  * If allocation of shared state fails. The "ptr" argument will not be
    217  * released.
    218  *//*--------------------------------------------------------------------*/
    219 template<typename T>
    220 inline SharedPtr<T>::SharedPtr (T* ptr)
    221 	: m_ptr		(DE_NULL)
    222 	, m_state	(DE_NULL)
    223 {
    224 	try
    225 	{
    226 		m_ptr	= ptr;
    227 		m_state	= new SharedPtrState<T, DefaultDeleter<T> >(ptr, DefaultDeleter<T>());
    228 		m_state->strongRefCount	= 1;
    229 		m_state->weakRefCount	= 1;
    230 	}
    231 	catch (...)
    232 	{
    233 		// \note ptr is not released.
    234 		delete m_state;
    235 		throw;
    236 	}
    237 }
    238 
    239 /*--------------------------------------------------------------------*//*!
    240  * \brief Construct shared pointer from pointer.
    241  * \param ptr Pointer to be managed.
    242  *
    243  * Ownership of the pointer will be transferred to SharedPtr and future
    244  * SharedPtr's initialized or assigned from this SharedPtr.
    245  *
    246  * Deleter must be callable type and deleter is called with the pointer
    247  * argument when the reference count becomes 0.
    248  *
    249  * If allocation of shared state fails. The "ptr" argument will not be
    250  * released.
    251  *
    252  * Calling deleter or calling destructor for deleter should never throw.
    253  *//*--------------------------------------------------------------------*/
    254 template<typename T>
    255 template<typename Deleter>
    256 inline SharedPtr<T>::SharedPtr (T* ptr, Deleter deleter)
    257 	: m_ptr		(DE_NULL)
    258 	, m_state	(DE_NULL)
    259 {
    260 	try
    261 	{
    262 		m_ptr	= ptr;
    263 		m_state	= new SharedPtrState<T, Deleter>(ptr, deleter);
    264 		m_state->strongRefCount	= 1;
    265 		m_state->weakRefCount	= 1;
    266 	}
    267 	catch (...)
    268 	{
    269 		// \note ptr is not released.
    270 		delete m_state;
    271 		throw;
    272 	}
    273 }
    274 
    275 /*--------------------------------------------------------------------*//*!
    276  * \brief Initialize shared pointer from another SharedPtr.
    277  * \param other Pointer to be shared.
    278  *//*--------------------------------------------------------------------*/
    279 template<typename T>
    280 inline SharedPtr<T>::SharedPtr (const SharedPtr<T>& other)
    281 	: m_ptr		(other.m_ptr)
    282 	, m_state	(other.m_state)
    283 {
    284 	acquire();
    285 }
    286 
    287 /*--------------------------------------------------------------------*//*!
    288  * \brief Initialize shared pointer from another SharedPtr.
    289  * \param other Pointer to be shared.
    290  *
    291  * Y* must be convertible to T*.
    292  *//*--------------------------------------------------------------------*/
    293 template<typename T>
    294 template<typename Y>
    295 inline SharedPtr<T>::SharedPtr (const SharedPtr<Y>& other)
    296 	: m_ptr		(other.m_ptr)
    297 	, m_state	(other.m_state)
    298 {
    299 	acquire();
    300 }
    301 
    302 /*--------------------------------------------------------------------*//*!
    303  * \brief Initialize shared pointer from weak reference.
    304  * \param other Pointer to be shared.
    305  *
    306  * Y* must be convertible to T*.
    307  *//*--------------------------------------------------------------------*/
    308 template<typename T>
    309 template<typename Y>
    310 inline SharedPtr<T>::SharedPtr (const WeakPtr<Y>& other)
    311 	: m_ptr		(DE_NULL)
    312 	, m_state	(DE_NULL)
    313 {
    314 	acquireFromWeak(other);
    315 }
    316 
    317 template<typename T>
    318 inline SharedPtr<T>::~SharedPtr (void)
    319 {
    320 	release();
    321 }
    322 
    323 /*--------------------------------------------------------------------*//*!
    324  * \brief Assign from other shared pointer.
    325  * \param other Pointer to be shared.
    326  * \return Reference to this SharedPtr.
    327  *
    328  * Reference to current pointer is released and reference to new pointer is
    329  * acquired.
    330  *
    331  * Y* must be convertible to T*.
    332  *//*--------------------------------------------------------------------*/
    333 template<typename T>
    334 template<typename Y>
    335 inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<Y>& other)
    336 {
    337 	if (m_state == other.m_state)
    338 		return *this;
    339 
    340 	// Release current reference.
    341 	release();
    342 
    343 	// Copy from other and acquire reference.
    344 	m_ptr	= other.m_ptr;
    345 	m_state	= other.m_state;
    346 
    347 	acquire();
    348 
    349 	return *this;
    350 }
    351 
    352 /*--------------------------------------------------------------------*//*!
    353  * \brief Assign from other shared pointer.
    354  * \param other Pointer to be shared.
    355  * \return Reference to this SharedPtr.
    356  *
    357  * Reference to current pointer is released and reference to new pointer is
    358  * acquired.
    359  *//*--------------------------------------------------------------------*/
    360 template<typename T>
    361 inline SharedPtr<T>& SharedPtr<T>::operator= (const SharedPtr<T>& other)
    362 {
    363 	if (m_state == other.m_state)
    364 		return *this;
    365 
    366 	// Release current reference.
    367 	release();
    368 
    369 	// Copy from other and acquire reference.
    370 	m_ptr	= other.m_ptr;
    371 	m_state	= other.m_state;
    372 
    373 	acquire();
    374 
    375 	return *this;
    376 }
    377 
    378 /*--------------------------------------------------------------------*//*!
    379  * \brief Assign from weak pointer.
    380  * \param other Weak reference.
    381  * \return Reference to this SharedPtr.
    382  *
    383  * Tries to acquire reference to WeakPtr, releases current reference and
    384  * holds reference to new pointer.
    385  *
    386  * If WeakPtr can't be acquired, throws DeadReferenceException and doesn't
    387  * release the current reference.
    388  *
    389  * If WeakPtr references same pointer as SharedPtr this call will always
    390  * succeed.
    391  *
    392  * Y* must be convertible to T*.
    393  *//*--------------------------------------------------------------------*/
    394 template<typename T>
    395 template<typename Y>
    396 inline SharedPtr<T>& SharedPtr<T>::operator= (const WeakPtr<Y>& other)
    397 {
    398 	if (m_state == other.m_state)
    399 		return *this;
    400 
    401 	{
    402 		SharedPtr<T> sharedOther(other);
    403 		*this = other;
    404 	}
    405 
    406 	return *this;
    407 }
    408 
    409 /*--------------------------------------------------------------------*//*!
    410  * \brief Type conversion operator.
    411  *
    412  * T* must be convertible to Y*.
    413  *//*--------------------------------------------------------------------*/
    414 template<class T>
    415 template<typename Y>
    416 inline SharedPtr<T>::operator SharedPtr<Y> (void) const
    417 {
    418 	return SharedPtr<Y>(*this);
    419 }
    420 
    421 /*--------------------------------------------------------------------*//*!
    422  * \brief Compare pointers.
    423  * \param a A
    424  * \param b B
    425  * \return true if A and B point to same object, false otherwise.
    426  *//*--------------------------------------------------------------------*/
    427 template<class T, class U>
    428 inline bool operator== (const SharedPtr<T>& a, const SharedPtr<U>& b) throw()
    429 {
    430 	return a.get() == b.get();
    431 }
    432 
    433 /*--------------------------------------------------------------------*//*!
    434  * \brief Compare pointers.
    435  * \param a A
    436  * \param b B
    437  * \return true if A and B point to different objects, false otherwise.
    438  *//*--------------------------------------------------------------------*/
    439 template<class T, class U>
    440 inline bool operator!= (const SharedPtr<T>& a, const SharedPtr<U>& b) throw()
    441 {
    442 	return a.get() != b.get();
    443 }
    444 
    445 /** Swap pointer contents. */
    446 template<typename T>
    447 inline void SharedPtr<T>::swap (SharedPtr<T>& other)
    448 {
    449 	using std::swap;
    450 	swap(m_ptr,		other.m_ptr);
    451 	swap(m_state,	other.m_state);
    452 }
    453 
    454 /** Swap operator for SharedPtr's. */
    455 template<typename T>
    456 inline void swap (SharedPtr<T>& a, SharedPtr<T>& b)
    457 {
    458 	a.swap(b);
    459 }
    460 
    461 /*--------------------------------------------------------------------*//*!
    462  * \brief Set pointer to null.
    463  *
    464  * clear() removes current reference and sets pointer to null value.
    465  *//*--------------------------------------------------------------------*/
    466 template<typename T>
    467 inline void SharedPtr<T>::clear (void)
    468 {
    469 	release();
    470 	m_ptr	= DE_NULL;
    471 	m_state	= DE_NULL;
    472 }
    473 
    474 template<typename T>
    475 inline void SharedPtr<T>::acquireFromWeak (const WeakPtr<T>& weakRef)
    476 {
    477 	DE_ASSERT(!m_ptr && !m_state);
    478 
    479 	SharedPtrStateBase* state = weakRef.m_state;
    480 
    481 	if (!state)
    482 		return; // Empty reference.
    483 
    484 	{
    485 		deInt32 oldCount, newCount;
    486 
    487 		// Do atomic compare and increment.
    488 		do
    489 		{
    490 			oldCount = state->strongRefCount;
    491 			if (oldCount == 0)
    492 				throw DeadReferenceException();
    493 			newCount = oldCount+1;
    494 		} while (deAtomicCompareExchange32((deUint32 volatile*)&state->strongRefCount, (deUint32)oldCount, (deUint32)newCount) != (deUint32)oldCount);
    495 
    496 		deAtomicIncrement32(&state->weakRefCount);
    497 	}
    498 
    499 	m_ptr	= weakRef.m_ptr;
    500 	m_state	= state;
    501 }
    502 
    503 template<typename T>
    504 inline void SharedPtr<T>::acquire (void)
    505 {
    506 	if (m_state)
    507 	{
    508 		deAtomicIncrement32(&m_state->strongRefCount);
    509 		deAtomicIncrement32(&m_state->weakRefCount);
    510 	}
    511 }
    512 
    513 template<typename T>
    514 inline void SharedPtr<T>::release (void)
    515 {
    516 	if (m_state)
    517 	{
    518 		if (deAtomicDecrement32(&m_state->strongRefCount) == 0)
    519 		{
    520 			m_ptr = DE_NULL;
    521 			m_state->deletePtr();
    522 		}
    523 
    524 		if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
    525 		{
    526 			delete m_state;
    527 			m_state = DE_NULL;
    528 		}
    529 	}
    530 }
    531 
    532 // WeakPtr template implementation.
    533 
    534 /*--------------------------------------------------------------------*//*!
    535  * \brief Construct empty weak pointer.
    536  *//*--------------------------------------------------------------------*/
    537 template<typename T>
    538 inline WeakPtr<T>::WeakPtr (void)
    539 	: m_ptr		(DE_NULL)
    540 	, m_state	(DE_NULL)
    541 {
    542 }
    543 
    544 /*--------------------------------------------------------------------*//*!
    545  * \brief Construct weak pointer from other weak reference.
    546  * \param other Weak reference.
    547  *//*--------------------------------------------------------------------*/
    548 template<typename T>
    549 inline WeakPtr<T>::WeakPtr (const WeakPtr<T>& other)
    550 	: m_ptr		(other.m_ptr)
    551 	, m_state	(other.m_state)
    552 {
    553 	acquire();
    554 }
    555 
    556 /*--------------------------------------------------------------------*//*!
    557  * \brief Construct weak pointer from shared pointer.
    558  * \param other Shared pointer.
    559  *//*--------------------------------------------------------------------*/
    560 template<typename T>
    561 inline WeakPtr<T>::WeakPtr (const SharedPtr<T>& other)
    562 	: m_ptr		(other.m_ptr)
    563 	, m_state	(other.m_state)
    564 {
    565 	acquire();
    566 }
    567 
    568 template<typename T>
    569 inline WeakPtr<T>::~WeakPtr (void)
    570 {
    571 	release();
    572 }
    573 
    574 /*--------------------------------------------------------------------*//*!
    575  * \brief Assign from another weak pointer.
    576  * \param other Weak reference.
    577  * \return Reference to this WeakPtr.
    578  *
    579  * The current weak reference is removed first and then a new weak reference
    580  * to the object pointed by other is taken.
    581  *//*--------------------------------------------------------------------*/
    582 template<typename T>
    583 inline WeakPtr<T>& WeakPtr<T>::operator= (const WeakPtr<T>& other)
    584 {
    585 	if (this == &other)
    586 		return *this;
    587 
    588 	release();
    589 
    590 	m_ptr	= other.m_ptr;
    591 	m_state	= other.m_state;
    592 
    593 	acquire();
    594 
    595 	return *this;
    596 }
    597 
    598 /*--------------------------------------------------------------------*//*!
    599  * \brief Assign from shared pointer.
    600  * \param other Shared pointer.
    601  * \return Reference to this WeakPtr.
    602  *
    603  * The current weak reference is removed first and then a new weak reference
    604  * to the object pointed by other is taken.
    605  *//*--------------------------------------------------------------------*/
    606 template<typename T>
    607 inline WeakPtr<T>& WeakPtr<T>::operator= (const SharedPtr<T>& other)
    608 {
    609 	release();
    610 
    611 	m_ptr	= other.m_ptr;
    612 	m_state	= other.m_state;
    613 
    614 	acquire();
    615 
    616 	return *this;
    617 }
    618 
    619 template<typename T>
    620 inline void WeakPtr<T>::acquire (void)
    621 {
    622 	if (m_state)
    623 		deAtomicIncrement32(&m_state->weakRefCount);
    624 }
    625 
    626 template<typename T>
    627 inline void WeakPtr<T>::release (void)
    628 {
    629 	if (m_state)
    630 	{
    631 		if (deAtomicDecrement32(&m_state->weakRefCount) == 0)
    632 		{
    633 			delete m_state;
    634 			m_state	= DE_NULL;
    635 			m_ptr	= DE_NULL;
    636 		}
    637 	}
    638 }
    639 
    640 } // de
    641 
    642 #endif // _DESHAREDPTR_HPP
    643