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