Halide 22.0.0 Halide compiler and libraries

Loading...
Searching...
No Matches
IntrusivePtr.h
Go to the documentation of this file.
1#ifndef HALIDE_INTRUSIVE_PTR_H
2#define HALIDE_INTRUSIVE_PTR_H
3
4/** \file
5 *
6 * Support classes for reference-counting via intrusive shared
7 * pointers.
8 */
9
10#include <atomic>
11#include <cstdlib>
12
13#include "runtime/HalideRuntime.h" // for HALIDE_ALWAYS_INLINE
14
15 namespace Halide {
16 namespace Internal {
17
18/** A class representing a reference count to be used with IntrusivePtr */
19 class RefCount {
20 std::atomic<int> count;
21
22 public:
23 RefCount() noexcept
24 : count(0) {
25 }
26 int increment() {
27 return ++count;
28 } // Increment and return new value
29 int decrement() {
30 return --count;
31 } // Decrement and return new value
32 bool is_const_zero() const {
33 return count == 0;
34 }
35 int atomic_get() const {
36 return count;
37 }
38};
39
40/**
41 * Because in this header we don't yet know how client classes store
42 * their RefCount (and we don't want to depend on the declarations of
43 * the client classes), any class that you want to hold onto via one
44 * of these must provide implementations of ref_count and destroy,
45 * which we forward-declare here.
46 *
47 * E.g. if you want to use IntrusivePtr<MyClass>, then you should
48 * define something like this in MyClass.cpp (assuming MyClass has
49 * a field: mutable RefCount ref_count):
50 *
51 * template<> RefCount &ref_count<MyClass>(const MyClass *c) noexcept {return c->ref_count;}
52 * template<> void destroy<MyClass>(const MyClass *c) {delete c;}
53 */
54// @{
55 template<typename T>
56 RefCount &ref_count(const T *t) noexcept;
57 template<typename T>
58 void destroy(const T *t);
59// @}
60
61/** Intrusive shared pointers have a reference count (a
62 * RefCount object) stored in the class itself. This is perhaps more
63 * efficient than storing it externally, but more importantly, it
64 * means it's possible to recover a reference-counted handle from the
65 * raw pointer, and it's impossible to have two different reference
66 * counts attached to the same raw object. Seeing as we pass around
67 * raw pointers to concrete IRNodes and Expr's interchangeably, this
68 * is a useful property.
69 */
70 template<typename T>
71 struct IntrusivePtr {
72 private:
73 void incref(T *p) {
74 if (p) {
75 ref_count(p).increment();
76 }
77 }
78
79 void decref(T *p) {
80 if (p) {
81 // Note that if the refcount is already zero, then we're
82 // in a recursive destructor due to a self-reference (a
83 // cycle), where the ref_count has been adjusted to remove
84 // the counts due to the cycle. The next line then makes
85 // the ref_count negative, which prevents actually
86 // entering the destructor recursively.
87 if (ref_count(p).decrement() == 0) {
88 destroy(p);
89 }
90 }
91 }
92
93 protected:
94 T *ptr = nullptr;
95
96 public:
97 /** Access the raw pointer in a variety of ways.
98 * Note that a "const IntrusivePtr<T>" is not the same thing as an
99 * IntrusivePtr<const T>. So the methods that return the ptr are
100 * const, despite not adding an extra const to T. */
101 // @{
102 T *get() const {
103 return ptr;
104 }
105
106 T &operator*() const {
107 return *ptr;
108 }
109
110 T *operator->() const {
111 return ptr;
112 }
113 // @}
114
115 ~IntrusivePtr() {
116 decref(ptr);
117 }
118
119 HALIDE_ALWAYS_INLINE
120 IntrusivePtr() = default;
121
122 HALIDE_ALWAYS_INLINE
123 IntrusivePtr(T *p)
124 : ptr(p) {
125 incref(ptr);
126 }
127
128 HALIDE_ALWAYS_INLINE
129 IntrusivePtr(const IntrusivePtr<T> &other) noexcept
130 : ptr(other.ptr) {
131 incref(ptr);
132 }
133
134 HALIDE_ALWAYS_INLINE
135 IntrusivePtr(IntrusivePtr<T> &&other) noexcept
136 : ptr(other.ptr) {
137 other.ptr = nullptr;
138 }
139
140 // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
141 IntrusivePtr<T> &operator=(const IntrusivePtr<T> &other) {
142 // Same-ptr but different-this happens frequently enough
143 // to check for (see https://github.com/halide/Halide/pull/5412)
144 if (other.ptr == ptr) {
145 return *this;
146 }
147 // Other can be inside of something owned by this, so we
148 // should be careful to incref other before we decref
149 // ourselves.
150 T *temp = other.ptr;
151 incref(temp);
152 decref(ptr);
153 ptr = temp;
154 return *this;
155 }
156
157 IntrusivePtr<T> &operator=(IntrusivePtr<T> &&other) noexcept {
158 std::swap(ptr, other.ptr);
159 return *this;
160 }
161
162 /* Handles can be null. This checks that. */
163 HALIDE_ALWAYS_INLINE
164 bool defined() const {
165 return ptr != nullptr;
166 }
167
168 /* Check if two handles point to the same ptr. This is
169 * equality of reference, not equality of value. */
170 HALIDE_ALWAYS_INLINE
171 bool same_as(const IntrusivePtr &other) const {
172 return ptr == other.ptr;
173 }
174
175 HALIDE_ALWAYS_INLINE
176 bool operator<(const IntrusivePtr<T> &other) const {
177 return ptr < other.ptr;
178 }
179
180 HALIDE_ALWAYS_INLINE
181 bool is_sole_reference() const {
182 return ptr && ref_count(ptr).atomic_get() == 1;
183 }
184};
185
186} // namespace Internal
187} // namespace Halide
188
189#endif
HalideRuntime.h
This file declares the routines used by Halide internally in its runtime.
HALIDE_ALWAYS_INLINE
#define HALIDE_ALWAYS_INLINE
Definition HalideRuntime.h:49
Halide::Internal::RefCount
A class representing a reference count to be used with IntrusivePtr.
Definition IntrusivePtr.h:19
Halide::Internal::RefCount::decrement
int decrement()
Definition IntrusivePtr.h:29
Halide::Internal::RefCount::increment
int increment()
Definition IntrusivePtr.h:26
Halide::Internal::RefCount::RefCount
RefCount() noexcept
Definition IntrusivePtr.h:23
Halide::Internal::RefCount::is_const_zero
bool is_const_zero() const
Definition IntrusivePtr.h:32
Halide::Internal::RefCount::atomic_get
int atomic_get() const
Definition IntrusivePtr.h:35
Halide::Internal::destroy
void destroy(const T *t)
Halide::Internal::ref_count
RefCount & ref_count(const T *t) noexcept
Because in this header we don't yet know how client classes store their RefCount (and we don't want t...
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition AbstractGenerator.h:19
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
Halide::cast
Internal::ConstantInterval cast(Type t, const Internal::ConstantInterval &a)
Cast operators for ConstantIntervals.
Halide::Internal::IntrusivePtr
Intrusive shared pointers have a reference count (a RefCount object) stored in the class itself.
Definition IntrusivePtr.h:71
Halide::Internal::IntrusivePtr::IntrusivePtr
HALIDE_ALWAYS_INLINE IntrusivePtr()=default
Halide::Internal::IntrusivePtr::operator=
IntrusivePtr< T > & operator=(IntrusivePtr< T > &&other) noexcept
Definition IntrusivePtr.h:157
Halide::Internal::IntrusivePtr::IntrusivePtr
HALIDE_ALWAYS_INLINE IntrusivePtr(T *p)
Definition IntrusivePtr.h:123
Halide::Internal::IntrusivePtr::defined
HALIDE_ALWAYS_INLINE bool defined() const
Definition IntrusivePtr.h:164
Halide::Internal::IntrusivePtr::operator->
T * operator->() const
Definition IntrusivePtr.h:110
Halide::Internal::IntrusivePtr::same_as
HALIDE_ALWAYS_INLINE bool same_as(const IntrusivePtr &other) const
Definition IntrusivePtr.h:171
Halide::Internal::IntrusivePtr::get
T * get() const
Access the raw pointer in a variety of ways.
Definition IntrusivePtr.h:102
Halide::Internal::IntrusivePtr::~IntrusivePtr
~IntrusivePtr()
Definition IntrusivePtr.h:115
Halide::Internal::IntrusivePtr::operator<
HALIDE_ALWAYS_INLINE bool operator<(const IntrusivePtr< T > &other) const
Definition IntrusivePtr.h:176
Halide::Internal::IntrusivePtr::ptr
T * ptr
Definition IntrusivePtr.h:94
Halide::Internal::IntrusivePtr::IntrusivePtr
HALIDE_ALWAYS_INLINE IntrusivePtr(const IntrusivePtr< T > &other) noexcept
Definition IntrusivePtr.h:129
Halide::Internal::IntrusivePtr::IntrusivePtr
HALIDE_ALWAYS_INLINE IntrusivePtr(IntrusivePtr< T > &&other) noexcept
Definition IntrusivePtr.h:135
Halide::Internal::IntrusivePtr::is_sole_reference
HALIDE_ALWAYS_INLINE bool is_sole_reference() const
Definition IntrusivePtr.h:181
Halide::Internal::IntrusivePtr::operator=
IntrusivePtr< T > & operator=(const IntrusivePtr< T > &other)
Definition IntrusivePtr.h:141
Halide::Internal::IntrusivePtr::operator*
T & operator*() const
Definition IntrusivePtr.h:106