include/boost/corosio/detail/object_ref.hpp
100.0% Lines (33 / 33)
100.0% Functions (13 / 13)
Functions (13)
Function
Calls
Lines
Blocks
boost::corosio::detail::acquire(boost::corosio::io_object::implementation*)
:23
105679x
100.0%
100.0%
boost::corosio::detail::release(boost::corosio::io_object::implementation*)
:38
126004x
100.0%
100.0%
boost::corosio::detail::object_ref::~object_ref()
:64
950945x
100.0%
100.0%
boost::corosio::detail::object_ref::object_ref()
:67
30938x
100.0%
100.0%
boost::corosio::detail::object_ref::object_ref(boost::corosio::io_object::implementation*)
:70
105659x
100.0%
100.0%
boost::corosio::detail::object_ref::object_ref(boost::corosio::detail::object_ref const&)
:77
3x
100.0%
100.0%
boost::corosio::detail::object_ref::object_ref(boost::corosio::detail::object_ref&&)
:84
511944x
100.0%
100.0%
boost::corosio::detail::object_ref::operator=(boost::corosio::detail::object_ref const&)
:90
2x
100.0%
100.0%
boost::corosio::detail::object_ref::operator=(boost::corosio::detail::object_ref&&)
:97
408367x
100.0%
100.0%
boost::corosio::detail::object_ref::reset()
:104
1431925x
100.0%
100.0%
boost::corosio::detail::object_ref::get() const
:111
3x
100.0%
100.0%
boost::corosio::detail::object_ref::operator bool() const
:114
13452x
100.0%
100.0%
boost::corosio::detail::object_ref::swap(boost::corosio::detail::object_ref&)
:117
408369x
100.0%
100.0%
| Line | TLA | Hits | Source 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 | ||
| 23 | 105679x | acquire(io_object::implementation* impl) noexcept | |
| 24 | { | ||
| 25 | 105679x | impl->refs_.fetch_add(1, std::memory_order_relaxed); | |
| 26 | 105679x | } | |
| 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 | ||
| 38 | 126004x | 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 | ||
| 44 | 252008x | if (impl->refs_.fetch_sub(1, std::memory_order_release) == 1) | |
| 45 | { | ||
| 46 | std::atomic_thread_fence(std::memory_order_acquire); | ||
| 47 | 20325x | impl->retire(); | |
| 48 | } | ||
| 49 | #endif | ||
| 50 | 126004x | } | |
| 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. | ||
| 64 | 950945x | ~object_ref() { reset(); } | |
| 65 | |||
| 66 | /// Construct an object_ref holding no reference. | ||
| 67 | 30938x | object_ref() noexcept = default; | |
| 68 | |||
| 69 | /// Construct an object_ref that acquires a new reference to `p`. | ||
| 70 | 105659x | explicit object_ref(io_object::implementation* p) noexcept : p_(p) | |
| 71 | { | ||
| 72 | 105659x | if (p_) | |
| 73 | 105659x | acquire(p_); | |
| 74 | 105659x | } | |
| 75 | |||
| 76 | /// Construct a copy, acquiring another reference to `other`'s target. | ||
| 77 | 3x | object_ref(object_ref const& other) noexcept : p_(other.p_) | |
| 78 | { | ||
| 79 | 3x | if (p_) | |
| 80 | 3x | acquire(p_); | |
| 81 | 3x | } | |
| 82 | |||
| 83 | /// Construct by transferring the reference out of `other`. | ||
| 84 | 511944x | object_ref(object_ref&& other) noexcept | |
| 85 | 511944x | : p_(std::exchange(other.p_, nullptr)) | |
| 86 | { | ||
| 87 | 511944x | } | |
| 88 | |||
| 89 | /// Release the held reference, if any, and acquire `other`'s target. | ||
| 90 | 2x | object_ref& operator=(object_ref const& other) noexcept | |
| 91 | { | ||
| 92 | 2x | object_ref(other).swap(*this); | |
| 93 | 2x | return *this; | |
| 94 | } | ||
| 95 | |||
| 96 | /// Release the held reference, if any, and take ownership of `other`'s. | ||
| 97 | 408367x | object_ref& operator=(object_ref&& other) noexcept | |
| 98 | { | ||
| 99 | 408367x | object_ref(std::move(other)).swap(*this); | |
| 100 | 408367x | return *this; | |
| 101 | } | ||
| 102 | |||
| 103 | /// Release the held reference, if any. | ||
| 104 | 1431925x | void reset() noexcept | |
| 105 | { | ||
| 106 | 1431925x | if (p_) | |
| 107 | 105662x | release(std::exchange(p_, nullptr)); | |
| 108 | 1431925x | } | |
| 109 | |||
| 110 | /// Return the held implementation pointer. | ||
| 111 | 3x | io_object::implementation* get() const noexcept { return p_; } | |
| 112 | |||
| 113 | /// Return true if a reference is held. | ||
| 114 | 13452x | explicit operator bool() const noexcept { return p_ != nullptr; } | |
| 115 | |||
| 116 | /// Exchange the implementation pointers held by `*this` and `other`. | ||
| 117 | 408369x | void swap(object_ref& other) noexcept { std::swap(p_, other.p_); } | |
| 118 | }; | ||
| 119 | |||
| 120 | } // namespace boost::corosio::detail | ||
| 121 | |||
| 122 | #endif | ||
| 123 |