• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines IntrusiveRefCntPtr, a template class that
11 // implements a "smart" pointer for objects that maintain their own
12 // internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
13 // generic base classes for objects that wish to have their lifetimes
14 // managed using reference counting.
15 //
16 // IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
17 // LLVM-style casting.
18 //
19 //===----------------------------------------------------------------------===//
20 
21 #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
22 #define LLVM_ADT_INTRUSIVEREFCNTPTR_H
23 
24 #include <atomic>
25 #include <cassert>
26 #include <cstddef>
27 
28 namespace llvm {
29 
30 //===----------------------------------------------------------------------===//
31 /// RefCountedBase - A generic base class for objects that wish to
32 ///  have their lifetimes managed using reference counts. Classes
33 ///  subclass RefCountedBase to obtain such functionality, and are
34 ///  typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
35 ///  which automatically handle the management of reference counts.
36 ///  Objects that subclass RefCountedBase should not be allocated on
37 ///  the stack, as invoking "delete" (which is called when the
38 ///  reference count hits 0) on such objects is an error.
39 //===----------------------------------------------------------------------===//
40   template <class Derived>
41   class RefCountedBase {
42     mutable unsigned ref_cnt = 0;
43 
44   public:
45     RefCountedBase() = default;
RefCountedBase(const RefCountedBase &)46     RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
47 
Retain()48     void Retain() const { ++ref_cnt; }
Release()49     void Release() const {
50       assert (ref_cnt > 0 && "Reference count is already zero.");
51       if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
52     }
53   };
54 
55 //===----------------------------------------------------------------------===//
56 /// RefCountedBaseVPTR - A class that has the same function as
57 ///  RefCountedBase, but with a virtual destructor. Should be used
58 ///  instead of RefCountedBase for classes that already have virtual
59 ///  methods to enforce dynamic allocation via 'new'. Classes that
60 ///  inherit from RefCountedBaseVPTR can't be allocated on stack -
61 ///  attempting to do this will produce a compile error.
62 //===----------------------------------------------------------------------===//
63   class RefCountedBaseVPTR {
64     mutable unsigned ref_cnt = 0;
65 
66     virtual void anchor();
67 
68   protected:
69     RefCountedBaseVPTR() = default;
RefCountedBaseVPTR(const RefCountedBaseVPTR &)70     RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
71 
72     virtual ~RefCountedBaseVPTR() = default;
73 
Retain()74     void Retain() const { ++ref_cnt; }
Release()75     void Release() const {
76       assert (ref_cnt > 0 && "Reference count is already zero.");
77       if (--ref_cnt == 0) delete this;
78     }
79 
80     template <typename T>
81     friend struct IntrusiveRefCntPtrInfo;
82   };
83 
84 
85   template <typename T> struct IntrusiveRefCntPtrInfo {
retainIntrusiveRefCntPtrInfo86     static void retain(T *obj) { obj->Retain(); }
releaseIntrusiveRefCntPtrInfo87     static void release(T *obj) { obj->Release(); }
88   };
89 
90 /// \brief A thread-safe version of \c llvm::RefCountedBase.
91 ///
92 /// A generic base class for objects that wish to have their lifetimes managed
93 /// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
94 /// obtain such functionality, and are typically handled with
95 /// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
96 /// management of reference counts.
97 template <class Derived>
98 class ThreadSafeRefCountedBase {
99   mutable std::atomic<int> RefCount;
100 
101 protected:
ThreadSafeRefCountedBase()102   ThreadSafeRefCountedBase() : RefCount(0) {}
103 
104 public:
Retain()105   void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
106 
Release()107   void Release() const {
108     int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
109     assert(NewRefCount >= 0 && "Reference count was already zero.");
110     if (NewRefCount == 0)
111       delete static_cast<const Derived*>(this);
112   }
113 };
114 
115 //===----------------------------------------------------------------------===//
116 /// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
117 ///  that assumes the wrapped object has a reference count associated
118 ///  with it that can be managed via calls to
119 ///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
120 ///  manage reference counts via the RAII idiom: upon creation of
121 ///  smart pointer the reference count of the wrapped object is
122 ///  incremented and upon destruction of the smart pointer the
123 ///  reference count is decremented.  This class also safely handles
124 ///  wrapping NULL pointers.
125 ///
126 /// Reference counting is implemented via calls to
127 ///  Obj->Retain()/Obj->Release(). Release() is required to destroy
128 ///  the object when the reference count reaches zero. Inheriting from
129 ///  RefCountedBase/RefCountedBaseVPTR takes care of this
130 ///  automatically.
131 //===----------------------------------------------------------------------===//
132   template <typename T>
133   class IntrusiveRefCntPtr {
134     T* Obj = nullptr;
135 
136   public:
137     typedef T element_type;
138 
139     explicit IntrusiveRefCntPtr() = default;
140 
IntrusiveRefCntPtr(T * obj)141     IntrusiveRefCntPtr(T* obj) : Obj(obj) {
142       retain();
143     }
144 
IntrusiveRefCntPtr(const IntrusiveRefCntPtr & S)145     IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
146       retain();
147     }
148 
IntrusiveRefCntPtr(IntrusiveRefCntPtr && S)149     IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
150       S.Obj = nullptr;
151     }
152 
153     template <class X>
IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> && S)154     IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
155       S.Obj = nullptr;
156     }
157 
158     template <class X>
IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> & S)159     IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
160       : Obj(S.get()) {
161       retain();
162     }
163 
164     IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
165       swap(S);
166       return *this;
167     }
168 
~IntrusiveRefCntPtr()169     ~IntrusiveRefCntPtr() { release(); }
170 
171     T& operator*() const { return *Obj; }
172 
173     T* operator->() const { return Obj; }
174 
get()175     T* get() const { return Obj; }
176 
177     explicit operator bool() const { return Obj; }
178 
swap(IntrusiveRefCntPtr & other)179     void swap(IntrusiveRefCntPtr& other) {
180       T* tmp = other.Obj;
181       other.Obj = Obj;
182       Obj = tmp;
183     }
184 
reset()185     void reset() {
186       release();
187       Obj = nullptr;
188     }
189 
resetWithoutRelease()190     void resetWithoutRelease() {
191       Obj = nullptr;
192     }
193 
194   private:
retain()195     void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
release()196     void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
197 
198     template <typename X>
199     friend class IntrusiveRefCntPtr;
200   };
201 
202   template<class T, class U>
203   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
204                          const IntrusiveRefCntPtr<U>& B)
205   {
206     return A.get() == B.get();
207   }
208 
209   template<class T, class U>
210   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
211                          const IntrusiveRefCntPtr<U>& B)
212   {
213     return A.get() != B.get();
214   }
215 
216   template<class T, class U>
217   inline bool operator==(const IntrusiveRefCntPtr<T>& A,
218                          U* B)
219   {
220     return A.get() == B;
221   }
222 
223   template<class T, class U>
224   inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
225                          U* B)
226   {
227     return A.get() != B;
228   }
229 
230   template<class T, class U>
231   inline bool operator==(T* A,
232                          const IntrusiveRefCntPtr<U>& B)
233   {
234     return A == B.get();
235   }
236 
237   template<class T, class U>
238   inline bool operator!=(T* A,
239                          const IntrusiveRefCntPtr<U>& B)
240   {
241     return A != B.get();
242   }
243 
244   template <class T>
245   bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
246     return !B;
247   }
248 
249   template <class T>
250   bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
251     return B == A;
252   }
253 
254   template <class T>
255   bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
256     return !(A == B);
257   }
258 
259   template <class T>
260   bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
261     return !(A == B);
262   }
263 
264 //===----------------------------------------------------------------------===//
265 // LLVM-style downcasting support for IntrusiveRefCntPtr objects
266 //===----------------------------------------------------------------------===//
267 
268   template <typename From> struct simplify_type;
269 
270   template<class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
271     typedef T* SimpleType;
272     static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
273       return Val.get();
274     }
275   };
276 
277   template<class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
278     typedef /*const*/ T* SimpleType;
279     static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
280       return Val.get();
281     }
282   };
283 
284 } // end namespace llvm
285 
286 #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
287