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
32namespace de
33{
34
35//! Shared pointer self-test.
36void SharedPtr_selfTest (void);
37
38class DeadReferenceException : public std::exception
39{
40public:
41				DeadReferenceException	(void) throw()
42		: std::exception()
43	{
44	}
45
46	const char*	what					(void) const throw()
47	{
48		return "DeadReferenceException";
49	}
50};
51
52struct 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
67template<typename Type, typename Deleter>
68struct 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
87private:
88	Type*		m_ptr;
89	Deleter		m_deleter;
90};
91
92template<typename T>
93class SharedPtr;
94
95template<typename T>
96class 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 *//*--------------------------------------------------------------------*/
107template<typename T>
108class SharedPtr
109{
110public:
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
146private:
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 *//*--------------------------------------------------------------------*/
172template<typename T>
173class WeakPtr
174{
175public:
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
187private:
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 *//*--------------------------------------------------------------------*/
202template<typename T>
203inline 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 *//*--------------------------------------------------------------------*/
219template<typename T>
220inline 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 *//*--------------------------------------------------------------------*/
254template<typename T>
255template<typename Deleter>
256inline 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 *//*--------------------------------------------------------------------*/
279template<typename T>
280inline 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 *//*--------------------------------------------------------------------*/
293template<typename T>
294template<typename Y>
295inline 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 *//*--------------------------------------------------------------------*/
308template<typename T>
309template<typename Y>
310inline SharedPtr<T>::SharedPtr (const WeakPtr<Y>& other)
311	: m_ptr		(DE_NULL)
312	, m_state	(DE_NULL)
313{
314	acquireFromWeak(other);
315}
316
317template<typename T>
318inline 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 *//*--------------------------------------------------------------------*/
333template<typename T>
334template<typename Y>
335inline 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 *//*--------------------------------------------------------------------*/
360template<typename T>
361inline 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 *//*--------------------------------------------------------------------*/
394template<typename T>
395template<typename Y>
396inline 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 *//*--------------------------------------------------------------------*/
414template<class T>
415template<typename Y>
416inline 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 *//*--------------------------------------------------------------------*/
427template<class T, class U>
428inline 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 *//*--------------------------------------------------------------------*/
439template<class T, class U>
440inline bool operator!= (const SharedPtr<T>& a, const SharedPtr<U>& b) throw()
441{
442	return a.get() != b.get();
443}
444
445/** Swap pointer contents. */
446template<typename T>
447inline 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. */
455template<typename T>
456inline 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 *//*--------------------------------------------------------------------*/
466template<typename T>
467inline void SharedPtr<T>::clear (void)
468{
469	release();
470	m_ptr	= DE_NULL;
471	m_state	= DE_NULL;
472}
473
474template<typename T>
475inline 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
503template<typename T>
504inline void SharedPtr<T>::acquire (void)
505{
506	if (m_state)
507	{
508		deAtomicIncrement32(&m_state->strongRefCount);
509		deAtomicIncrement32(&m_state->weakRefCount);
510	}
511}
512
513template<typename T>
514inline 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 *//*--------------------------------------------------------------------*/
537template<typename T>
538inline 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 *//*--------------------------------------------------------------------*/
548template<typename T>
549inline 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 *//*--------------------------------------------------------------------*/
560template<typename T>
561inline WeakPtr<T>::WeakPtr (const SharedPtr<T>& other)
562	: m_ptr		(other.m_ptr)
563	, m_state	(other.m_state)
564{
565	acquire();
566}
567
568template<typename T>
569inline 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 *//*--------------------------------------------------------------------*/
582template<typename T>
583inline 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 *//*--------------------------------------------------------------------*/
606template<typename T>
607inline 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
619template<typename T>
620inline void WeakPtr<T>::acquire (void)
621{
622	if (m_state)
623		deAtomicIncrement32(&m_state->weakRefCount);
624}
625
626template<typename T>
627inline 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