IntrusiveRefCntPtr.h revision f3014761c955345d6e05491608e73228d014afb7
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 the RefCountedBase, ThreadSafeRefCountedBase, and
11// IntrusiveRefCntPtr classes.
12//
13// IntrusiveRefCntPtr is a smart pointer to an object which maintains a
14// reference count.  (ThreadSafe)RefCountedBase is a mixin class that adds a
15// refcount member variable and methods for updating the refcount.  An object
16// that inherits from (ThreadSafe)RefCountedBase deletes itself when its
17// refcount hits zero.
18//
19// For example:
20//
21//   class MyClass : public RefCountedBase<MyClass> {};
22//
23//   void foo() {
24//     // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by
25//     // 1 (from 0 in this case).
26//     IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass());
27//
28//     // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1.
29//     IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1);
30//
31//     // Constructing an IntrusiveRefCntPtr has no effect on the object's
32//     // refcount.  After a move, the moved-from pointer is null.
33//     IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1));
34//     assert(Ptr1 == nullptr);
35//
36//     // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1.
37//     Ptr2.reset();
38//
39//     // The object deletes itself when we return from the function, because
40//     // Ptr3's destructor decrements its refcount to 0.
41//   }
42//
43// You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.:
44//
45//   IntrusiveRefCntPtr<MyClass> Ptr(new MyClass());
46//   OtherClass *Other = dyn_cast<OtherClass>(Ptr);  // Ptr.get() not required
47//
48// IntrusiveRefCntPtr works with any class that
49//
50//  - inherits from (ThreadSafe)RefCountedBase,
51//  - has Retain() and Release() methods, or
52//  - specializes IntrusiveRefCntPtrInfo.
53//
54//===----------------------------------------------------------------------===//
55
56#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
57#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
58
59#include <atomic>
60#include <cassert>
61#include <cstddef>
62
63namespace llvm {
64
65/// A CRTP mixin class that adds reference counting to a type.
66///
67/// The lifetime of an object which inherits from RefCountedBase is managed by
68/// calls to Release() and Retain(), which increment and decrement the object's
69/// refcount, respectively.  When a Release() call decrements the refcount to 0,
70/// the object deletes itself.
71template <class Derived> class RefCountedBase {
72  mutable unsigned RefCount = 0;
73
74public:
75  RefCountedBase() = default;
76  RefCountedBase(const RefCountedBase &) {}
77
78  void Retain() const { ++RefCount; }
79
80  void Release() const {
81    assert(RefCount > 0 && "Reference count is already zero.");
82    if (--RefCount == 0)
83      delete static_cast<const Derived *>(this);
84  }
85};
86
87/// A thread-safe version of \c RefCountedBase.
88template <class Derived> class ThreadSafeRefCountedBase {
89  mutable std::atomic<int> RefCount;
90
91protected:
92  ThreadSafeRefCountedBase() : RefCount(0) {}
93
94public:
95  void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); }
96
97  void Release() const {
98    int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
99    assert(NewRefCount >= 0 && "Reference count was already zero.");
100    if (NewRefCount == 0)
101      delete static_cast<const Derived *>(this);
102  }
103};
104
105/// Class you can specialize to provide custom retain/release functionality for
106/// a type.
107///
108/// Usually specializing this class is not necessary, as IntrusiveRefCntPtr
109/// works with any type which defines Retain() and Release() functions -- you
110/// can define those functions yourself if RefCountedBase doesn't work for you.
111///
112/// One case when you might want to specialize this type is if you have
113///  - Foo.h defines type Foo and includes Bar.h, and
114///  - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions.
115///
116/// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in
117/// the declaration of Foo.  Without the declaration of Foo, normally Bar.h
118/// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call
119/// T::Retain and T::Release.
120///
121/// To resolve this, Bar.h could include a third header, FooFwd.h, which
122/// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>.  Then
123/// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any
124/// functions on Foo itself, because Foo would be an incomplete type.
125template <typename T> struct IntrusiveRefCntPtrInfo {
126  static void retain(T *obj) { obj->Retain(); }
127  static void release(T *obj) { obj->Release(); }
128};
129
130/// A smart pointer to a reference-counted object that inherits from
131/// RefCountedBase or ThreadSafeRefCountedBase.
132///
133/// This class increments its pointee's reference count when it is created, and
134/// decrements its refcount when it's destroyed (or is changed to point to a
135/// different object).
136template <typename T> class IntrusiveRefCntPtr {
137  T *Obj = nullptr;
138
139public:
140  using element_type = T;
141
142  explicit IntrusiveRefCntPtr() = default;
143  IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); }
144  IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); }
145  IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; }
146
147  template <class X>
148  IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> &&S) : Obj(S.get()) {
149    S.Obj = nullptr;
150  }
151
152  template <class X>
153  IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X> &S) : Obj(S.get()) {
154    retain();
155  }
156
157  ~IntrusiveRefCntPtr() { release(); }
158
159  IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) {
160    swap(S);
161    return *this;
162  }
163
164  T &operator*() const { return *Obj; }
165  T *operator->() const { return Obj; }
166  T *get() const { return Obj; }
167  explicit operator bool() const { return Obj; }
168
169  void swap(IntrusiveRefCntPtr &other) {
170    T *tmp = other.Obj;
171    other.Obj = Obj;
172    Obj = tmp;
173  }
174
175  void reset() {
176    release();
177    Obj = nullptr;
178  }
179
180  void resetWithoutRelease() { Obj = nullptr; }
181
182private:
183  void retain() {
184    if (Obj)
185      IntrusiveRefCntPtrInfo<T>::retain(Obj);
186  }
187
188  void release() {
189    if (Obj)
190      IntrusiveRefCntPtrInfo<T>::release(Obj);
191  }
192
193  template <typename X> friend class IntrusiveRefCntPtr;
194};
195
196template <class T, class U>
197inline bool operator==(const IntrusiveRefCntPtr<T> &A,
198                       const IntrusiveRefCntPtr<U> &B) {
199  return A.get() == B.get();
200}
201
202template <class T, class U>
203inline bool operator!=(const IntrusiveRefCntPtr<T> &A,
204                       const IntrusiveRefCntPtr<U> &B) {
205  return A.get() != B.get();
206}
207
208template <class T, class U>
209inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) {
210  return A.get() == B;
211}
212
213template <class T, class U>
214inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) {
215  return A.get() != B;
216}
217
218template <class T, class U>
219inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) {
220  return A == B.get();
221}
222
223template <class T, class U>
224inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) {
225  return A != B.get();
226}
227
228template <class T>
229bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
230  return !B;
231}
232
233template <class T>
234bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
235  return B == A;
236}
237
238template <class T>
239bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
240  return !(A == B);
241}
242
243template <class T>
244bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
245  return !(A == B);
246}
247
248// Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from
249// Casting.h.
250template <typename From> struct simplify_type;
251
252template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> {
253  using SimpleType = T *;
254
255  static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) {
256    return Val.get();
257  }
258};
259
260template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> {
261  using SimpleType = /*const*/ T *;
262
263  static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) {
264    return Val.get();
265  }
266};
267
268} // end namespace llvm
269
270#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H
271