xgboost
intrusive_ptr.h
Go to the documentation of this file.
1 
6 #ifndef XGBOOST_INTRUSIVE_PTR_H_
7 #define XGBOOST_INTRUSIVE_PTR_H_
8 
9 #include <atomic>
10 #include <cinttypes>
11 #include <functional>
12 #include <ostream>
13 
14 namespace xgboost {
21  private:
22  std::atomic<int32_t> count_ {0};
23  template <typename T> friend class IntrusivePtr;
24 
25  std::int32_t IncRef() noexcept {
26  return count_.fetch_add(1, std::memory_order_relaxed);
27  }
28  std::int32_t DecRef() noexcept {
29  return count_.fetch_sub(1, std::memory_order_release);
30  }
31  bool IsZero() const { return Count() == 0; }
32 
33  public:
34  IntrusivePtrCell() noexcept = default;
35  int32_t Count() const { return count_.load(std::memory_order_relaxed); }
36 };
37 
41 template <typename T> IntrusivePtrCell &IntrusivePtrRefCount(T const *ptr) noexcept;
42 
73 template <typename T> class IntrusivePtr {
74  private:
75  void IncRef(T *ptr) {
76  if (ptr) {
77  IntrusivePtrRefCount(ptr).IncRef();
78  }
79  }
80  void DecRef(T *ptr) {
81  if (ptr) {
82  if (IntrusivePtrRefCount(ptr).DecRef() == 1) {
83  std::atomic_thread_fence(std::memory_order_acquire);
84  delete ptr;
85  }
86  }
87  }
88 
89  protected:
90  T *ptr_{nullptr};
91 
92  public:
93  using element_type = T; // NOLINT
94  struct Hash {
95  std::size_t operator()(IntrusivePtr<element_type> const &ptr) const noexcept {
96  return std::hash<element_type *>()(ptr.get());
97  }
98  };
104  explicit IntrusivePtr(T *p) : ptr_{p} {
105  if (ptr_) {
106  IncRef(ptr_);
107  }
108  }
109 
110  IntrusivePtr() noexcept = default;
111  IntrusivePtr(IntrusivePtr const &that) : ptr_{that.ptr_} { IncRef(ptr_); }
112  IntrusivePtr(IntrusivePtr &&that) noexcept : ptr_{that.ptr_} { that.ptr_ = nullptr; }
113 
114  ~IntrusivePtr() { DecRef(ptr_); }
115 
117  IntrusivePtr<T>{that}.swap(*this);
118  return *this;
119  }
121  std::swap(ptr_, that.ptr_);
122  return *this;
123  }
124 
125  void reset() { // NOLINT
126  DecRef(ptr_);
127  ptr_ = nullptr;
128  }
129  void reset(element_type *that) { IntrusivePtr{that}.swap(*this); } // NOLINT
130  // clang-tidy might manufacture a null value, disable the check
131  element_type &operator*() const noexcept { return *ptr_; } // NOLINT
132  element_type *operator->() const noexcept { return ptr_; }
133  element_type *get() const noexcept { return ptr_; } // NOLINT
134 
135  explicit operator bool() const noexcept { return static_cast<bool>(ptr_); }
136 
137  int32_t use_count() noexcept { // NOLINT
138  return ptr_ ? IntrusivePtrRefCount(ptr_).Count() : 0;
139  }
140 
141  /*
142  * \brief Helper function for swapping 2 pointers.
143  */
144  void swap(IntrusivePtr<T> &that) noexcept { // NOLINT
145  std::swap(ptr_, that.ptr_);
146  }
147 };
148 
149 template <class T, class U>
150 bool operator==(IntrusivePtr<T> const &x, IntrusivePtr<U> const &y) noexcept {
151  return x.get() == y.get();
152 }
153 
154 template <class T, class U>
155 bool operator!=(IntrusivePtr<T> const &x, IntrusivePtr<U> const &y) noexcept {
156  return x.get() != y.get();
157 }
158 
159 template <class T, class U>
160 bool operator==(IntrusivePtr<T> const &x, U *y) noexcept {
161  return x.get() == y;
162 }
163 
164 template <class T, class U>
165 bool operator!=(IntrusivePtr<T> const &x, U *y) noexcept {
166  return x.get() != y;
167 }
168 
169 template <class T, class U>
170 bool operator==(T *x, IntrusivePtr<U> const &y) noexcept {
171  return y == x;
172 }
173 
174 template <class T, class U>
175 bool operator!=(T *x, IntrusivePtr<U> const &y) noexcept {
176  return y != x;
177 }
178 
179 template <class T>
180 bool operator<(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
181  return std::less<T*>{}(x.get(), y.get());
182 }
183 
184 template <class T>
185 bool operator<=(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
186  return std::less_equal<T*>{}(x.get(), y.get());
187 }
188 
189 template <class T>
190 bool operator>(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
191  return !(x <= y);
192 }
193 
194 template <class T>
195 bool operator>=(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
196  return !(x < y);
197 }
198 
199 template <class E, class T, class Y>
200 std::basic_ostream<E, T> &operator<<(std::basic_ostream<E, T> &os,
201  IntrusivePtr<Y> const &p) {
202  os << p.get();
203  return os;
204 }
205 } // namespace xgboost
206 
207 namespace std {
208 template <class T>
209 void swap(xgboost::IntrusivePtr<T> &x, // NOLINT
210  xgboost::IntrusivePtr<T> &y) noexcept {
211  x.swap(y);
212 }
213 
214 template <typename T>
215 struct hash<xgboost::IntrusivePtr<T>> : public xgboost::IntrusivePtr<T>::Hash {};
216 } // namespace std
217 #endif // XGBOOST_INTRUSIVE_PTR_H_
Helper class for embedding reference counting into client objects. See https://www....
Definition: intrusive_ptr.h:20
int32_t Count() const
Definition: intrusive_ptr.h:35
IntrusivePtrCell() noexcept=default
Implementation of Intrusive Pointer. A smart pointer that points to an object with an embedded refere...
Definition: intrusive_ptr.h:73
IntrusivePtr< T > & operator=(IntrusivePtr< T > &&that) noexcept
Definition: intrusive_ptr.h:120
element_type & operator*() const noexcept
Definition: intrusive_ptr.h:131
void reset(element_type *that)
Definition: intrusive_ptr.h:129
IntrusivePtr< T > & operator=(IntrusivePtr< T > const &that)
Definition: intrusive_ptr.h:116
IntrusivePtr(IntrusivePtr &&that) noexcept
Definition: intrusive_ptr.h:112
void swap(IntrusivePtr< T > &that) noexcept
Definition: intrusive_ptr.h:144
element_type * get() const noexcept
Definition: intrusive_ptr.h:133
~IntrusivePtr()
Definition: intrusive_ptr.h:114
IntrusivePtr() noexcept=default
T * ptr_
Definition: intrusive_ptr.h:90
T element_type
Definition: intrusive_ptr.h:93
int32_t use_count() noexcept
Definition: intrusive_ptr.h:137
IntrusivePtr(T *p)
Contruct an IntrusivePtr from raw pointer. IntrusivePtr takes the ownership.
Definition: intrusive_ptr.h:104
element_type * operator->() const noexcept
Definition: intrusive_ptr.h:132
void reset()
Definition: intrusive_ptr.h:125
Definition: intrusive_ptr.h:207
void swap(xgboost::IntrusivePtr< T > &x, xgboost::IntrusivePtr< T > &y) noexcept
Definition: intrusive_ptr.h:209
Core data structure for multi-target trees.
Definition: base.h:87
bool operator!=(IntrusivePtr< T > const &x, IntrusivePtr< U > const &y) noexcept
Definition: intrusive_ptr.h:155
bool operator==(IntrusivePtr< T > const &x, IntrusivePtr< U > const &y) noexcept
Definition: intrusive_ptr.h:150
IntrusivePtrCell & IntrusivePtrRefCount(T const *ptr) noexcept
User defined function for returning embedded reference count.
std::ostream & operator<<(std::ostream &os, DeviceOrd ord)
bool operator>=(IntrusivePtr< T > const &x, IntrusivePtr< T > const &y) noexcept
Definition: intrusive_ptr.h:195
bool operator>(IntrusivePtr< T > const &x, IntrusivePtr< T > const &y) noexcept
Definition: intrusive_ptr.h:190
bool operator<=(IntrusivePtr< T > const &x, IntrusivePtr< T > const &y) noexcept
Definition: intrusive_ptr.h:185
bool operator<(IntrusivePtr< T > const &x, IntrusivePtr< T > const &y) noexcept
Definition: intrusive_ptr.h:180
Definition: intrusive_ptr.h:94
std::size_t operator()(IntrusivePtr< element_type > const &ptr) const noexcept
Definition: intrusive_ptr.h:95