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