Coverage Report

Created: 2020-06-26 05:44

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