xref: /aosp_15_r20/external/deqp/framework/delibs/decpp/deSharedPtr.hpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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