100.00% Lines (33/33) 100.00% Functions (13/13)
TLA Baseline Branch
Line Hits Code Line Hits Code
  1 + //
  2 + // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
  3 + // Copyright (c) 2026 Steve Gerbino
  4 + //
  5 + // Distributed under the Boost Software License, Version 1.0. (See accompanying
  6 + // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7 + //
  8 + // Official repository: https://github.com/cppalliance/corosio
  9 + //
  10 +
  11 + #ifndef BOOST_COROSIO_DETAIL_OBJECT_REF_HPP
  12 + #define BOOST_COROSIO_DETAIL_OBJECT_REF_HPP
  13 +
  14 + #include <boost/corosio/detail/platform.hpp>
  15 + #include <boost/corosio/io/io_object.hpp>
  16 + #include <atomic>
  17 + #include <utility>
  18 +
  19 + namespace boost::corosio::detail {
  20 +
  21 + /// Add one reference to `impl`. `impl` must be non-null.
  22 + inline void
HITGNC   23 + 105679 acquire(io_object::implementation* impl) noexcept
  24 + {
HITGNC   25 + 105679 impl->refs_.fetch_add(1, std::memory_order_relaxed);
HITGNC   26 + 105679 }
  27 +
  28 + /** Drop one reference; runs `retire()` at zero. `impl` must be
  29 + non-null.
  30 +
  31 + Uses release on the decrement and an acquire fence before the
  32 + zero-action so writes made while holding a reference are visible
  33 + to the recycler. TSan cannot model a standalone fence, so under
  34 + it the decrement itself is acq_rel instead -- strictly stronger,
  35 + and TSan's happens-before tracking models the exchange directly.
  36 + */
  37 + inline void
HITGNC   38 + 126004 release(io_object::implementation* impl) noexcept
  39 + {
  40 + #if BOOST_COROSIO_TSAN
  41 + if (impl->refs_.fetch_sub(1, std::memory_order_acq_rel) == 1)
  42 + impl->retire();
  43 + #else
HITGNC   44 + 252008 if (impl->refs_.fetch_sub(1, std::memory_order_release) == 1)
  45 + {
  46 + std::atomic_thread_fence(std::memory_order_acquire);
HITGNC   47 + 20325 impl->retire();
  48 + }
  49 + #endif
HITGNC   50 + 126004 }
  51 +
  52 + /** Owning intrusive reference to an I/O implementation.
  53 +
  54 + Replaces `std::shared_ptr<void>` op keepalives: copy acquires,
  55 + move steals, destruction releases. Kept deliberately minimal —
  56 + two words smaller than a shared_ptr and no control block.
  57 + */
  58 + class object_ref
  59 + {
  60 + io_object::implementation* p_ = nullptr;
  61 +
  62 + public:
  63 + /// Destroy the object_ref, releasing the held reference, if any.
HITGNC   64 + 950945 ~object_ref() { reset(); }
  65 +
  66 + /// Construct an object_ref holding no reference.
HITGNC   67 + 30938 object_ref() noexcept = default;
  68 +
  69 + /// Construct an object_ref that acquires a new reference to `p`.
HITGNC   70 + 105659 explicit object_ref(io_object::implementation* p) noexcept : p_(p)
  71 + {
HITGNC   72 + 105659 if (p_)
HITGNC   73 + 105659 acquire(p_);
HITGNC   74 + 105659 }
  75 +
  76 + /// Construct a copy, acquiring another reference to `other`'s target.
HITGNC   77 + 3 object_ref(object_ref const& other) noexcept : p_(other.p_)
  78 + {
HITGNC   79 + 3 if (p_)
HITGNC   80 + 3 acquire(p_);
HITGNC   81 + 3 }
  82 +
  83 + /// Construct by transferring the reference out of `other`.
HITGNC   84 + 511944 object_ref(object_ref&& other) noexcept
HITGNC   85 + 511944 : p_(std::exchange(other.p_, nullptr))
  86 + {
HITGNC   87 + 511944 }
  88 +
  89 + /// Release the held reference, if any, and acquire `other`'s target.
HITGNC   90 + 2 object_ref& operator=(object_ref const& other) noexcept
  91 + {
HITGNC   92 + 2 object_ref(other).swap(*this);
HITGNC   93 + 2 return *this;
  94 + }
  95 +
  96 + /// Release the held reference, if any, and take ownership of `other`'s.
HITGNC   97 + 408367 object_ref& operator=(object_ref&& other) noexcept
  98 + {
HITGNC   99 + 408367 object_ref(std::move(other)).swap(*this);
HITGNC   100 + 408367 return *this;
  101 + }
  102 +
  103 + /// Release the held reference, if any.
HITGNC   104 + 1431925 void reset() noexcept
  105 + {
HITGNC   106 + 1431925 if (p_)
HITGNC   107 + 105662 release(std::exchange(p_, nullptr));
HITGNC   108 + 1431925 }
  109 +
  110 + /// Return the held implementation pointer.
HITGNC   111 + 3 io_object::implementation* get() const noexcept { return p_; }
  112 +
  113 + /// Return true if a reference is held.
HITGNC   114 + 13452 explicit operator bool() const noexcept { return p_ != nullptr; }
  115 +
  116 + /// Exchange the implementation pointers held by `*this` and `other`.
HITGNC   117 + 408369 void swap(object_ref& other) noexcept { std::swap(p_, other.p_); }
  118 + };
  119 +
  120 + } // namespace boost::corosio::detail
  121 +
  122 + #endif