// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // The file has been adapted from the PyTorch project. // Licensed under BSD-style license: // https://github.com/pytorch/pytorch/blob/main/LICENSE #pragma once #include #include #include #include namespace c10 { // Forward declarations class intrusive_ptr_target; namespace raw { namespace intrusive_ptr { inline void incref(intrusive_ptr_target* self); inline void decref(intrusive_ptr_target* self); } // namespace intrusive_ptr namespace weak_intrusive_ptr { inline void incref(intrusive_ptr_target* self); inline void decref(intrusive_ptr_target* self); } // namespace weak_intrusive_ptr struct DontIncreaseRefcount {}; } // namespace raw namespace detail { constexpr uint64_t kImpracticallyHugeReferenceCount = 0x0FFFFFFF; constexpr uint64_t kImpracticallyHugeWeakReferenceCount = (kImpracticallyHugeReferenceCount << 32); constexpr uint64_t kReferenceCountOne = 1; constexpr uint64_t kWeakReferenceCountOne = (kReferenceCountOne << 32); constexpr uint64_t kUniqueRef = (kReferenceCountOne | kWeakReferenceCountOne); inline uint32_t refcount(uint64_t combined_refcount) { return static_cast(combined_refcount); } inline uint32_t weakcount(uint64_t combined_refcount) { // Bit 63 is reserved for kHasPyObject in PyTorch (a flag indicating a live // Python wrapper). This compat layer does not implement the PyObject path, // so the bit will never be set, but we mask it out here to match PyTorch's // extraction logic and remain numerically correct if the bit were ever set. return static_cast((combined_refcount & ~(uint64_t(1) << 63)) >> 32); } inline uint64_t atomic_combined_refcount_increment( std::atomic* combined_refcount, uint64_t inc) { return combined_refcount->fetch_add(inc, std::memory_order_relaxed) + inc; } inline uint64_t atomic_combined_refcount_decrement( std::atomic* combined_refcount, uint64_t dec) { return combined_refcount->fetch_sub(dec, std::memory_order_acq_rel) - dec; } inline uint32_t atomic_weakcount_increment( std::atomic* combined_refcount) { return weakcount(atomic_combined_refcount_increment(combined_refcount, kWeakReferenceCountOne)); } inline uint32_t atomic_weakcount_decrement( std::atomic* combined_refcount) { return weakcount(atomic_combined_refcount_decrement(combined_refcount, kWeakReferenceCountOne)); } template struct intrusive_target_default_null_type final { static constexpr T* singleton() noexcept { return nullptr; } }; } // namespace detail class intrusive_ptr_target { public: intrusive_ptr_target() noexcept : combined_refcount_(0) {} intrusive_ptr_target(intrusive_ptr_target&& /*other*/) noexcept : intrusive_ptr_target() {} intrusive_ptr_target& operator=(intrusive_ptr_target&& /*other*/) noexcept { return *this; } intrusive_ptr_target(const intrusive_ptr_target& /*other*/) noexcept : intrusive_ptr_target() {} intrusive_ptr_target& operator=( const intrusive_ptr_target& /*other*/) noexcept { return *this; } uint32_t refcount() const { return detail::refcount(combined_refcount_.load(std::memory_order_relaxed)); } uint32_t weakcount() const { return detail::weakcount( combined_refcount_.load(std::memory_order_relaxed)); } protected: virtual ~intrusive_ptr_target() = default; private: mutable std::atomic combined_refcount_; template friend class intrusive_ptr; template friend class weak_intrusive_ptr; friend inline void raw::intrusive_ptr::incref(intrusive_ptr_target* self); friend inline void raw::intrusive_ptr::decref(intrusive_ptr_target* self); friend inline void raw::weak_intrusive_ptr::incref( intrusive_ptr_target* self); friend inline void raw::weak_intrusive_ptr::decref( intrusive_ptr_target* self); }; namespace raw { namespace intrusive_ptr { inline void incref(intrusive_ptr_target* self) { if (self) { detail::atomic_combined_refcount_increment(&self->combined_refcount_, detail::kReferenceCountOne); } } inline void decref(intrusive_ptr_target* self) { if (self) { uint64_t new_count = detail::atomic_combined_refcount_decrement( &self->combined_refcount_, detail::kReferenceCountOne); if (detail::refcount(new_count) == 0) { // All strong references gone; release the implicit weak reference // (strong refs count as +1 to weakcount per the kUniqueRef invariant). if (detail::atomic_weakcount_decrement(&self->combined_refcount_) == 0) { delete self; } } } } } // namespace intrusive_ptr namespace weak_intrusive_ptr { inline void incref(intrusive_ptr_target* self) { if (self) { detail::atomic_weakcount_increment(&self->combined_refcount_); } } inline void decref(intrusive_ptr_target* self) { if (self) { if (detail::atomic_weakcount_decrement(&self->combined_refcount_) == 0) { delete self; } } } } // namespace weak_intrusive_ptr } // namespace raw template class weak_intrusive_ptr; template > class intrusive_ptr final { private: static_assert( std::is_base_of_v>, "NullType::singleton() must return a element_type* pointer"); TTarget* target_; template friend class intrusive_ptr; friend class weak_intrusive_ptr; void retain_() noexcept { if (target_ != NullType::singleton()) { detail::atomic_combined_refcount_increment(&target_->combined_refcount_, detail::kReferenceCountOne); } } void reset_() noexcept { if (target_ != NullType::singleton()) { uint64_t new_count = detail::atomic_combined_refcount_decrement( &target_->combined_refcount_, detail::kReferenceCountOne); if (detail::refcount(new_count) == 0) { // All strong references gone; release the implicit weak reference // (strong refs count as +1 to weakcount per the kUniqueRef invariant). if (detail::atomic_weakcount_decrement(&target_->combined_refcount_) == 0) { delete target_; } } target_ = NullType::singleton(); } } public: using element_type = TTarget; using pointer = TTarget*; intrusive_ptr() noexcept : target_(NullType::singleton()) {} intrusive_ptr(std::nullptr_t) noexcept : target_(NullType::singleton()) {} explicit intrusive_ptr(TTarget* raw) : target_(raw) { if (target_ != NullType::singleton()) { target_->combined_refcount_.store(detail::kUniqueRef, std::memory_order_relaxed); } } intrusive_ptr(const intrusive_ptr& rhs) : target_(rhs.target_) { retain_(); } intrusive_ptr(intrusive_ptr&& rhs) noexcept : target_(rhs.target_) { rhs.target_ = NullType::singleton(); } template /* implicit */ intrusive_ptr( const intrusive_ptr& rhs) noexcept : target_(rhs.target_) { static_assert(std::is_convertible_v, "Source type must be convertible to target type"); retain_(); } template /* implicit */ intrusive_ptr(intrusive_ptr&& rhs) noexcept : target_(rhs.target_) { static_assert(std::is_convertible_v, "Source type must be convertible to target type"); rhs.target_ = FromNullType::singleton(); } ~intrusive_ptr() { reset_(); } intrusive_ptr& operator=(const intrusive_ptr& rhs) { if (this != &rhs) { reset_(); target_ = rhs.target_; retain_(); } return *this; } intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept { if (this != &rhs) { reset_(); target_ = rhs.target_; rhs.target_ = NullType::singleton(); } return *this; } // Takes ownership of a raw pointer without incrementing the refcount. static intrusive_ptr reclaim(TTarget* raw_ptr) { intrusive_ptr result; result.target_ = raw_ptr; return result; } // unsafe_adopt is a PyTorch API compatibility alias for reclaim(). // Both adopt a raw pointer without incrementing the refcount; prefer // reclaim() in new code. static intrusive_ptr unsafe_adopt(TTarget* raw_ptr) { return reclaim(raw_ptr); } TTarget* get() const noexcept { return target_; } TTarget& operator*() const { return *target_; } TTarget* operator->() const { return target_; } explicit operator bool() const noexcept { return target_ != NullType::singleton(); } uint32_t use_count() const noexcept { if (target_ == NullType::singleton()) { return 0; } return target_->refcount(); } bool defined() const noexcept { return target_ != NullType::singleton(); } bool unique() const noexcept { return use_count() == 1; } void reset() noexcept { reset_(); } void swap(intrusive_ptr& other) noexcept { using std::swap; swap(target_, other.target_); } [[deprecated( "intrusive_ptr::release is unsafe; use reclaim() or explicit ownership " "transfer instead")]] TTarget* release() noexcept { TTarget* result = target_; target_ = NullType::singleton(); return result; } bool operator==(const intrusive_ptr& rhs) const noexcept { return target_ == rhs.target_; } bool operator!=(const intrusive_ptr& rhs) const noexcept { return target_ != rhs.target_; } bool operator==(std::nullptr_t) const noexcept { return target_ == NullType::singleton(); } bool operator!=(std::nullptr_t) const noexcept { return target_ != NullType::singleton(); } }; template > class weak_intrusive_ptr final { private: TTarget* target_; template friend class weak_intrusive_ptr; friend class intrusive_ptr; void retain_() { if (target_ != NullType::singleton()) { detail::atomic_weakcount_increment(&target_->combined_refcount_); } } void reset_() noexcept { if (target_ != NullType::singleton()) { if (detail::atomic_weakcount_decrement(&target_->combined_refcount_) == 0) { delete target_; } target_ = NullType::singleton(); } } public: using element_type = TTarget; weak_intrusive_ptr() noexcept : target_(NullType::singleton()) {} weak_intrusive_ptr(const intrusive_ptr& p) : target_(p.target_) { retain_(); } weak_intrusive_ptr(const weak_intrusive_ptr& rhs) : target_(rhs.target_) { retain_(); } weak_intrusive_ptr(weak_intrusive_ptr&& rhs) noexcept : target_(rhs.target_) { rhs.target_ = NullType::singleton(); } ~weak_intrusive_ptr() { reset_(); } weak_intrusive_ptr& operator=(const weak_intrusive_ptr& rhs) { if (this != &rhs) { reset_(); target_ = rhs.target_; retain_(); } return *this; } weak_intrusive_ptr& operator=(weak_intrusive_ptr&& rhs) { if (this != &rhs) { reset_(); target_ = rhs.target_; rhs.target_ = NullType::singleton(); } return *this; } intrusive_ptr lock() const { if (target_ == NullType::singleton()) { return intrusive_ptr(); } auto& atomic = target_->combined_refcount_; uint64_t count = atomic.load(std::memory_order_relaxed); while (true) { if (detail::refcount(count) == 0) { return intrusive_ptr(); } if (atomic.compare_exchange_weak(count, count + detail::kReferenceCountOne, std::memory_order_acq_rel, std::memory_order_relaxed)) { return intrusive_ptr::unsafe_adopt(target_); } } } uint32_t use_count() const { if (target_ == NullType::singleton()) { return 0; } return target_->refcount(); } bool expired() const { return use_count() == 0; } void reset() { reset_(); } }; // Creates a new T with an initial strong refcount of 1. template intrusive_ptr make_intrusive(Args&&... args) { return intrusive_ptr(new T(std::forward(args)...)); } } // namespace c10