1*da0073e9SAndroid Build Coastguard Worker #pragma once
2*da0073e9SAndroid Build Coastguard Worker
3*da0073e9SAndroid Build Coastguard Worker #include <c10/util/Exception.h>
4*da0073e9SAndroid Build Coastguard Worker #include <c10/util/MaybeOwned.h>
5*da0073e9SAndroid Build Coastguard Worker #include <atomic>
6*da0073e9SAndroid Build Coastguard Worker #include <climits>
7*da0073e9SAndroid Build Coastguard Worker #include <memory>
8*da0073e9SAndroid Build Coastguard Worker #include <type_traits>
9*da0073e9SAndroid Build Coastguard Worker
10*da0073e9SAndroid Build Coastguard Worker namespace pybind11 {
11*da0073e9SAndroid Build Coastguard Worker template <typename, typename...>
12*da0073e9SAndroid Build Coastguard Worker class class_;
13*da0073e9SAndroid Build Coastguard Worker }
14*da0073e9SAndroid Build Coastguard Worker
15*da0073e9SAndroid Build Coastguard Worker namespace c10 {
16*da0073e9SAndroid Build Coastguard Worker class intrusive_ptr_target;
17*da0073e9SAndroid Build Coastguard Worker namespace raw {
18*da0073e9SAndroid Build Coastguard Worker namespace weak_intrusive_ptr {
19*da0073e9SAndroid Build Coastguard Worker inline void incref(intrusive_ptr_target* self);
20*da0073e9SAndroid Build Coastguard Worker }
21*da0073e9SAndroid Build Coastguard Worker namespace intrusive_ptr {
22*da0073e9SAndroid Build Coastguard Worker inline void incref(intrusive_ptr_target* self);
23*da0073e9SAndroid Build Coastguard Worker }
24*da0073e9SAndroid Build Coastguard Worker
25*da0073e9SAndroid Build Coastguard Worker // constructor tag used by intrusive_ptr constructors
26*da0073e9SAndroid Build Coastguard Worker struct DontIncreaseRefcount {};
27*da0073e9SAndroid Build Coastguard Worker } // namespace raw
28*da0073e9SAndroid Build Coastguard Worker
29*da0073e9SAndroid Build Coastguard Worker namespace detail {
30*da0073e9SAndroid Build Coastguard Worker constexpr uint32_t kImpracticallyHugeReferenceCount = 0x0FFFFFFF;
31*da0073e9SAndroid Build Coastguard Worker } // namespace detail
32*da0073e9SAndroid Build Coastguard Worker
33*da0073e9SAndroid Build Coastguard Worker /**
34*da0073e9SAndroid Build Coastguard Worker * intrusive_ptr<T> is an alternative to shared_ptr<T> that has better
35*da0073e9SAndroid Build Coastguard Worker * performance because it does the refcounting intrusively
36*da0073e9SAndroid Build Coastguard Worker * (i.e. in a member of the object itself).
37*da0073e9SAndroid Build Coastguard Worker * Your class T needs to inherit from intrusive_ptr_target to allow it to be
38*da0073e9SAndroid Build Coastguard Worker * used in an intrusive_ptr<T>. Your class's constructor should not allow
39*da0073e9SAndroid Build Coastguard Worker *`this` to escape to other threads or create an intrusive_ptr from `this`.
40*da0073e9SAndroid Build Coastguard Worker */
41*da0073e9SAndroid Build Coastguard Worker
42*da0073e9SAndroid Build Coastguard Worker // Note [Stack allocated intrusive_ptr_target safety]
43*da0073e9SAndroid Build Coastguard Worker // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
44*da0073e9SAndroid Build Coastguard Worker // A well known problem with std::enable_shared_from_this is that it
45*da0073e9SAndroid Build Coastguard Worker // allows you to create a std::shared_ptr from a stack allocated object,
46*da0073e9SAndroid Build Coastguard Worker // which is totally bogus because the object will die once you return
47*da0073e9SAndroid Build Coastguard Worker // from the stack. In intrusive_ptr, we can detect that this has occurred,
48*da0073e9SAndroid Build Coastguard Worker // because we set the refcount/weakcount of objects which inherit from
49*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr_target to zero, *unless* we can prove that the object
50*da0073e9SAndroid Build Coastguard Worker // was dynamically allocated (e.g., via make_intrusive).
51*da0073e9SAndroid Build Coastguard Worker //
52*da0073e9SAndroid Build Coastguard Worker // Thus, whenever you transmute a T* into a intrusive_ptr<T>, we check
53*da0073e9SAndroid Build Coastguard Worker // and make sure that the refcount isn't zero (or, a more subtle
54*da0073e9SAndroid Build Coastguard Worker // test for weak_intrusive_ptr<T>, for which the refcount may validly
55*da0073e9SAndroid Build Coastguard Worker // be zero, but the weak refcount better not be zero), because that
56*da0073e9SAndroid Build Coastguard Worker // tells us if the object was allocated by us. If it wasn't, no
57*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr for you!
58*da0073e9SAndroid Build Coastguard Worker
59*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor)
60*da0073e9SAndroid Build Coastguard Worker class C10_API intrusive_ptr_target {
61*da0073e9SAndroid Build Coastguard Worker // Note [Weak references for intrusive refcounting]
62*da0073e9SAndroid Build Coastguard Worker // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63*da0073e9SAndroid Build Coastguard Worker // Here's the scheme:
64*da0073e9SAndroid Build Coastguard Worker //
65*da0073e9SAndroid Build Coastguard Worker // - refcount == number of strong references to the object
66*da0073e9SAndroid Build Coastguard Worker // weakcount == number of weak references to the object,
67*da0073e9SAndroid Build Coastguard Worker // plus one more if refcount > 0
68*da0073e9SAndroid Build Coastguard Worker // An invariant: refcount > 0 => weakcount > 0
69*da0073e9SAndroid Build Coastguard Worker //
70*da0073e9SAndroid Build Coastguard Worker // - c10::StorageImpl stays live as long as there are any strong
71*da0073e9SAndroid Build Coastguard Worker // or weak pointers to it (weakcount > 0, since strong
72*da0073e9SAndroid Build Coastguard Worker // references count as a +1 to weakcount)
73*da0073e9SAndroid Build Coastguard Worker //
74*da0073e9SAndroid Build Coastguard Worker // - finalizers are called and data_ptr is deallocated when refcount == 0
75*da0073e9SAndroid Build Coastguard Worker //
76*da0073e9SAndroid Build Coastguard Worker // - Once refcount == 0, it can never again be > 0 (the transition
77*da0073e9SAndroid Build Coastguard Worker // from > 0 to == 0 is monotonic)
78*da0073e9SAndroid Build Coastguard Worker //
79*da0073e9SAndroid Build Coastguard Worker // - When you access c10::StorageImpl via a weak pointer, you must
80*da0073e9SAndroid Build Coastguard Worker // atomically increment the use count, if it is greater than 0.
81*da0073e9SAndroid Build Coastguard Worker // If it is not, you must report that the storage is dead.
82*da0073e9SAndroid Build Coastguard Worker //
83*da0073e9SAndroid Build Coastguard Worker mutable std::atomic<uint32_t> refcount_;
84*da0073e9SAndroid Build Coastguard Worker mutable std::atomic<uint32_t> weakcount_;
85*da0073e9SAndroid Build Coastguard Worker
86*da0073e9SAndroid Build Coastguard Worker template <typename T, typename NullType>
87*da0073e9SAndroid Build Coastguard Worker friend class intrusive_ptr;
88*da0073e9SAndroid Build Coastguard Worker friend inline void raw::intrusive_ptr::incref(intrusive_ptr_target* self);
89*da0073e9SAndroid Build Coastguard Worker
90*da0073e9SAndroid Build Coastguard Worker template <typename T, typename NullType>
91*da0073e9SAndroid Build Coastguard Worker friend class weak_intrusive_ptr;
92*da0073e9SAndroid Build Coastguard Worker friend inline void raw::weak_intrusive_ptr::incref(
93*da0073e9SAndroid Build Coastguard Worker intrusive_ptr_target* self);
94*da0073e9SAndroid Build Coastguard Worker
95*da0073e9SAndroid Build Coastguard Worker template <typename T>
96*da0073e9SAndroid Build Coastguard Worker friend struct ExclusivelyOwnedTensorTraits;
97*da0073e9SAndroid Build Coastguard Worker
98*da0073e9SAndroid Build Coastguard Worker protected:
99*da0073e9SAndroid Build Coastguard Worker // protected destructor. We never want to destruct intrusive_ptr_target*
100*da0073e9SAndroid Build Coastguard Worker // directly.
~intrusive_ptr_target()101*da0073e9SAndroid Build Coastguard Worker virtual ~intrusive_ptr_target() {
102*da0073e9SAndroid Build Coastguard Worker // Disable -Wterminate and -Wexceptions so we're allowed to use assertions
103*da0073e9SAndroid Build Coastguard Worker // (i.e. throw exceptions) in a destructor.
104*da0073e9SAndroid Build Coastguard Worker // We also have to disable -Wunknown-warning-option and -Wpragmas, because
105*da0073e9SAndroid Build Coastguard Worker // some other compilers don't know about -Wterminate or -Wexceptions and
106*da0073e9SAndroid Build Coastguard Worker // will show a warning about unknown warning options otherwise.
107*da0073e9SAndroid Build Coastguard Worker #if defined(_MSC_VER) && !defined(__clang__)
108*da0073e9SAndroid Build Coastguard Worker #pragma warning(push)
109*da0073e9SAndroid Build Coastguard Worker #pragma warning( \
110*da0073e9SAndroid Build Coastguard Worker disable : 4297) // function assumed not to throw an exception but does
111*da0073e9SAndroid Build Coastguard Worker #else
112*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic push
113*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wpragmas"
114*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wunknown-warning-option"
115*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wterminate"
116*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wexceptions"
117*da0073e9SAndroid Build Coastguard Worker #endif
118*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
119*da0073e9SAndroid Build Coastguard Worker // Second condition is there to accommodate
120*da0073e9SAndroid Build Coastguard Worker // unsafe_adapt_non_heap_allocated: since we are doing our own
121*da0073e9SAndroid Build Coastguard Worker // deallocation in that case, it is correct for each
122*da0073e9SAndroid Build Coastguard Worker // expected_decref to have happened (some user code tried to
123*da0073e9SAndroid Build Coastguard Worker // decref and thus free the object, but it didn't happen right
124*da0073e9SAndroid Build Coastguard Worker // away) or not (no user code tried to free the object, and
125*da0073e9SAndroid Build Coastguard Worker // now it's getting destroyed through whatever mechanism the
126*da0073e9SAndroid Build Coastguard Worker // caller of unsafe_adapt_non_heap_allocated wanted to
127*da0073e9SAndroid Build Coastguard Worker // use). We choose our reference count such that the count
128*da0073e9SAndroid Build Coastguard Worker // will not dip below kImpracticallyHugeReferenceCount regardless.
129*da0073e9SAndroid Build Coastguard Worker refcount_.load() == 0 ||
130*da0073e9SAndroid Build Coastguard Worker refcount_.load() >= detail::kImpracticallyHugeReferenceCount,
131*da0073e9SAndroid Build Coastguard Worker "Tried to destruct an intrusive_ptr_target that still has intrusive_ptr to it; refcount was ",
132*da0073e9SAndroid Build Coastguard Worker refcount_.load());
133*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
134*da0073e9SAndroid Build Coastguard Worker // See ~intrusive_ptr for optimization that will frequently result in 1
135*da0073e9SAndroid Build Coastguard Worker // at destruction time.
136*da0073e9SAndroid Build Coastguard Worker weakcount_.load() == 1 || weakcount_.load() == 0 ||
137*da0073e9SAndroid Build Coastguard Worker weakcount_.load() == detail::kImpracticallyHugeReferenceCount - 1 ||
138*da0073e9SAndroid Build Coastguard Worker weakcount_.load() == detail::kImpracticallyHugeReferenceCount,
139*da0073e9SAndroid Build Coastguard Worker "Tried to destruct an intrusive_ptr_target that still has weak_intrusive_ptr to it");
140*da0073e9SAndroid Build Coastguard Worker #if defined(_MSC_VER) && !defined(__clang__)
141*da0073e9SAndroid Build Coastguard Worker #pragma warning(pop)
142*da0073e9SAndroid Build Coastguard Worker #else
143*da0073e9SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
144*da0073e9SAndroid Build Coastguard Worker #endif
145*da0073e9SAndroid Build Coastguard Worker }
146*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr_target()147*da0073e9SAndroid Build Coastguard Worker constexpr intrusive_ptr_target() noexcept : refcount_(0), weakcount_(0) {}
148*da0073e9SAndroid Build Coastguard Worker
149*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr_target supports copy and move: but refcount and weakcount
150*da0073e9SAndroid Build Coastguard Worker // don't participate (since they are intrinsic properties of the memory
151*da0073e9SAndroid Build Coastguard Worker // location)
intrusive_ptr_target(intrusive_ptr_target &&)152*da0073e9SAndroid Build Coastguard Worker intrusive_ptr_target(intrusive_ptr_target&& /*other*/) noexcept
153*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr_target() {}
154*da0073e9SAndroid Build Coastguard Worker
155*da0073e9SAndroid Build Coastguard Worker intrusive_ptr_target& operator=(intrusive_ptr_target&& /*other*/) noexcept {
156*da0073e9SAndroid Build Coastguard Worker return *this;
157*da0073e9SAndroid Build Coastguard Worker }
158*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr_target(const intrusive_ptr_target &)159*da0073e9SAndroid Build Coastguard Worker intrusive_ptr_target(const intrusive_ptr_target& /*other*/) noexcept
160*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr_target() {}
161*da0073e9SAndroid Build Coastguard Worker
162*da0073e9SAndroid Build Coastguard Worker intrusive_ptr_target& operator=(
163*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr_target& /*other*/) noexcept {
164*da0073e9SAndroid Build Coastguard Worker return *this;
165*da0073e9SAndroid Build Coastguard Worker }
166*da0073e9SAndroid Build Coastguard Worker
167*da0073e9SAndroid Build Coastguard Worker private:
168*da0073e9SAndroid Build Coastguard Worker /**
169*da0073e9SAndroid Build Coastguard Worker * This is called when refcount reaches zero.
170*da0073e9SAndroid Build Coastguard Worker * You can override this to release expensive resources.
171*da0073e9SAndroid Build Coastguard Worker * There might still be weak references, so your object might not get
172*da0073e9SAndroid Build Coastguard Worker * destructed yet, but you can assume the object isn't used anymore,
173*da0073e9SAndroid Build Coastguard Worker * i.e. no more calls to methods or accesses to members (we just can't
174*da0073e9SAndroid Build Coastguard Worker * destruct it yet because we need the weakcount accessible).
175*da0073e9SAndroid Build Coastguard Worker *
176*da0073e9SAndroid Build Coastguard Worker * If there are no weak references (i.e. your class is about to be
177*da0073e9SAndroid Build Coastguard Worker * destructed), this function WILL NOT be called.
178*da0073e9SAndroid Build Coastguard Worker */
release_resources()179*da0073e9SAndroid Build Coastguard Worker virtual void release_resources() {}
180*da0073e9SAndroid Build Coastguard Worker };
181*da0073e9SAndroid Build Coastguard Worker
182*da0073e9SAndroid Build Coastguard Worker namespace detail {
183*da0073e9SAndroid Build Coastguard Worker template <class TTarget>
184*da0073e9SAndroid Build Coastguard Worker struct intrusive_target_default_null_type final {
singletonfinal185*da0073e9SAndroid Build Coastguard Worker static constexpr TTarget* singleton() noexcept {
186*da0073e9SAndroid Build Coastguard Worker return nullptr;
187*da0073e9SAndroid Build Coastguard Worker }
188*da0073e9SAndroid Build Coastguard Worker };
189*da0073e9SAndroid Build Coastguard Worker
190*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class ToNullType, class FromNullType>
assign_ptr_(TTarget * rhs)191*da0073e9SAndroid Build Coastguard Worker TTarget* assign_ptr_(TTarget* rhs) {
192*da0073e9SAndroid Build Coastguard Worker if (FromNullType::singleton() == rhs) {
193*da0073e9SAndroid Build Coastguard Worker return ToNullType::singleton();
194*da0073e9SAndroid Build Coastguard Worker } else {
195*da0073e9SAndroid Build Coastguard Worker return rhs;
196*da0073e9SAndroid Build Coastguard Worker }
197*da0073e9SAndroid Build Coastguard Worker }
198*da0073e9SAndroid Build Coastguard Worker
199*da0073e9SAndroid Build Coastguard Worker // Increment needs to be acquire-release to make use_count() and
200*da0073e9SAndroid Build Coastguard Worker // unique() reliable.
atomic_refcount_increment(std::atomic<uint32_t> & refcount)201*da0073e9SAndroid Build Coastguard Worker inline uint32_t atomic_refcount_increment(std::atomic<uint32_t>& refcount) {
202*da0073e9SAndroid Build Coastguard Worker return refcount.fetch_add(1, std::memory_order_acq_rel) + 1;
203*da0073e9SAndroid Build Coastguard Worker }
204*da0073e9SAndroid Build Coastguard Worker
205*da0073e9SAndroid Build Coastguard Worker // weak_use_count() is only used for testing, so we don't need it to
206*da0073e9SAndroid Build Coastguard Worker // be reliable. Relaxed should be fine.
atomic_weakcount_increment(std::atomic<uint32_t> & weakcount)207*da0073e9SAndroid Build Coastguard Worker inline uint32_t atomic_weakcount_increment(std::atomic<uint32_t>& weakcount) {
208*da0073e9SAndroid Build Coastguard Worker return weakcount.fetch_add(1, std::memory_order_relaxed) + 1;
209*da0073e9SAndroid Build Coastguard Worker }
210*da0073e9SAndroid Build Coastguard Worker
211*da0073e9SAndroid Build Coastguard Worker // Both decrements need to be acquire-release for correctness. See
212*da0073e9SAndroid Build Coastguard Worker // e.g. std::shared_ptr implementation.
atomic_refcount_decrement(std::atomic<uint32_t> & refcount)213*da0073e9SAndroid Build Coastguard Worker inline uint32_t atomic_refcount_decrement(std::atomic<uint32_t>& refcount) {
214*da0073e9SAndroid Build Coastguard Worker return refcount.fetch_sub(1, std::memory_order_acq_rel) - 1;
215*da0073e9SAndroid Build Coastguard Worker }
216*da0073e9SAndroid Build Coastguard Worker
atomic_weakcount_decrement(std::atomic<uint32_t> & weakcount)217*da0073e9SAndroid Build Coastguard Worker inline uint32_t atomic_weakcount_decrement(std::atomic<uint32_t>& weakcount) {
218*da0073e9SAndroid Build Coastguard Worker return weakcount.fetch_sub(1, std::memory_order_acq_rel) - 1;
219*da0073e9SAndroid Build Coastguard Worker }
220*da0073e9SAndroid Build Coastguard Worker
221*da0073e9SAndroid Build Coastguard Worker } // namespace detail
222*da0073e9SAndroid Build Coastguard Worker
223*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class NullType>
224*da0073e9SAndroid Build Coastguard Worker class weak_intrusive_ptr;
225*da0073e9SAndroid Build Coastguard Worker
226*da0073e9SAndroid Build Coastguard Worker template <
227*da0073e9SAndroid Build Coastguard Worker class TTarget,
228*da0073e9SAndroid Build Coastguard Worker class NullType = detail::intrusive_target_default_null_type<TTarget>>
229*da0073e9SAndroid Build Coastguard Worker class intrusive_ptr final {
230*da0073e9SAndroid Build Coastguard Worker private:
231*da0073e9SAndroid Build Coastguard Worker // the following static assert would be nice to have but it requires
232*da0073e9SAndroid Build Coastguard Worker // the target class T to be fully defined when intrusive_ptr<T> is instantiated
233*da0073e9SAndroid Build Coastguard Worker // this is a problem for classes that contain pointers to themselves
234*da0073e9SAndroid Build Coastguard Worker // static_assert(
235*da0073e9SAndroid Build Coastguard Worker // std::is_base_of<intrusive_ptr_target, TTarget>::value,
236*da0073e9SAndroid Build Coastguard Worker // "intrusive_ptr can only be used for classes that inherit from
237*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr_target.");
238*da0073e9SAndroid Build Coastguard Worker #ifndef _WIN32
239*da0073e9SAndroid Build Coastguard Worker // This static_assert triggers on MSVC
240*da0073e9SAndroid Build Coastguard Worker // error C2131: expression did not evaluate to a constant
241*da0073e9SAndroid Build Coastguard Worker static_assert(
242*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(misc-redundant-expression)
243*da0073e9SAndroid Build Coastguard Worker NullType::singleton() == NullType::singleton(),
244*da0073e9SAndroid Build Coastguard Worker "NullType must have a constexpr singleton() method");
245*da0073e9SAndroid Build Coastguard Worker #endif
246*da0073e9SAndroid Build Coastguard Worker static_assert(
247*da0073e9SAndroid Build Coastguard Worker std::is_base_of_v<
248*da0073e9SAndroid Build Coastguard Worker TTarget,
249*da0073e9SAndroid Build Coastguard Worker std::remove_pointer_t<decltype(NullType::singleton())>>,
250*da0073e9SAndroid Build Coastguard Worker "NullType::singleton() must return a element_type* pointer");
251*da0073e9SAndroid Build Coastguard Worker
252*da0073e9SAndroid Build Coastguard Worker TTarget* target_;
253*da0073e9SAndroid Build Coastguard Worker
254*da0073e9SAndroid Build Coastguard Worker template <typename T>
255*da0073e9SAndroid Build Coastguard Worker friend struct ExclusivelyOwnedTensorTraits;
256*da0073e9SAndroid Build Coastguard Worker template <class TTarget2, class NullType2>
257*da0073e9SAndroid Build Coastguard Worker friend class intrusive_ptr;
258*da0073e9SAndroid Build Coastguard Worker friend class weak_intrusive_ptr<TTarget, NullType>;
259*da0073e9SAndroid Build Coastguard Worker
260*da0073e9SAndroid Build Coastguard Worker // Make pybind11::class_ be a friend class of intrusive_ptr, so that custom
261*da0073e9SAndroid Build Coastguard Worker // smart holder in pybind11 could access the private constructor of
262*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr(T*) which took the ownership of the object. This is required
263*da0073e9SAndroid Build Coastguard Worker // by customer holder macro PYBIND11_DECLARE_HOLDER_TYPE, where it uses
264*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr(TTarget*) to initialize and take ownership of the object. For
265*da0073e9SAndroid Build Coastguard Worker // details, see
266*da0073e9SAndroid Build Coastguard Worker // https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html#custom-smart-pointers
267*da0073e9SAndroid Build Coastguard Worker template <typename, typename...>
268*da0073e9SAndroid Build Coastguard Worker friend class pybind11::class_;
269*da0073e9SAndroid Build Coastguard Worker
retain_()270*da0073e9SAndroid Build Coastguard Worker void retain_() {
271*da0073e9SAndroid Build Coastguard Worker if (target_ != NullType::singleton()) {
272*da0073e9SAndroid Build Coastguard Worker uint32_t new_refcount =
273*da0073e9SAndroid Build Coastguard Worker detail::atomic_refcount_increment(target_->refcount_);
274*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
275*da0073e9SAndroid Build Coastguard Worker new_refcount != 1,
276*da0073e9SAndroid Build Coastguard Worker "intrusive_ptr: Cannot increase refcount after it reached zero.");
277*da0073e9SAndroid Build Coastguard Worker }
278*da0073e9SAndroid Build Coastguard Worker }
279*da0073e9SAndroid Build Coastguard Worker
reset_()280*da0073e9SAndroid Build Coastguard Worker void reset_() noexcept {
281*da0073e9SAndroid Build Coastguard Worker if (target_ != NullType::singleton() &&
282*da0073e9SAndroid Build Coastguard Worker detail::atomic_refcount_decrement(target_->refcount_) == 0) {
283*da0073e9SAndroid Build Coastguard Worker // See comment above about weakcount. As long as refcount>0,
284*da0073e9SAndroid Build Coastguard Worker // weakcount is one larger than the actual number of weak references.
285*da0073e9SAndroid Build Coastguard Worker // So we need to decrement it here.
286*da0073e9SAndroid Build Coastguard Worker bool should_delete =
287*da0073e9SAndroid Build Coastguard Worker target_->weakcount_.load(std::memory_order_acquire) == 1;
288*da0073e9SAndroid Build Coastguard Worker if (!should_delete) {
289*da0073e9SAndroid Build Coastguard Worker // justification for const_cast: release_resources is basically a
290*da0073e9SAndroid Build Coastguard Worker // destructor and a destructor always mutates the object, even for const
291*da0073e9SAndroid Build Coastguard Worker // objects. NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
292*da0073e9SAndroid Build Coastguard Worker const_cast<std::remove_const_t<TTarget>*>(target_)->release_resources();
293*da0073e9SAndroid Build Coastguard Worker should_delete =
294*da0073e9SAndroid Build Coastguard Worker detail::atomic_weakcount_decrement(target_->weakcount_) == 0;
295*da0073e9SAndroid Build Coastguard Worker }
296*da0073e9SAndroid Build Coastguard Worker if (should_delete) {
297*da0073e9SAndroid Build Coastguard Worker delete target_;
298*da0073e9SAndroid Build Coastguard Worker }
299*da0073e9SAndroid Build Coastguard Worker }
300*da0073e9SAndroid Build Coastguard Worker }
301*da0073e9SAndroid Build Coastguard Worker
302*da0073e9SAndroid Build Coastguard Worker // raw pointer constructors are not public because we shouldn't make
303*da0073e9SAndroid Build Coastguard Worker // intrusive_ptr out of raw pointers except from inside the make_intrusive(),
304*da0073e9SAndroid Build Coastguard Worker // reclaim() and weak_intrusive_ptr::lock() implementations.
305*da0073e9SAndroid Build Coastguard Worker
306*da0073e9SAndroid Build Coastguard Worker // This constructor will increase the ref counter for you.
307*da0073e9SAndroid Build Coastguard Worker // This constructor will be used by the make_intrusive(), and also pybind11,
308*da0073e9SAndroid Build Coastguard Worker // which wrap the intrusive_ptr holder around the raw pointer and incref
309*da0073e9SAndroid Build Coastguard Worker // correspondingly (pybind11 requires raw pointer constructor to incref by
310*da0073e9SAndroid Build Coastguard Worker // default).
intrusive_ptr(TTarget * target)311*da0073e9SAndroid Build Coastguard Worker explicit intrusive_ptr(TTarget* target)
312*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr(target, raw::DontIncreaseRefcount{}) {
313*da0073e9SAndroid Build Coastguard Worker if (target_ != NullType::singleton()) {
314*da0073e9SAndroid Build Coastguard Worker // We just created result.target_, so we know no other thread has
315*da0073e9SAndroid Build Coastguard Worker // access to it, so we know we needn't care about memory ordering.
316*da0073e9SAndroid Build Coastguard Worker // (On x86_64, a store with memory_order_relaxed generates a plain old
317*da0073e9SAndroid Build Coastguard Worker // `mov`, whereas an atomic increment does a lock-prefixed `add`, which is
318*da0073e9SAndroid Build Coastguard Worker // much more expensive: https://godbolt.org/z/eKPzj8.)
319*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
320*da0073e9SAndroid Build Coastguard Worker target_->refcount_ == 0 && target_->weakcount_ == 0,
321*da0073e9SAndroid Build Coastguard Worker "intrusive_ptr: Newly-created target had non-zero refcounts. Does its "
322*da0073e9SAndroid Build Coastguard Worker "constructor do something strange like incref or create an "
323*da0073e9SAndroid Build Coastguard Worker "intrusive_ptr from `this`?");
324*da0073e9SAndroid Build Coastguard Worker target_->refcount_.store(1, std::memory_order_relaxed);
325*da0073e9SAndroid Build Coastguard Worker target_->weakcount_.store(1, std::memory_order_relaxed);
326*da0073e9SAndroid Build Coastguard Worker }
327*da0073e9SAndroid Build Coastguard Worker }
328*da0073e9SAndroid Build Coastguard Worker
329*da0073e9SAndroid Build Coastguard Worker public:
330*da0073e9SAndroid Build Coastguard Worker using element_type = TTarget;
331*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr()332*da0073e9SAndroid Build Coastguard Worker intrusive_ptr() noexcept
333*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr(NullType::singleton(), raw::DontIncreaseRefcount{}) {}
334*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr(std::nullptr_t)335*da0073e9SAndroid Build Coastguard Worker intrusive_ptr(std::nullptr_t) noexcept
336*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr(NullType::singleton(), raw::DontIncreaseRefcount{}) {}
337*da0073e9SAndroid Build Coastguard Worker
338*da0073e9SAndroid Build Coastguard Worker // This constructor will not increase the ref counter for you.
339*da0073e9SAndroid Build Coastguard Worker // We use the tagged dispatch mechanism to explicitly mark this constructor
340*da0073e9SAndroid Build Coastguard Worker // to not increase the refcount
intrusive_ptr(TTarget * target,raw::DontIncreaseRefcount)341*da0073e9SAndroid Build Coastguard Worker explicit intrusive_ptr(TTarget* target, raw::DontIncreaseRefcount) noexcept
342*da0073e9SAndroid Build Coastguard Worker : target_(target) {}
343*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr(std::unique_ptr<TTarget> rhs)344*da0073e9SAndroid Build Coastguard Worker explicit intrusive_ptr(std::unique_ptr<TTarget> rhs) noexcept
345*da0073e9SAndroid Build Coastguard Worker : intrusive_ptr(rhs.release()) {}
346*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr(intrusive_ptr && rhs)347*da0073e9SAndroid Build Coastguard Worker intrusive_ptr(intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
348*da0073e9SAndroid Build Coastguard Worker rhs.target_ = NullType::singleton();
349*da0073e9SAndroid Build Coastguard Worker }
350*da0073e9SAndroid Build Coastguard Worker
351*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
352*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
intrusive_ptr(intrusive_ptr<From,FromNullType> && rhs)353*da0073e9SAndroid Build Coastguard Worker /* implicit */ intrusive_ptr(intrusive_ptr<From, FromNullType>&& rhs) noexcept
354*da0073e9SAndroid Build Coastguard Worker : target_(
355*da0073e9SAndroid Build Coastguard Worker detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
356*da0073e9SAndroid Build Coastguard Worker static_assert(
357*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
358*da0073e9SAndroid Build Coastguard Worker "Type mismatch. intrusive_ptr move constructor got pointer of wrong type.");
359*da0073e9SAndroid Build Coastguard Worker rhs.target_ = FromNullType::singleton();
360*da0073e9SAndroid Build Coastguard Worker }
361*da0073e9SAndroid Build Coastguard Worker
intrusive_ptr(const intrusive_ptr & rhs)362*da0073e9SAndroid Build Coastguard Worker intrusive_ptr(const intrusive_ptr& rhs) : target_(rhs.target_) {
363*da0073e9SAndroid Build Coastguard Worker retain_();
364*da0073e9SAndroid Build Coastguard Worker }
365*da0073e9SAndroid Build Coastguard Worker
366*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
intrusive_ptr(const intrusive_ptr<From,FromNullType> & rhs)367*da0073e9SAndroid Build Coastguard Worker /* implicit */ intrusive_ptr(const intrusive_ptr<From, FromNullType>& rhs)
368*da0073e9SAndroid Build Coastguard Worker : target_(
369*da0073e9SAndroid Build Coastguard Worker detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
370*da0073e9SAndroid Build Coastguard Worker static_assert(
371*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
372*da0073e9SAndroid Build Coastguard Worker "Type mismatch. intrusive_ptr copy constructor got pointer of wrong type.");
373*da0073e9SAndroid Build Coastguard Worker retain_();
374*da0073e9SAndroid Build Coastguard Worker }
375*da0073e9SAndroid Build Coastguard Worker
~intrusive_ptr()376*da0073e9SAndroid Build Coastguard Worker ~intrusive_ptr() noexcept {
377*da0073e9SAndroid Build Coastguard Worker reset_();
378*da0073e9SAndroid Build Coastguard Worker }
379*da0073e9SAndroid Build Coastguard Worker
380*da0073e9SAndroid Build Coastguard Worker intrusive_ptr& operator=(intrusive_ptr&& rhs) & noexcept {
381*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(*assign*)
382*da0073e9SAndroid Build Coastguard Worker return this->template operator= <TTarget, NullType>(std::move(rhs));
383*da0073e9SAndroid Build Coastguard Worker }
384*da0073e9SAndroid Build Coastguard Worker
385*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
386*da0073e9SAndroid Build Coastguard Worker intrusive_ptr& operator=(intrusive_ptr<From, FromNullType>&& rhs) & noexcept {
387*da0073e9SAndroid Build Coastguard Worker static_assert(
388*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
389*da0073e9SAndroid Build Coastguard Worker "Type mismatch. intrusive_ptr move assignment got pointer of wrong type.");
390*da0073e9SAndroid Build Coastguard Worker intrusive_ptr tmp = std::move(rhs);
391*da0073e9SAndroid Build Coastguard Worker swap(tmp);
392*da0073e9SAndroid Build Coastguard Worker return *this;
393*da0073e9SAndroid Build Coastguard Worker }
394*da0073e9SAndroid Build Coastguard Worker
395*da0073e9SAndroid Build Coastguard Worker // Assignment is implemented using copy and swap. That's safe for self
396*da0073e9SAndroid Build Coastguard Worker // assignment.
397*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(bugprone-unhandled-self-assignment)
398*da0073e9SAndroid Build Coastguard Worker intrusive_ptr& operator=(const intrusive_ptr& rhs) & noexcept {
399*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(*assign-operator, *assignment-signature)
400*da0073e9SAndroid Build Coastguard Worker return this->template operator= <TTarget, NullType>(rhs);
401*da0073e9SAndroid Build Coastguard Worker }
402*da0073e9SAndroid Build Coastguard Worker
403*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
404*da0073e9SAndroid Build Coastguard Worker intrusive_ptr& operator=(
405*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<From, NullType>& rhs) & noexcept {
406*da0073e9SAndroid Build Coastguard Worker static_assert(
407*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
408*da0073e9SAndroid Build Coastguard Worker "Type mismatch. intrusive_ptr copy assignment got pointer of wrong type.");
409*da0073e9SAndroid Build Coastguard Worker intrusive_ptr tmp = rhs;
410*da0073e9SAndroid Build Coastguard Worker swap(tmp);
411*da0073e9SAndroid Build Coastguard Worker return *this;
412*da0073e9SAndroid Build Coastguard Worker }
413*da0073e9SAndroid Build Coastguard Worker
get()414*da0073e9SAndroid Build Coastguard Worker TTarget* get() const noexcept {
415*da0073e9SAndroid Build Coastguard Worker return target_;
416*da0073e9SAndroid Build Coastguard Worker }
417*da0073e9SAndroid Build Coastguard Worker
418*da0073e9SAndroid Build Coastguard Worker TTarget& operator*() const noexcept {
419*da0073e9SAndroid Build Coastguard Worker return *target_;
420*da0073e9SAndroid Build Coastguard Worker }
421*da0073e9SAndroid Build Coastguard Worker
422*da0073e9SAndroid Build Coastguard Worker TTarget* operator->() const noexcept {
423*da0073e9SAndroid Build Coastguard Worker return target_;
424*da0073e9SAndroid Build Coastguard Worker }
425*da0073e9SAndroid Build Coastguard Worker
426*da0073e9SAndroid Build Coastguard Worker operator bool() const noexcept {
427*da0073e9SAndroid Build Coastguard Worker return target_ != NullType::singleton();
428*da0073e9SAndroid Build Coastguard Worker }
429*da0073e9SAndroid Build Coastguard Worker
reset()430*da0073e9SAndroid Build Coastguard Worker void reset() noexcept {
431*da0073e9SAndroid Build Coastguard Worker reset_();
432*da0073e9SAndroid Build Coastguard Worker target_ = NullType::singleton();
433*da0073e9SAndroid Build Coastguard Worker }
434*da0073e9SAndroid Build Coastguard Worker
swap(intrusive_ptr & rhs)435*da0073e9SAndroid Build Coastguard Worker void swap(intrusive_ptr& rhs) noexcept {
436*da0073e9SAndroid Build Coastguard Worker std::swap(target_, rhs.target_);
437*da0073e9SAndroid Build Coastguard Worker }
438*da0073e9SAndroid Build Coastguard Worker
439*da0073e9SAndroid Build Coastguard Worker // We do a lot of null-pointer checks in our code, good to have this be cheap.
defined()440*da0073e9SAndroid Build Coastguard Worker bool defined() const noexcept {
441*da0073e9SAndroid Build Coastguard Worker return target_ != NullType::singleton();
442*da0073e9SAndroid Build Coastguard Worker }
443*da0073e9SAndroid Build Coastguard Worker
use_count()444*da0073e9SAndroid Build Coastguard Worker uint32_t use_count() const noexcept {
445*da0073e9SAndroid Build Coastguard Worker if (target_ == NullType::singleton()) {
446*da0073e9SAndroid Build Coastguard Worker return 0;
447*da0073e9SAndroid Build Coastguard Worker }
448*da0073e9SAndroid Build Coastguard Worker return target_->refcount_.load(std::memory_order_acquire);
449*da0073e9SAndroid Build Coastguard Worker }
450*da0073e9SAndroid Build Coastguard Worker
weak_use_count()451*da0073e9SAndroid Build Coastguard Worker uint32_t weak_use_count() const noexcept {
452*da0073e9SAndroid Build Coastguard Worker if (target_ == NullType::singleton()) {
453*da0073e9SAndroid Build Coastguard Worker return 0;
454*da0073e9SAndroid Build Coastguard Worker }
455*da0073e9SAndroid Build Coastguard Worker return target_->weakcount_.load(std::memory_order_acquire);
456*da0073e9SAndroid Build Coastguard Worker }
457*da0073e9SAndroid Build Coastguard Worker
unique()458*da0073e9SAndroid Build Coastguard Worker bool unique() const noexcept {
459*da0073e9SAndroid Build Coastguard Worker return use_count() == 1;
460*da0073e9SAndroid Build Coastguard Worker }
461*da0073e9SAndroid Build Coastguard Worker
462*da0073e9SAndroid Build Coastguard Worker /**
463*da0073e9SAndroid Build Coastguard Worker * Returns an owning (!) pointer to the underlying object and makes the
464*da0073e9SAndroid Build Coastguard Worker * intrusive_ptr instance invalid. That means the refcount is not decreased.
465*da0073e9SAndroid Build Coastguard Worker * You *must* put the returned pointer back into a intrusive_ptr using
466*da0073e9SAndroid Build Coastguard Worker * intrusive_ptr::reclaim(ptr) to properly destruct it.
467*da0073e9SAndroid Build Coastguard Worker * This is helpful for C APIs.
468*da0073e9SAndroid Build Coastguard Worker */
release()469*da0073e9SAndroid Build Coastguard Worker TTarget* release() noexcept {
470*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign)
471*da0073e9SAndroid Build Coastguard Worker TTarget* result = target_;
472*da0073e9SAndroid Build Coastguard Worker target_ = NullType::singleton();
473*da0073e9SAndroid Build Coastguard Worker return result;
474*da0073e9SAndroid Build Coastguard Worker }
475*da0073e9SAndroid Build Coastguard Worker
476*da0073e9SAndroid Build Coastguard Worker /**
477*da0073e9SAndroid Build Coastguard Worker * Takes an owning pointer to TTarget* and creates an intrusive_ptr that takes
478*da0073e9SAndroid Build Coastguard Worker * over ownership. That means the refcount is not increased.
479*da0073e9SAndroid Build Coastguard Worker * This is the counter-part to intrusive_ptr::release() and the pointer
480*da0073e9SAndroid Build Coastguard Worker * passed in *must* have been created using intrusive_ptr::release().
481*da0073e9SAndroid Build Coastguard Worker */
reclaim(TTarget * owning_ptr)482*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr reclaim(TTarget* owning_ptr) {
483*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
484*da0073e9SAndroid Build Coastguard Worker owning_ptr == NullType::singleton() ||
485*da0073e9SAndroid Build Coastguard Worker owning_ptr->refcount_.load() == 0 || owning_ptr->weakcount_.load(),
486*da0073e9SAndroid Build Coastguard Worker "TTarget violates the invariant that refcount > 0 => weakcount > 0");
487*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr(owning_ptr, raw::DontIncreaseRefcount{});
488*da0073e9SAndroid Build Coastguard Worker }
489*da0073e9SAndroid Build Coastguard Worker
490*da0073e9SAndroid Build Coastguard Worker /**
491*da0073e9SAndroid Build Coastguard Worker * Takes an owning pointer to TTarget* and creates an intrusive_ptr
492*da0073e9SAndroid Build Coastguard Worker * representing a new reference, i.e. the raw pointer retains
493*da0073e9SAndroid Build Coastguard Worker * ownership.
494*da0073e9SAndroid Build Coastguard Worker */
reclaim_copy(TTarget * owning_ptr)495*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr reclaim_copy(TTarget* owning_ptr) {
496*da0073e9SAndroid Build Coastguard Worker auto ret = reclaim(owning_ptr);
497*da0073e9SAndroid Build Coastguard Worker ret.retain_();
498*da0073e9SAndroid Build Coastguard Worker return ret;
499*da0073e9SAndroid Build Coastguard Worker }
500*da0073e9SAndroid Build Coastguard Worker
501*da0073e9SAndroid Build Coastguard Worker /**
502*da0073e9SAndroid Build Coastguard Worker * Allocate a heap object with args and wrap it inside a intrusive_ptr and
503*da0073e9SAndroid Build Coastguard Worker * incref. This is a helper function to let make_intrusive() access private
504*da0073e9SAndroid Build Coastguard Worker * intrusive_ptr constructors.
505*da0073e9SAndroid Build Coastguard Worker */
506*da0073e9SAndroid Build Coastguard Worker template <class... Args>
make(Args &&...args)507*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr make(Args&&... args) {
508*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr(new TTarget(std::forward<Args>(args)...));
509*da0073e9SAndroid Build Coastguard Worker }
510*da0073e9SAndroid Build Coastguard Worker
511*da0073e9SAndroid Build Coastguard Worker /**
512*da0073e9SAndroid Build Coastguard Worker * Turn a new instance of TTarget (e.g., literally allocated
513*da0073e9SAndroid Build Coastguard Worker * using new TTarget(...) into an intrusive_ptr. If possible,
514*da0073e9SAndroid Build Coastguard Worker * use intrusive_ptr::make instead which statically guarantees
515*da0073e9SAndroid Build Coastguard Worker * that the allocation was done properly.
516*da0073e9SAndroid Build Coastguard Worker *
517*da0073e9SAndroid Build Coastguard Worker * At the moment, the only reason this method exists is because
518*da0073e9SAndroid Build Coastguard Worker * pybind11 holder types expect to be able to allocate in
519*da0073e9SAndroid Build Coastguard Worker * this way (because pybind11 handles the new allocation itself).
520*da0073e9SAndroid Build Coastguard Worker */
unsafe_steal_from_new(TTarget * raw_ptr)521*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr unsafe_steal_from_new(TTarget* raw_ptr) {
522*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr(raw_ptr);
523*da0073e9SAndroid Build Coastguard Worker }
524*da0073e9SAndroid Build Coastguard Worker
525*da0073e9SAndroid Build Coastguard Worker /**
526*da0073e9SAndroid Build Coastguard Worker * Turn an instance of TTarget that should not be reference counted
527*da0073e9SAndroid Build Coastguard Worker * (e.g., allocated into an arena with placement new) into an
528*da0073e9SAndroid Build Coastguard Worker * intrusive_ptr. This is gratuitously unsafe and should only be
529*da0073e9SAndroid Build Coastguard Worker * used if you can guarantee that the pointer will not escape and be
530*da0073e9SAndroid Build Coastguard Worker * refcounted as normal.
531*da0073e9SAndroid Build Coastguard Worker *
532*da0073e9SAndroid Build Coastguard Worker * `expected_decrefs` is a debugging parameter: it indicates the
533*da0073e9SAndroid Build Coastguard Worker * number of strong owners the intrusive_ptr_target in question is
534*da0073e9SAndroid Build Coastguard Worker * expected to get. In most use cases, this will likely be 1.
535*da0073e9SAndroid Build Coastguard Worker *
536*da0073e9SAndroid Build Coastguard Worker * The reason this method exists is for manually sharing
537*da0073e9SAndroid Build Coastguard Worker * StorageImpls across Tensors in the static runtime. It needs
538*da0073e9SAndroid Build Coastguard Worker * access to private intrusive_ptr members so that the refcounts can
539*da0073e9SAndroid Build Coastguard Worker * be initialized to custom values.
540*da0073e9SAndroid Build Coastguard Worker */
unsafe_adapt_non_heap_allocated(TTarget * raw_ptr,uint32_t expected_decrefs)541*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr unsafe_adapt_non_heap_allocated(
542*da0073e9SAndroid Build Coastguard Worker TTarget* raw_ptr,
543*da0073e9SAndroid Build Coastguard Worker uint32_t expected_decrefs) {
544*da0073e9SAndroid Build Coastguard Worker intrusive_ptr result(raw_ptr, raw::DontIncreaseRefcount{});
545*da0073e9SAndroid Build Coastguard Worker // kImpracticallyHugeReferenceCount is impractically huge for a reference
546*da0073e9SAndroid Build Coastguard Worker // count, while being in no danger of overflowing uint32_t. We actually only
547*da0073e9SAndroid Build Coastguard Worker // need to initialize the refcount to 2 -- we are just doing an unbalanced
548*da0073e9SAndroid Build Coastguard Worker // incref to prevent the non-heap-allocated target from being
549*da0073e9SAndroid Build Coastguard Worker // freed, and we are optimizing that incref by directly
550*da0073e9SAndroid Build Coastguard Worker // initializing the refcounts rather than doing an expensive
551*da0073e9SAndroid Build Coastguard Worker // atomic increment. The reason to use kImpracticallyHugeReferenceCount is
552*da0073e9SAndroid Build Coastguard Worker // to accommodate the debug assertions in ~intrusive_ptr_target.
553*da0073e9SAndroid Build Coastguard Worker #ifdef NDEBUG
554*da0073e9SAndroid Build Coastguard Worker expected_decrefs = 0;
555*da0073e9SAndroid Build Coastguard Worker #endif
556*da0073e9SAndroid Build Coastguard Worker result.target_->refcount_.store(
557*da0073e9SAndroid Build Coastguard Worker detail::kImpracticallyHugeReferenceCount + expected_decrefs,
558*da0073e9SAndroid Build Coastguard Worker std::memory_order_relaxed);
559*da0073e9SAndroid Build Coastguard Worker result.target_->weakcount_.store(
560*da0073e9SAndroid Build Coastguard Worker detail::kImpracticallyHugeReferenceCount, std::memory_order_relaxed);
561*da0073e9SAndroid Build Coastguard Worker return result;
562*da0073e9SAndroid Build Coastguard Worker }
563*da0073e9SAndroid Build Coastguard Worker
564*da0073e9SAndroid Build Coastguard Worker /**
565*da0073e9SAndroid Build Coastguard Worker * Turn a **non-owning raw pointer** to an intrusive_ptr. It is
566*da0073e9SAndroid Build Coastguard Worker * the moral equivalent of enable_shared_from_this on a shared pointer.
567*da0073e9SAndroid Build Coastguard Worker *
568*da0073e9SAndroid Build Coastguard Worker * This method is only valid for objects that are already live. If
569*da0073e9SAndroid Build Coastguard Worker * you are looking for the moral equivalent of unique_ptr<T>(T*)
570*da0073e9SAndroid Build Coastguard Worker * constructor, see steal_from_new.
571*da0073e9SAndroid Build Coastguard Worker *
572*da0073e9SAndroid Build Coastguard Worker * TODO: https://github.com/pytorch/pytorch/issues/56482
573*da0073e9SAndroid Build Coastguard Worker */
unsafe_reclaim_from_nonowning(TTarget * raw_ptr)574*da0073e9SAndroid Build Coastguard Worker static intrusive_ptr unsafe_reclaim_from_nonowning(TTarget* raw_ptr) {
575*da0073e9SAndroid Build Coastguard Worker // See Note [Stack allocated intrusive_ptr_target safety]
576*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
577*da0073e9SAndroid Build Coastguard Worker raw_ptr == NullType::singleton() || raw_ptr->refcount_.load() > 0,
578*da0073e9SAndroid Build Coastguard Worker "intrusive_ptr: Can only reclaim pointers that are owned by someone");
579*da0073e9SAndroid Build Coastguard Worker auto ptr = reclaim(raw_ptr); // doesn't increase refcount
580*da0073e9SAndroid Build Coastguard Worker ptr.retain_();
581*da0073e9SAndroid Build Coastguard Worker return ptr;
582*da0073e9SAndroid Build Coastguard Worker }
583*da0073e9SAndroid Build Coastguard Worker };
584*da0073e9SAndroid Build Coastguard Worker
585*da0073e9SAndroid Build Coastguard Worker template <
586*da0073e9SAndroid Build Coastguard Worker class TTarget,
587*da0073e9SAndroid Build Coastguard Worker class NullType = detail::intrusive_target_default_null_type<TTarget>,
588*da0073e9SAndroid Build Coastguard Worker class... Args>
make_intrusive(Args &&...args)589*da0073e9SAndroid Build Coastguard Worker inline intrusive_ptr<TTarget, NullType> make_intrusive(Args&&... args) {
590*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr<TTarget, NullType>::make(std::forward<Args>(args)...);
591*da0073e9SAndroid Build Coastguard Worker }
592*da0073e9SAndroid Build Coastguard Worker
593*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class NullType>
swap(intrusive_ptr<TTarget,NullType> & lhs,intrusive_ptr<TTarget,NullType> & rhs)594*da0073e9SAndroid Build Coastguard Worker inline void swap(
595*da0073e9SAndroid Build Coastguard Worker intrusive_ptr<TTarget, NullType>& lhs,
596*da0073e9SAndroid Build Coastguard Worker intrusive_ptr<TTarget, NullType>& rhs) noexcept {
597*da0073e9SAndroid Build Coastguard Worker lhs.swap(rhs);
598*da0073e9SAndroid Build Coastguard Worker }
599*da0073e9SAndroid Build Coastguard Worker
600*da0073e9SAndroid Build Coastguard Worker // To allow intrusive_ptr inside std::map or std::set, we need operator<
601*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
602*da0073e9SAndroid Build Coastguard Worker inline bool operator<(
603*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget1, NullType1>& lhs,
604*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
605*da0073e9SAndroid Build Coastguard Worker return lhs.get() < rhs.get();
606*da0073e9SAndroid Build Coastguard Worker }
607*da0073e9SAndroid Build Coastguard Worker
608*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
609*da0073e9SAndroid Build Coastguard Worker inline bool operator==(
610*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget1, NullType1>& lhs,
611*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
612*da0073e9SAndroid Build Coastguard Worker return lhs.get() == rhs.get();
613*da0073e9SAndroid Build Coastguard Worker }
614*da0073e9SAndroid Build Coastguard Worker
615*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1>
616*da0073e9SAndroid Build Coastguard Worker inline bool operator==(
617*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget1, NullType1>& lhs,
618*da0073e9SAndroid Build Coastguard Worker std::nullptr_t) noexcept {
619*da0073e9SAndroid Build Coastguard Worker return lhs.get() == nullptr;
620*da0073e9SAndroid Build Coastguard Worker }
621*da0073e9SAndroid Build Coastguard Worker
622*da0073e9SAndroid Build Coastguard Worker template <class TTarget2, class NullType2>
623*da0073e9SAndroid Build Coastguard Worker inline bool operator==(
624*da0073e9SAndroid Build Coastguard Worker std::nullptr_t,
625*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
626*da0073e9SAndroid Build Coastguard Worker return nullptr == rhs.get();
627*da0073e9SAndroid Build Coastguard Worker }
628*da0073e9SAndroid Build Coastguard Worker
629*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
630*da0073e9SAndroid Build Coastguard Worker inline bool operator!=(
631*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget1, NullType1>& lhs,
632*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
633*da0073e9SAndroid Build Coastguard Worker return !operator==(lhs, rhs);
634*da0073e9SAndroid Build Coastguard Worker }
635*da0073e9SAndroid Build Coastguard Worker
636*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1>
637*da0073e9SAndroid Build Coastguard Worker inline bool operator!=(
638*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget1, NullType1>& lhs,
639*da0073e9SAndroid Build Coastguard Worker std::nullptr_t) noexcept {
640*da0073e9SAndroid Build Coastguard Worker return !operator==(lhs, nullptr);
641*da0073e9SAndroid Build Coastguard Worker }
642*da0073e9SAndroid Build Coastguard Worker
643*da0073e9SAndroid Build Coastguard Worker template <class TTarget2, class NullType2>
644*da0073e9SAndroid Build Coastguard Worker inline bool operator!=(
645*da0073e9SAndroid Build Coastguard Worker std::nullptr_t,
646*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
647*da0073e9SAndroid Build Coastguard Worker return !operator==(nullptr, rhs);
648*da0073e9SAndroid Build Coastguard Worker }
649*da0073e9SAndroid Build Coastguard Worker template <typename T>
650*da0073e9SAndroid Build Coastguard Worker struct MaybeOwnedTraits<c10::intrusive_ptr<T>> {
651*da0073e9SAndroid Build Coastguard Worker using owned_type = c10::intrusive_ptr<T>;
652*da0073e9SAndroid Build Coastguard Worker using borrow_type = c10::intrusive_ptr<T>;
653*da0073e9SAndroid Build Coastguard Worker
654*da0073e9SAndroid Build Coastguard Worker static borrow_type createBorrow(const owned_type& from) {
655*da0073e9SAndroid Build Coastguard Worker return borrow_type::reclaim(from.get());
656*da0073e9SAndroid Build Coastguard Worker }
657*da0073e9SAndroid Build Coastguard Worker
658*da0073e9SAndroid Build Coastguard Worker static void assignBorrow(borrow_type& lhs, const borrow_type& rhs) {
659*da0073e9SAndroid Build Coastguard Worker lhs.release();
660*da0073e9SAndroid Build Coastguard Worker lhs = borrow_type::reclaim(rhs.get());
661*da0073e9SAndroid Build Coastguard Worker }
662*da0073e9SAndroid Build Coastguard Worker
663*da0073e9SAndroid Build Coastguard Worker static void destroyBorrow(borrow_type& toDestroy) {
664*da0073e9SAndroid Build Coastguard Worker toDestroy.release();
665*da0073e9SAndroid Build Coastguard Worker }
666*da0073e9SAndroid Build Coastguard Worker
667*da0073e9SAndroid Build Coastguard Worker static const owned_type& referenceFromBorrow(const borrow_type& borrow) {
668*da0073e9SAndroid Build Coastguard Worker return borrow;
669*da0073e9SAndroid Build Coastguard Worker }
670*da0073e9SAndroid Build Coastguard Worker
671*da0073e9SAndroid Build Coastguard Worker static const owned_type* pointerFromBorrow(const borrow_type& borrow) {
672*da0073e9SAndroid Build Coastguard Worker return &borrow;
673*da0073e9SAndroid Build Coastguard Worker }
674*da0073e9SAndroid Build Coastguard Worker
675*da0073e9SAndroid Build Coastguard Worker static bool debugBorrowIsValid(const borrow_type& /*borrow*/) {
676*da0073e9SAndroid Build Coastguard Worker return true;
677*da0073e9SAndroid Build Coastguard Worker }
678*da0073e9SAndroid Build Coastguard Worker };
679*da0073e9SAndroid Build Coastguard Worker
680*da0073e9SAndroid Build Coastguard Worker template <
681*da0073e9SAndroid Build Coastguard Worker typename TTarget,
682*da0073e9SAndroid Build Coastguard Worker class NullType = detail::intrusive_target_default_null_type<TTarget>>
683*da0073e9SAndroid Build Coastguard Worker class weak_intrusive_ptr final {
684*da0073e9SAndroid Build Coastguard Worker private:
685*da0073e9SAndroid Build Coastguard Worker static_assert(
686*da0073e9SAndroid Build Coastguard Worker std::is_base_of_v<intrusive_ptr_target, TTarget>,
687*da0073e9SAndroid Build Coastguard Worker "intrusive_ptr can only be used for classes that inherit from intrusive_ptr_target.");
688*da0073e9SAndroid Build Coastguard Worker #ifndef _WIN32
689*da0073e9SAndroid Build Coastguard Worker // This static_assert triggers on MSVC
690*da0073e9SAndroid Build Coastguard Worker // error C2131: expression did not evaluate to a constant
691*da0073e9SAndroid Build Coastguard Worker static_assert(
692*da0073e9SAndroid Build Coastguard Worker NullType::singleton() == NullType::singleton(),
693*da0073e9SAndroid Build Coastguard Worker "NullType must have a constexpr singleton() method");
694*da0073e9SAndroid Build Coastguard Worker #endif
695*da0073e9SAndroid Build Coastguard Worker static_assert(
696*da0073e9SAndroid Build Coastguard Worker std::is_base_of_v<
697*da0073e9SAndroid Build Coastguard Worker TTarget,
698*da0073e9SAndroid Build Coastguard Worker std::remove_pointer_t<decltype(NullType::singleton())>>,
699*da0073e9SAndroid Build Coastguard Worker "NullType::singleton() must return a element_type* pointer");
700*da0073e9SAndroid Build Coastguard Worker
701*da0073e9SAndroid Build Coastguard Worker TTarget* target_;
702*da0073e9SAndroid Build Coastguard Worker
703*da0073e9SAndroid Build Coastguard Worker template <class TTarget2, class NullType2>
704*da0073e9SAndroid Build Coastguard Worker friend class weak_intrusive_ptr;
705*da0073e9SAndroid Build Coastguard Worker
706*da0073e9SAndroid Build Coastguard Worker void retain_() {
707*da0073e9SAndroid Build Coastguard Worker if (target_ != NullType::singleton()) {
708*da0073e9SAndroid Build Coastguard Worker uint32_t new_weakcount =
709*da0073e9SAndroid Build Coastguard Worker detail::atomic_weakcount_increment(target_->weakcount_);
710*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
711*da0073e9SAndroid Build Coastguard Worker new_weakcount != 1,
712*da0073e9SAndroid Build Coastguard Worker "weak_intrusive_ptr: Cannot increase weakcount after it reached zero.");
713*da0073e9SAndroid Build Coastguard Worker }
714*da0073e9SAndroid Build Coastguard Worker }
715*da0073e9SAndroid Build Coastguard Worker
716*da0073e9SAndroid Build Coastguard Worker void reset_() noexcept {
717*da0073e9SAndroid Build Coastguard Worker if (target_ != NullType::singleton() &&
718*da0073e9SAndroid Build Coastguard Worker detail::atomic_weakcount_decrement(target_->weakcount_) == 0) {
719*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDelete)
720*da0073e9SAndroid Build Coastguard Worker delete target_;
721*da0073e9SAndroid Build Coastguard Worker }
722*da0073e9SAndroid Build Coastguard Worker target_ = NullType::singleton();
723*da0073e9SAndroid Build Coastguard Worker }
724*da0073e9SAndroid Build Coastguard Worker
725*da0073e9SAndroid Build Coastguard Worker constexpr explicit weak_intrusive_ptr(TTarget* target) : target_(target) {}
726*da0073e9SAndroid Build Coastguard Worker
727*da0073e9SAndroid Build Coastguard Worker public:
728*da0073e9SAndroid Build Coastguard Worker using element_type = TTarget;
729*da0073e9SAndroid Build Coastguard Worker
730*da0073e9SAndroid Build Coastguard Worker explicit weak_intrusive_ptr(const intrusive_ptr<TTarget, NullType>& ptr)
731*da0073e9SAndroid Build Coastguard Worker : weak_intrusive_ptr(ptr.get()) {
732*da0073e9SAndroid Build Coastguard Worker retain_();
733*da0073e9SAndroid Build Coastguard Worker }
734*da0073e9SAndroid Build Coastguard Worker
735*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr(weak_intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
736*da0073e9SAndroid Build Coastguard Worker rhs.target_ = NullType::singleton();
737*da0073e9SAndroid Build Coastguard Worker }
738*da0073e9SAndroid Build Coastguard Worker
739*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
740*da0073e9SAndroid Build Coastguard Worker /* implicit */ weak_intrusive_ptr(
741*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
742*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr<From, FromNullType>&& rhs) noexcept
743*da0073e9SAndroid Build Coastguard Worker : target_(
744*da0073e9SAndroid Build Coastguard Worker detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
745*da0073e9SAndroid Build Coastguard Worker static_assert(
746*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
747*da0073e9SAndroid Build Coastguard Worker "Type mismatch. weak_intrusive_ptr move constructor got pointer of wrong type.");
748*da0073e9SAndroid Build Coastguard Worker rhs.target_ = FromNullType::singleton();
749*da0073e9SAndroid Build Coastguard Worker }
750*da0073e9SAndroid Build Coastguard Worker
751*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr(const weak_intrusive_ptr& rhs) : target_(rhs.target_) {
752*da0073e9SAndroid Build Coastguard Worker retain_();
753*da0073e9SAndroid Build Coastguard Worker }
754*da0073e9SAndroid Build Coastguard Worker
755*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
756*da0073e9SAndroid Build Coastguard Worker /* implicit */ weak_intrusive_ptr(
757*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<From, FromNullType>& rhs)
758*da0073e9SAndroid Build Coastguard Worker : target_(
759*da0073e9SAndroid Build Coastguard Worker detail::assign_ptr_<TTarget, NullType, FromNullType>(rhs.target_)) {
760*da0073e9SAndroid Build Coastguard Worker static_assert(
761*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
762*da0073e9SAndroid Build Coastguard Worker "Type mismatch. weak_intrusive_ptr copy constructor got pointer of wrong type.");
763*da0073e9SAndroid Build Coastguard Worker retain_();
764*da0073e9SAndroid Build Coastguard Worker }
765*da0073e9SAndroid Build Coastguard Worker
766*da0073e9SAndroid Build Coastguard Worker ~weak_intrusive_ptr() noexcept {
767*da0073e9SAndroid Build Coastguard Worker reset_();
768*da0073e9SAndroid Build Coastguard Worker }
769*da0073e9SAndroid Build Coastguard Worker
770*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr& operator=(weak_intrusive_ptr&& rhs) & noexcept {
771*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(*assign*)
772*da0073e9SAndroid Build Coastguard Worker return this->template operator= <TTarget, NullType>(std::move(rhs));
773*da0073e9SAndroid Build Coastguard Worker }
774*da0073e9SAndroid Build Coastguard Worker
775*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
776*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr& operator=(
777*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr<From, FromNullType>&& rhs) & noexcept {
778*da0073e9SAndroid Build Coastguard Worker static_assert(
779*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
780*da0073e9SAndroid Build Coastguard Worker "Type mismatch. weak_intrusive_ptr move assignment got pointer of wrong type.");
781*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr tmp = std::move(rhs);
782*da0073e9SAndroid Build Coastguard Worker swap(tmp);
783*da0073e9SAndroid Build Coastguard Worker return *this;
784*da0073e9SAndroid Build Coastguard Worker }
785*da0073e9SAndroid Build Coastguard Worker
786*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr& operator=(const weak_intrusive_ptr& rhs) & noexcept {
787*da0073e9SAndroid Build Coastguard Worker if (this == &rhs) {
788*da0073e9SAndroid Build Coastguard Worker return *this;
789*da0073e9SAndroid Build Coastguard Worker }
790*da0073e9SAndroid Build Coastguard Worker // NOLINTNEXTLINE(*assign*)
791*da0073e9SAndroid Build Coastguard Worker return this->template operator= <TTarget, NullType>(rhs);
792*da0073e9SAndroid Build Coastguard Worker }
793*da0073e9SAndroid Build Coastguard Worker
794*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr& operator=(
795*da0073e9SAndroid Build Coastguard Worker const intrusive_ptr<TTarget, NullType>& rhs) & noexcept {
796*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr tmp(rhs);
797*da0073e9SAndroid Build Coastguard Worker swap(tmp);
798*da0073e9SAndroid Build Coastguard Worker return *this;
799*da0073e9SAndroid Build Coastguard Worker }
800*da0073e9SAndroid Build Coastguard Worker
801*da0073e9SAndroid Build Coastguard Worker template <class From, class FromNullType>
802*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr& operator=(
803*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<From, NullType>& rhs) & noexcept {
804*da0073e9SAndroid Build Coastguard Worker static_assert(
805*da0073e9SAndroid Build Coastguard Worker std::is_convertible<From*, TTarget*>::value,
806*da0073e9SAndroid Build Coastguard Worker "Type mismatch. weak_intrusive_ptr copy assignment got pointer of wrong type.");
807*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr tmp = rhs;
808*da0073e9SAndroid Build Coastguard Worker swap(tmp);
809*da0073e9SAndroid Build Coastguard Worker return *this;
810*da0073e9SAndroid Build Coastguard Worker }
811*da0073e9SAndroid Build Coastguard Worker
812*da0073e9SAndroid Build Coastguard Worker void reset() noexcept {
813*da0073e9SAndroid Build Coastguard Worker reset_();
814*da0073e9SAndroid Build Coastguard Worker }
815*da0073e9SAndroid Build Coastguard Worker
816*da0073e9SAndroid Build Coastguard Worker void swap(weak_intrusive_ptr& rhs) noexcept {
817*da0073e9SAndroid Build Coastguard Worker TTarget* tmp = target_;
818*da0073e9SAndroid Build Coastguard Worker target_ = rhs.target_;
819*da0073e9SAndroid Build Coastguard Worker rhs.target_ = tmp;
820*da0073e9SAndroid Build Coastguard Worker }
821*da0073e9SAndroid Build Coastguard Worker
822*da0073e9SAndroid Build Coastguard Worker // NB: This should ONLY be used by the std::hash implementation
823*da0073e9SAndroid Build Coastguard Worker // for weak_intrusive_ptr. Another way you could do this is
824*da0073e9SAndroid Build Coastguard Worker // friend std::hash<weak_intrusive_ptr>, but this triggers two
825*da0073e9SAndroid Build Coastguard Worker // bugs:
826*da0073e9SAndroid Build Coastguard Worker //
827*da0073e9SAndroid Build Coastguard Worker // (1) It triggers an nvcc bug, where std::hash in a friend class
828*da0073e9SAndroid Build Coastguard Worker // declaration gets preprocessed into hash, which then cannot
829*da0073e9SAndroid Build Coastguard Worker // actually be found. The error in this case looks like:
830*da0073e9SAndroid Build Coastguard Worker //
831*da0073e9SAndroid Build Coastguard Worker // error: no template named 'hash'; did you mean 'std::hash'?
832*da0073e9SAndroid Build Coastguard Worker //
833*da0073e9SAndroid Build Coastguard Worker // (2) On OS X, std::hash is declared as a struct, not a class.
834*da0073e9SAndroid Build Coastguard Worker // This twings:
835*da0073e9SAndroid Build Coastguard Worker //
836*da0073e9SAndroid Build Coastguard Worker // error: class 'hash' was previously declared as a struct
837*da0073e9SAndroid Build Coastguard Worker // [-Werror,-Wmismatched-tags]
838*da0073e9SAndroid Build Coastguard Worker //
839*da0073e9SAndroid Build Coastguard Worker // Both of these are work-aroundable, but on the whole, I decided
840*da0073e9SAndroid Build Coastguard Worker // it would be simpler and easier to make work if we just expose
841*da0073e9SAndroid Build Coastguard Worker // an unsafe getter for target_
842*da0073e9SAndroid Build Coastguard Worker //
843*da0073e9SAndroid Build Coastguard Worker TTarget* _unsafe_get_target() const noexcept {
844*da0073e9SAndroid Build Coastguard Worker return target_;
845*da0073e9SAndroid Build Coastguard Worker }
846*da0073e9SAndroid Build Coastguard Worker
847*da0073e9SAndroid Build Coastguard Worker uint32_t use_count() const noexcept {
848*da0073e9SAndroid Build Coastguard Worker if (target_ == NullType::singleton()) {
849*da0073e9SAndroid Build Coastguard Worker return 0;
850*da0073e9SAndroid Build Coastguard Worker }
851*da0073e9SAndroid Build Coastguard Worker return target_->refcount_.load(
852*da0073e9SAndroid Build Coastguard Worker std::memory_order_acquire); // refcount, not weakcount!
853*da0073e9SAndroid Build Coastguard Worker }
854*da0073e9SAndroid Build Coastguard Worker
855*da0073e9SAndroid Build Coastguard Worker uint32_t weak_use_count() const noexcept {
856*da0073e9SAndroid Build Coastguard Worker if (target_ == NullType::singleton()) {
857*da0073e9SAndroid Build Coastguard Worker return 0;
858*da0073e9SAndroid Build Coastguard Worker }
859*da0073e9SAndroid Build Coastguard Worker return target_->weakcount_.load(std::memory_order_acquire);
860*da0073e9SAndroid Build Coastguard Worker }
861*da0073e9SAndroid Build Coastguard Worker
862*da0073e9SAndroid Build Coastguard Worker bool expired() const noexcept {
863*da0073e9SAndroid Build Coastguard Worker return use_count() == 0;
864*da0073e9SAndroid Build Coastguard Worker }
865*da0073e9SAndroid Build Coastguard Worker
866*da0073e9SAndroid Build Coastguard Worker intrusive_ptr<TTarget, NullType> lock() const noexcept {
867*da0073e9SAndroid Build Coastguard Worker if (expired()) {
868*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr<TTarget, NullType>();
869*da0073e9SAndroid Build Coastguard Worker } else {
870*da0073e9SAndroid Build Coastguard Worker auto refcount = target_->refcount_.load(std::memory_order_seq_cst);
871*da0073e9SAndroid Build Coastguard Worker do {
872*da0073e9SAndroid Build Coastguard Worker if (refcount == 0) {
873*da0073e9SAndroid Build Coastguard Worker // Object already destructed, no strong references left anymore.
874*da0073e9SAndroid Build Coastguard Worker // Return nullptr.
875*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr<TTarget, NullType>();
876*da0073e9SAndroid Build Coastguard Worker }
877*da0073e9SAndroid Build Coastguard Worker } while (
878*da0073e9SAndroid Build Coastguard Worker !target_->refcount_.compare_exchange_weak(refcount, refcount + 1));
879*da0073e9SAndroid Build Coastguard Worker return intrusive_ptr<TTarget, NullType>(
880*da0073e9SAndroid Build Coastguard Worker target_, raw::DontIncreaseRefcount{});
881*da0073e9SAndroid Build Coastguard Worker }
882*da0073e9SAndroid Build Coastguard Worker }
883*da0073e9SAndroid Build Coastguard Worker
884*da0073e9SAndroid Build Coastguard Worker /**
885*da0073e9SAndroid Build Coastguard Worker * Returns an owning (but still only weakly referenced) pointer to the
886*da0073e9SAndroid Build Coastguard Worker * underlying object and makes the weak_intrusive_ptr instance invalid.
887*da0073e9SAndroid Build Coastguard Worker * That means the weakcount is not decreased.
888*da0073e9SAndroid Build Coastguard Worker * You *must* put the returned pointer back into a weak_intrusive_ptr using
889*da0073e9SAndroid Build Coastguard Worker * weak_intrusive_ptr::reclaim(ptr) to properly destruct it.
890*da0073e9SAndroid Build Coastguard Worker * This is helpful for C APIs.
891*da0073e9SAndroid Build Coastguard Worker */
892*da0073e9SAndroid Build Coastguard Worker TTarget* release() noexcept {
893*da0073e9SAndroid Build Coastguard Worker TTarget* result = target_;
894*da0073e9SAndroid Build Coastguard Worker target_ = NullType::singleton();
895*da0073e9SAndroid Build Coastguard Worker return result;
896*da0073e9SAndroid Build Coastguard Worker }
897*da0073e9SAndroid Build Coastguard Worker
898*da0073e9SAndroid Build Coastguard Worker /**
899*da0073e9SAndroid Build Coastguard Worker * Takes an owning (but must be weakly referenced) pointer to TTarget* and
900*da0073e9SAndroid Build Coastguard Worker * creates a weak_intrusive_ptr that takes over ownership.
901*da0073e9SAndroid Build Coastguard Worker * This means that the weakcount is not increased.
902*da0073e9SAndroid Build Coastguard Worker * This is the counter-part to weak_intrusive_ptr::release() and the pointer
903*da0073e9SAndroid Build Coastguard Worker * passed in *must* have been created using weak_intrusive_ptr::release().
904*da0073e9SAndroid Build Coastguard Worker */
905*da0073e9SAndroid Build Coastguard Worker static weak_intrusive_ptr reclaim(TTarget* owning_weak_ptr) {
906*da0073e9SAndroid Build Coastguard Worker // See Note [Stack allocated intrusive_ptr_target safety]
907*da0073e9SAndroid Build Coastguard Worker // if refcount > 0, weakcount must be >1 for weak references to exist.
908*da0073e9SAndroid Build Coastguard Worker // see weak counting explanation at top of this file.
909*da0073e9SAndroid Build Coastguard Worker // if refcount == 0, weakcount only must be >0.
910*da0073e9SAndroid Build Coastguard Worker TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
911*da0073e9SAndroid Build Coastguard Worker owning_weak_ptr == NullType::singleton() ||
912*da0073e9SAndroid Build Coastguard Worker owning_weak_ptr->weakcount_.load() > 1 ||
913*da0073e9SAndroid Build Coastguard Worker (owning_weak_ptr->refcount_.load() == 0 &&
914*da0073e9SAndroid Build Coastguard Worker owning_weak_ptr->weakcount_.load() > 0),
915*da0073e9SAndroid Build Coastguard Worker "weak_intrusive_ptr: Can only weak_intrusive_ptr::reclaim() owning pointers that were created using weak_intrusive_ptr::release().");
916*da0073e9SAndroid Build Coastguard Worker return weak_intrusive_ptr(owning_weak_ptr);
917*da0073e9SAndroid Build Coastguard Worker }
918*da0073e9SAndroid Build Coastguard Worker
919*da0073e9SAndroid Build Coastguard Worker /**
920*da0073e9SAndroid Build Coastguard Worker * Takes a pointer to TTarget* (may be weak or strong) and creates a
921*da0073e9SAndroid Build Coastguard Worker * new weak_intrusive_ptr representing a new weak reference, i.e.
922*da0073e9SAndroid Build Coastguard Worker * the raw pointer retains ownership.
923*da0073e9SAndroid Build Coastguard Worker */
924*da0073e9SAndroid Build Coastguard Worker static weak_intrusive_ptr reclaim_copy(TTarget* owning_ptr) {
925*da0073e9SAndroid Build Coastguard Worker auto ret = reclaim(owning_ptr);
926*da0073e9SAndroid Build Coastguard Worker ret.retain_();
927*da0073e9SAndroid Build Coastguard Worker return ret;
928*da0073e9SAndroid Build Coastguard Worker }
929*da0073e9SAndroid Build Coastguard Worker
930*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
931*da0073e9SAndroid Build Coastguard Worker friend bool operator<(
932*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget1, NullType1>& lhs,
933*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept;
934*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
935*da0073e9SAndroid Build Coastguard Worker friend bool operator==(
936*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget1, NullType1>& lhs,
937*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept;
938*da0073e9SAndroid Build Coastguard Worker };
939*da0073e9SAndroid Build Coastguard Worker
940*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class NullType>
941*da0073e9SAndroid Build Coastguard Worker inline void swap(
942*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr<TTarget, NullType>& lhs,
943*da0073e9SAndroid Build Coastguard Worker weak_intrusive_ptr<TTarget, NullType>& rhs) noexcept {
944*da0073e9SAndroid Build Coastguard Worker lhs.swap(rhs);
945*da0073e9SAndroid Build Coastguard Worker }
946*da0073e9SAndroid Build Coastguard Worker
947*da0073e9SAndroid Build Coastguard Worker // To allow weak_intrusive_ptr inside std::map or std::set, we need operator<
948*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
949*da0073e9SAndroid Build Coastguard Worker inline bool operator<(
950*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget1, NullType1>& lhs,
951*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
952*da0073e9SAndroid Build Coastguard Worker return lhs.target_ < rhs.target_;
953*da0073e9SAndroid Build Coastguard Worker }
954*da0073e9SAndroid Build Coastguard Worker
955*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
956*da0073e9SAndroid Build Coastguard Worker inline bool operator==(
957*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget1, NullType1>& lhs,
958*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
959*da0073e9SAndroid Build Coastguard Worker return lhs.target_ == rhs.target_;
960*da0073e9SAndroid Build Coastguard Worker }
961*da0073e9SAndroid Build Coastguard Worker
962*da0073e9SAndroid Build Coastguard Worker template <class TTarget1, class NullType1, class TTarget2, class NullType2>
963*da0073e9SAndroid Build Coastguard Worker inline bool operator!=(
964*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget1, NullType1>& lhs,
965*da0073e9SAndroid Build Coastguard Worker const weak_intrusive_ptr<TTarget2, NullType2>& rhs) noexcept {
966*da0073e9SAndroid Build Coastguard Worker return !operator==(lhs, rhs);
967*da0073e9SAndroid Build Coastguard Worker }
968*da0073e9SAndroid Build Coastguard Worker
969*da0073e9SAndroid Build Coastguard Worker // Alias for documentary purposes, to more easily distinguish
970*da0073e9SAndroid Build Coastguard Worker // weak raw intrusive pointers from intrusive pointers.
971*da0073e9SAndroid Build Coastguard Worker using weak_intrusive_ptr_target = intrusive_ptr_target;
972*da0073e9SAndroid Build Coastguard Worker
973*da0073e9SAndroid Build Coastguard Worker // This namespace provides some methods for working with
974*da0073e9SAndroid Build Coastguard Worker // raw pointers that subclass intrusive_ptr_target. They are not provided
975*da0073e9SAndroid Build Coastguard Worker // as methods on intrusive_ptr_target, because ideally you would not need these
976*da0073e9SAndroid Build Coastguard Worker // methods at all (use smart pointers), but if you are dealing with legacy code
977*da0073e9SAndroid Build Coastguard Worker // that still needs to pass around raw pointers, you may find these quite
978*da0073e9SAndroid Build Coastguard Worker // useful.
979*da0073e9SAndroid Build Coastguard Worker //
980*da0073e9SAndroid Build Coastguard Worker // An important usage note: some functions are only valid if you have a
981*da0073e9SAndroid Build Coastguard Worker // strong raw pointer to the object, while others are only valid if you
982*da0073e9SAndroid Build Coastguard Worker // have a weak raw pointer to the object. ONLY call intrusive_ptr namespace
983*da0073e9SAndroid Build Coastguard Worker // functions on strong pointers, and weak_intrusive_ptr namespace functions
984*da0073e9SAndroid Build Coastguard Worker // on weak pointers. If you mix it up, you may get an assert failure.
985*da0073e9SAndroid Build Coastguard Worker namespace raw {
986*da0073e9SAndroid Build Coastguard Worker
987*da0073e9SAndroid Build Coastguard Worker namespace intrusive_ptr {
988*da0073e9SAndroid Build Coastguard Worker
989*da0073e9SAndroid Build Coastguard Worker // WARNING: Unlike the reclaim() API, it is NOT valid to pass
990*da0073e9SAndroid Build Coastguard Worker // NullType::singleton to this function
991*da0073e9SAndroid Build Coastguard Worker inline void incref(intrusive_ptr_target* self) {
992*da0073e9SAndroid Build Coastguard Worker if (self) {
993*da0073e9SAndroid Build Coastguard Worker detail::atomic_refcount_increment(self->refcount_);
994*da0073e9SAndroid Build Coastguard Worker }
995*da0073e9SAndroid Build Coastguard Worker }
996*da0073e9SAndroid Build Coastguard Worker
997*da0073e9SAndroid Build Coastguard Worker // WARNING: Unlike the reclaim() API, it is NOT valid to pass
998*da0073e9SAndroid Build Coastguard Worker // NullType::singleton to this function
999*da0073e9SAndroid Build Coastguard Worker inline void decref(intrusive_ptr_target* self) {
1000*da0073e9SAndroid Build Coastguard Worker // Let it die
1001*da0073e9SAndroid Build Coastguard Worker c10::intrusive_ptr<intrusive_ptr_target>::reclaim(self);
1002*da0073e9SAndroid Build Coastguard Worker // NB: Caller still has 'self' pointer, but it's now invalid.
1003*da0073e9SAndroid Build Coastguard Worker // If you want more safety, used the actual c10::intrusive_ptr class
1004*da0073e9SAndroid Build Coastguard Worker }
1005*da0073e9SAndroid Build Coastguard Worker
1006*da0073e9SAndroid Build Coastguard Worker template <typename T>
1007*da0073e9SAndroid Build Coastguard Worker inline T* make_weak(T* self) {
1008*da0073e9SAndroid Build Coastguard Worker // NB: 'this' is a strong pointer, but we return a weak pointer
1009*da0073e9SAndroid Build Coastguard Worker auto ptr = c10::intrusive_ptr<T>::reclaim(self);
1010*da0073e9SAndroid Build Coastguard Worker c10::weak_intrusive_ptr<T> wptr(ptr);
1011*da0073e9SAndroid Build Coastguard Worker ptr.release();
1012*da0073e9SAndroid Build Coastguard Worker return wptr.release();
1013*da0073e9SAndroid Build Coastguard Worker }
1014*da0073e9SAndroid Build Coastguard Worker
1015*da0073e9SAndroid Build Coastguard Worker inline uint32_t use_count(intrusive_ptr_target* self) {
1016*da0073e9SAndroid Build Coastguard Worker auto ptr = c10::intrusive_ptr<intrusive_ptr_target>::reclaim(self);
1017*da0073e9SAndroid Build Coastguard Worker auto r = ptr.use_count();
1018*da0073e9SAndroid Build Coastguard Worker ptr.release();
1019*da0073e9SAndroid Build Coastguard Worker return r;
1020*da0073e9SAndroid Build Coastguard Worker }
1021*da0073e9SAndroid Build Coastguard Worker
1022*da0073e9SAndroid Build Coastguard Worker } // namespace intrusive_ptr
1023*da0073e9SAndroid Build Coastguard Worker
1024*da0073e9SAndroid Build Coastguard Worker namespace weak_intrusive_ptr {
1025*da0073e9SAndroid Build Coastguard Worker
1026*da0073e9SAndroid Build Coastguard Worker inline void incref(weak_intrusive_ptr_target* self) {
1027*da0073e9SAndroid Build Coastguard Worker detail::atomic_weakcount_increment(self->weakcount_);
1028*da0073e9SAndroid Build Coastguard Worker }
1029*da0073e9SAndroid Build Coastguard Worker
1030*da0073e9SAndroid Build Coastguard Worker inline void decref(weak_intrusive_ptr_target* self) {
1031*da0073e9SAndroid Build Coastguard Worker // Let it die
1032*da0073e9SAndroid Build Coastguard Worker c10::weak_intrusive_ptr<intrusive_ptr_target>::reclaim(self);
1033*da0073e9SAndroid Build Coastguard Worker // NB: You still "have" the 'self' pointer, but it's now invalid.
1034*da0073e9SAndroid Build Coastguard Worker // If you want more safety, used the actual c10::weak_intrusive_ptr class
1035*da0073e9SAndroid Build Coastguard Worker }
1036*da0073e9SAndroid Build Coastguard Worker
1037*da0073e9SAndroid Build Coastguard Worker template <typename T>
1038*da0073e9SAndroid Build Coastguard Worker inline T* lock(T* self) {
1039*da0073e9SAndroid Build Coastguard Worker auto wptr = c10::weak_intrusive_ptr<T>::reclaim(self);
1040*da0073e9SAndroid Build Coastguard Worker auto ptr = wptr.lock();
1041*da0073e9SAndroid Build Coastguard Worker wptr.release();
1042*da0073e9SAndroid Build Coastguard Worker return ptr.release();
1043*da0073e9SAndroid Build Coastguard Worker }
1044*da0073e9SAndroid Build Coastguard Worker
1045*da0073e9SAndroid Build Coastguard Worker // This gives the STRONG refcount of a WEAK pointer
1046*da0073e9SAndroid Build Coastguard Worker inline uint32_t use_count(weak_intrusive_ptr_target* self) {
1047*da0073e9SAndroid Build Coastguard Worker auto wptr = c10::weak_intrusive_ptr<intrusive_ptr_target>::reclaim(self);
1048*da0073e9SAndroid Build Coastguard Worker auto r = wptr.use_count();
1049*da0073e9SAndroid Build Coastguard Worker wptr.release();
1050*da0073e9SAndroid Build Coastguard Worker return r;
1051*da0073e9SAndroid Build Coastguard Worker }
1052*da0073e9SAndroid Build Coastguard Worker
1053*da0073e9SAndroid Build Coastguard Worker } // namespace weak_intrusive_ptr
1054*da0073e9SAndroid Build Coastguard Worker
1055*da0073e9SAndroid Build Coastguard Worker } // namespace raw
1056*da0073e9SAndroid Build Coastguard Worker
1057*da0073e9SAndroid Build Coastguard Worker } // namespace c10
1058*da0073e9SAndroid Build Coastguard Worker
1059*da0073e9SAndroid Build Coastguard Worker namespace std {
1060*da0073e9SAndroid Build Coastguard Worker // To allow intrusive_ptr and weak_intrusive_ptr inside std::unordered_map or
1061*da0073e9SAndroid Build Coastguard Worker // std::unordered_set, we need std::hash
1062*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class NullType>
1063*da0073e9SAndroid Build Coastguard Worker struct hash<c10::intrusive_ptr<TTarget, NullType>> {
1064*da0073e9SAndroid Build Coastguard Worker size_t operator()(const c10::intrusive_ptr<TTarget, NullType>& x) const {
1065*da0073e9SAndroid Build Coastguard Worker return std::hash<TTarget*>()(x.get());
1066*da0073e9SAndroid Build Coastguard Worker }
1067*da0073e9SAndroid Build Coastguard Worker };
1068*da0073e9SAndroid Build Coastguard Worker template <class TTarget, class NullType>
1069*da0073e9SAndroid Build Coastguard Worker struct hash<c10::weak_intrusive_ptr<TTarget, NullType>> {
1070*da0073e9SAndroid Build Coastguard Worker size_t operator()(const c10::weak_intrusive_ptr<TTarget, NullType>& x) const {
1071*da0073e9SAndroid Build Coastguard Worker return std::hash<TTarget*>()(x._unsafe_get_target());
1072*da0073e9SAndroid Build Coastguard Worker }
1073*da0073e9SAndroid Build Coastguard Worker };
1074*da0073e9SAndroid Build Coastguard Worker } // namespace std
1075