Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_RUN_SYNC_HPP
11 : #define BOOST_CAPY_RUN_SYNC_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/ex/any_coro.hpp>
15 : #include <boost/capy/task.hpp>
16 :
17 : #include <coroutine>
18 : #include <exception>
19 : #include <type_traits>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace capy {
24 :
25 : namespace detail {
26 :
27 : /** Trivial dispatcher for synchronous execution.
28 :
29 : Returns the coroutine handle directly for symmetric transfer,
30 : enabling inline execution without scheduling.
31 : */
32 : struct sync_dispatcher
33 : {
34 23 : any_coro operator()(any_coro h) const
35 : {
36 23 : return h;
37 : }
38 : };
39 :
40 : /** Synchronous task runner.
41 :
42 : Runs a coroutine task to completion on the caller's thread,
43 : returning the result directly or rethrowing any exception.
44 :
45 : This class is not intended for direct use. Use the `run_sync()`
46 : factory function instead.
47 :
48 : @par Thread Safety
49 : Not thread-safe. The task runs entirely on the calling thread.
50 :
51 : @see run_sync
52 : */
53 : class sync_runner
54 : {
55 : public:
56 : sync_runner() = default;
57 :
58 : sync_runner(sync_runner const&) = delete;
59 : sync_runner& operator=(sync_runner const&) = delete;
60 : sync_runner(sync_runner&&) = default;
61 : sync_runner& operator=(sync_runner&&) = default;
62 :
63 : /** Run a task to completion and return the result.
64 :
65 : Executes the task synchronously on the calling thread. The task
66 : runs to completion before this function returns.
67 :
68 : @par Exception Safety
69 : If the task throws an exception, it is rethrown to the caller.
70 :
71 : @param t The task to execute.
72 :
73 : @return The value returned by the task.
74 :
75 : @throws Any exception thrown by the task.
76 : */
77 : template<typename T>
78 23 : T operator()(task<T> t) &&
79 : {
80 23 : auto h = t.release();
81 : sync_dispatcher d;
82 :
83 23 : h.promise().continuation_ = std::noop_coroutine();
84 23 : h.promise().ex_ = d;
85 23 : h.promise().caller_ex_ = d;
86 23 : h.promise().needs_dispatch_ = false;
87 :
88 23 : d(any_coro{h}).resume();
89 :
90 23 : std::exception_ptr ep = h.promise().ep_;
91 :
92 : if constexpr (std::is_void_v<T>)
93 : {
94 7 : h.destroy();
95 7 : if (ep)
96 2 : std::rethrow_exception(ep);
97 : }
98 : else
99 : {
100 16 : if (ep)
101 : {
102 3 : h.destroy();
103 6 : std::rethrow_exception(ep);
104 : }
105 13 : auto& result_base = static_cast<detail::task_return_base<T>&>(
106 13 : h.promise());
107 13 : auto result = std::move(*result_base.result_);
108 13 : h.destroy();
109 15 : return result;
110 2 : }
111 23 : }
112 : };
113 :
114 : } // namespace detail
115 :
116 : /** Create a synchronous task runner.
117 :
118 : Returns a runner that executes a coroutine task to completion
119 : on the caller's thread. The task completes before this function
120 : returns, and the result is returned directly.
121 :
122 : @par Usage
123 : @code
124 : // Run a task and get the result
125 : int value = run_sync()(compute_value());
126 :
127 : // Run a void task
128 : run_sync()(do_work());
129 :
130 : // Exceptions propagate normally
131 : try {
132 : run_sync()(failing_task());
133 : } catch (std::exception const& e) {
134 : // handle error
135 : }
136 : @endcode
137 :
138 : @par Thread Safety
139 : The task runs entirely on the calling thread. No dispatcher or
140 : execution context is required.
141 :
142 : @return A runner object with `operator()(task<T>)` that returns `T`.
143 :
144 : @see task
145 : @see run_async
146 : @see run_on
147 : */
148 : inline
149 : detail::sync_runner
150 23 : run_sync()
151 : {
152 23 : return detail::sync_runner{};
153 : }
154 :
155 : } // namespace capy
156 : } // namespace boost
157 :
158 : #endif
|