Line data 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 20092 : if (handle)
32 78 : handle.destroy();
33 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 230235 : if (handle)
55 230157 : handle.destroy();
56 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 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 0 : 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 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
|