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