Medial Code Documentation
Loading...
Searching...
No Matches
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
14namespace 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
41template <typename T> IntrusivePtrCell &IntrusivePtrRefCount(T const *ptr) noexcept;
42
73template <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
116 IntrusivePtr<T> &operator=(IntrusivePtr<T> const &that) {
117 IntrusivePtr<T>{that}.swap(*this);
118 return *this;
119 }
120 IntrusivePtr<T> &operator=(IntrusivePtr<T> &&that) noexcept {
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
149template <class T, class U>
150bool operator==(IntrusivePtr<T> const &x, IntrusivePtr<U> const &y) noexcept {
151 return x.get() == y.get();
152}
153
154template <class T, class U>
155bool operator!=(IntrusivePtr<T> const &x, IntrusivePtr<U> const &y) noexcept {
156 return x.get() != y.get();
157}
158
159template <class T, class U>
160bool operator==(IntrusivePtr<T> const &x, U *y) noexcept {
161 return x.get() == y;
162}
163
164template <class T, class U>
165bool operator!=(IntrusivePtr<T> const &x, U *y) noexcept {
166 return x.get() != y;
167}
168
169template <class T, class U>
170bool operator==(T *x, IntrusivePtr<U> const &y) noexcept {
171 return y == x;
172}
173
174template <class T, class U>
175bool operator!=(T *x, IntrusivePtr<U> const &y) noexcept {
176 return y != x;
177}
178
179template <class T>
180bool operator<(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
181 return std::less<T*>{}(x.get(), y.get());
182}
183
184template <class T>
185bool operator<=(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
186 return std::less_equal<T*>{}(x.get(), y.get());
187}
188
189template <class T>
190bool operator>(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
191 return !(x <= y);
192}
193
194template <class T>
195bool operator>=(IntrusivePtr<T> const &x, IntrusivePtr<T> const &y) noexcept {
196 return !(x < y);
197}
198
199template <class E, class T, class Y>
200std::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
207namespace std {
208template <class T>
209void swap(xgboost::IntrusivePtr<T> &x, // NOLINT
210 xgboost::IntrusivePtr<T> &y) noexcept {
211 x.swap(y);
212}
213
214template <typename T>
215struct 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
Implementation of Intrusive Pointer. A smart pointer that points to an object with an embedded refere...
Definition intrusive_ptr.h:73
IntrusivePtr(T *p)
Contruct an IntrusivePtr from raw pointer. IntrusivePtr takes the ownership.
Definition intrusive_ptr.h:104
bool operator<(const value_t lhs, const value_t rhs) noexcept
comparison operator for JSON types
Definition json.hpp:2889
Definition StdDeque.h:58
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:24418
namespace of xgboost
Definition base.h:90
IntrusivePtrCell & IntrusivePtrRefCount(T const *ptr) noexcept
User defined function for returning embedded reference count.
Definition intrusive_ptr.h:94