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