libs/corosio/src/corosio/src/detail/cached_initiator.hpp

96.2% Lines (25/26) 90.0% Functions (18/20) 100.0% Branches (11/11)
libs/corosio/src/corosio/src/detail/cached_initiator.hpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2024 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_DETAIL_CACHED_INITIATOR_HPP
11 #define BOOST_COROSIO_DETAIL_CACHED_INITIATOR_HPP
12
13 #include <coroutine>
14 #include <cstddef>
15
16 namespace boost::corosio::detail {
17
18 /** Cached initiator coroutine frame with RAII cleanup.
19
20 Manages the lifecycle of a cached coroutine frame used for I/O
21 initiator coroutines. Automatically destroys the coroutine handle
22 and frees the cached frame memory on destruction.
23 */
24 struct cached_initiator
25 {
26 void* frame = nullptr;
27 std::coroutine_handle<> handle;
28
29 20092 ~cached_initiator()
30 {
31
2/2
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 20014 times.
20092 if (handle)
32 78 handle.destroy();
33
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 20014 times.
20092 if (frame)
34 78 ::operator delete(frame);
35 20092 }
36
37 20092 cached_initiator() = default;
38 cached_initiator(cached_initiator const&) = delete;
39 cached_initiator& operator=(cached_initiator const&) = delete;
40
41 /** Start initiator coroutine that calls Fn on impl.
42
43 Destroys any existing coroutine, creates a new initiator that
44 will call the specified member function, and returns the handle
45 for symmetric transfer.
46
47 @tparam Fn Member function pointer to call (e.g., &Impl::do_read_io)
48 @param impl Pointer to the I/O object implementation
49 @return Coroutine handle for symmetric transfer
50 */
51 template<auto Fn, class Impl>
52 230235 std::coroutine_handle<> start(Impl* impl)
53 {
54
2/2
✓ Branch 1 taken 230157 times.
✓ Branch 2 taken 78 times.
230235 if (handle)
55
1/1
✓ Branch 1 taken 230157 times.
230157 handle.destroy();
56
1/1
✓ Branch 1 taken 230235 times.
230235 auto initiator = make_initiator_coro<Fn>(frame, impl);
57 230235 handle = initiator.h;
58 460470 return initiator.h;
59 }
60
61 private:
62 template<class Impl, auto Fn>
63 struct initiator_coro
64 {
65 struct promise_type
66 {
67 Impl* impl;
68
69 230235 static void* operator new(std::size_t n, void*& cached, Impl*)
70 {
71
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 230157 times.
230235 if (!cached)
72 78 cached = ::operator new(n);
73 230235 return cached;
74 }
75
76 230235 static void operator delete(void*) noexcept {}
77
78 230235 std::suspend_always initial_suspend() noexcept { return {}; }
79 230235 std::suspend_always final_suspend() noexcept { return {}; }
80
81 230235 initiator_coro get_return_object()
82 {
83 230235 return {std::coroutine_handle<promise_type>::from_promise(*this)};
84 }
85
86 230235 void return_void() {}
87 void unhandled_exception() { std::terminate(); }
88 };
89
90 using handle_type = std::coroutine_handle<promise_type>;
91 handle_type h;
92 };
93
94 template<auto Fn, class Impl>
95
1/1
✓ Branch 1 taken 230235 times.
230235 static initiator_coro<Impl, Fn> make_initiator_coro(void*&, Impl* impl)
96 {
97 (impl->*Fn)();
98 co_return;
99 460470 }
100 };
101
102 } // namespace boost::corosio::detail
103
104 #endif
105