Halide
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 <stdlib.h>
11 #include <atomic>
12 
13 #include "Util.h"
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 public:
22  RefCount() : count(0) {}
23  int increment() {return ++count;} // Increment and return new value
24  int decrement() {return --count;} // Decrement and return new value
25  bool is_zero() const {return count == 0;}
26 };
27 
28 /**
29  * Because in this header we don't yet know how client classes store
30  * their RefCount (and we don't want to depend on the declarations of
31  * the client classes), any class that you want to hold onto via one
32  * of these must provide implementations of ref_count and destroy,
33  * which we forward-declare here.
34  *
35  * E.g. if you want to use IntrusivePtr<MyClass>, then you should
36  * define something like this in MyClass.cpp (assuming MyClass has
37  * a field: mutable RefCount ref_count):
38  *
39  * template<> RefCount &ref_count<MyClass>(const MyClass *c) {return c->ref_count;}
40  * template<> void destroy<MyClass>(const MyClass *c) {delete c;}
41  */
42 // @{
43 template<typename T> EXPORT RefCount &ref_count(const T *t);
44 template<typename T> EXPORT void destroy(const T *t);
45 // @}
46 
47 /** Intrusive shared pointers have a reference count (a
48  * RefCount object) stored in the class itself. This is perhaps more
49  * efficient than storing it externally, but more importantly, it
50  * means it's possible to recover a reference-counted handle from the
51  * raw pointer, and it's impossible to have two different reference
52  * counts attached to the same raw object. Seeing as we pass around
53  * raw pointers to concrete IRNodes and Expr's interchangeably, this
54  * is a useful property.
55  */
56 template<typename T>
57 struct IntrusivePtr {
58 private:
59 
60  void incref(T *p) {
61  if (p) {
62  ref_count(p).increment();
63  }
64  };
65 
66  void decref(T *p) {
67  if (p) {
68  // Note that if the refcount is already zero, then we're
69  // in a recursive destructor due to a self-reference (a
70  // cycle), where the ref_count has been adjusted to remove
71  // the counts due to the cycle. The next line then makes
72  // the ref_count negative, which prevents actually
73  // entering the destructor recursively.
74  if (ref_count(p).decrement() == 0) {
75  destroy(p);
76  }
77  }
78  }
79 
80 protected:
81  T *ptr;
82 
83 public:
84  /** Access the raw pointer in a variety of ways.
85  * Note that a "const IntrusivePtr<T>" is not the same thing as an
86  * IntrusivePtr<const T>. So the methods that return the ptr are
87  * const, despite not adding an extra const to T. */
88  // @{
89  T *get() const {
90  return ptr;
91  }
92 
93  T &operator*() const {
94  return *ptr;
95  }
96 
97  T *operator->() const {
98  return ptr;
99  }
100  // @}
101 
103  decref(ptr);
104  }
105 
106  IntrusivePtr() : ptr(nullptr) {
107  }
108 
109  IntrusivePtr(T *p) : ptr(p) {
110  incref(ptr);
111  }
112 
113  IntrusivePtr(const IntrusivePtr<T> &other) : ptr(other.ptr) {
114  incref(ptr);
115  }
116 
117  IntrusivePtr(IntrusivePtr<T> &&other) : ptr(other.ptr) {
118  other.ptr = nullptr;
119  }
120 
122  if (other.ptr == ptr) return *this;
123  // Other can be inside of something owned by this, so we
124  // should be careful to incref other before we decref
125  // ourselves.
126  T *temp = other.ptr;
127  incref(temp);
128  decref(ptr);
129  ptr = temp;
130  return *this;
131  }
132 
134  std::swap(ptr, other.ptr);
135  return *this;
136  }
137 
138  /* Handles can be null. This checks that. */
139  bool defined() const {
140  return ptr != nullptr;
141  }
142 
143  /* Check if two handles point to the same ptr. This is
144  * equality of reference, not equality of value. */
145  bool same_as(const IntrusivePtr &other) const {
146  return ptr == other.ptr;
147  }
148 
149  bool operator <(const IntrusivePtr<T> &other) const {
150  return ptr < other.ptr;
151  }
152 
153 };
154 
155 }
156 }
157 
158 #endif
Various utility functions used internally Halide.
EXPORT RefCount & ref_count(const T *t)
Because in this header we don&#39;t yet know how client classes store their RefCount (and we don&#39;t want t...
Intrusive shared pointers have a reference count (a RefCount object) stored in the class itself...
Definition: IntrusivePtr.h:57
Defines methods for manipulating and analyzing boolean expressions.
bool same_as(const IntrusivePtr &other) const
Definition: IntrusivePtr.h:145
T & operator*() const
Access the raw pointer in a variety of ways.
Definition: IntrusivePtr.h:93
IntrusivePtr< T > & operator=(const IntrusivePtr< T > &other)
Definition: IntrusivePtr.h:121
EXPORT void destroy(const T *t)
Because in this header we don&#39;t yet know how client classes store their RefCount (and we don&#39;t want t...
IntrusivePtr(const IntrusivePtr< T > &other)
Definition: IntrusivePtr.h:113
T * operator->() const
Access the raw pointer in a variety of ways.
Definition: IntrusivePtr.h:97
IntrusivePtr< T > & operator=(IntrusivePtr< T > &&other)
Definition: IntrusivePtr.h:133
IntrusivePtr(IntrusivePtr< T > &&other)
Definition: IntrusivePtr.h:117
#define EXPORT
Definition: Util.h:30
A class representing a reference count to be used with IntrusivePtr.
Definition: IntrusivePtr.h:19