• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
DeadReferenceException(void)41 				DeadReferenceException	(void) throw()
42 		: std::exception()
43 	{
44 	}
45 
what(void) const46 	const char*	what					(void) const throw()
47 	{
48 		return "DeadReferenceException";
49 	}
50 };
51 
52 struct SharedPtrStateBase
53 {
SharedPtrStateBasede::SharedPtrStateBase54 	SharedPtrStateBase (void)
55 		: strongRefCount	(0)
56 		, weakRefCount		(0)
57 	{
58 	}
59 
~SharedPtrStateBasede::SharedPtrStateBase60 	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 {
SharedPtrStatede::SharedPtrState70 	SharedPtrState (Type* ptr, Deleter deleter)
71 		: m_ptr		(ptr)
72 		, m_deleter	(deleter)
73 	{
74 	}
75 
~SharedPtrStatede::SharedPtrState76 	virtual ~SharedPtrState (void) throw()
77 	{
78 		DE_ASSERT(!m_ptr);
79 	}
80 
deletePtrde::SharedPtrState81 	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 
get(void) const133 	T*							get					(void) const throw() { return m_ptr;	}	//!< Get stored pointer.
operator ->(void) const134 	T*							operator->			(void) const throw() { return m_ptr;	}	//!< Get stored pointer.
operator *(void) const135 	T&							operator*			(void) const throw() { return *m_ptr;	}	//!< De-reference pointer.
136 
operator bool(void) const137 	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>
SharedPtr(void)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>
SharedPtr(T * ptr)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>
SharedPtr(T * ptr,Deleter 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>
SharedPtr(const SharedPtr<T> & other)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>
SharedPtr(const SharedPtr<Y> & other)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>
SharedPtr(const WeakPtr<Y> & other)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>
~SharedPtr(void)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>
operator =(const SharedPtr<Y> & other)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>
operator =(const SharedPtr<T> & other)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>
operator =(const WeakPtr<Y> & other)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>
operator SharedPtr<Y>(void) const416 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>
operator ==(const SharedPtr<T> & a,const SharedPtr<U> & b)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>
operator !=(const SharedPtr<T> & a,const SharedPtr<U> & b)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>
swap(SharedPtr<T> & other)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>
swap(SharedPtr<T> & a,SharedPtr<T> & b)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>
clear(void)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>
acquireFromWeak(const WeakPtr<T> & weakRef)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>
acquire(void)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>
release(void)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>
WeakPtr(void)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>
WeakPtr(const WeakPtr<T> & other)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>
WeakPtr(const SharedPtr<T> & other)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>
~WeakPtr(void)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>
operator =(const WeakPtr<T> & other)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>
operator =(const SharedPtr<T> & other)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>
acquire(void)620 inline void WeakPtr<T>::acquire (void)
621 {
622 	if (m_state)
623 		deAtomicIncrement32(&m_state->weakRefCount);
624 }
625 
626 template<typename T>
release(void)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