GCC Code Coverage Report


Directory: ./
File: libs/capy/include/boost/capy/ex/executor_work_guard.hpp
Date: 2026-01-15 20:40:20
Exec Total Coverage
Lines: 31 31 100.0%
Functions: 8 8 100.0%
Branches: 6 6 100.0%

Line Branch Exec Source
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_EXECUTOR_WORK_GUARD_HPP
11 #define BOOST_CAPY_EXECUTOR_WORK_GUARD_HPP
12
13 #include <boost/capy/detail/config.hpp>
14 #include <boost/capy/ex/execution_context.hpp>
15 #include <boost/capy/concept/executor.hpp>
16
17 #include <utility>
18
19 namespace boost {
20 namespace capy {
21
22 /** RAII guard that keeps an executor's context from completing.
23
24 This class holds "work" on an executor, preventing the associated
25 execution context's `run()` function from returning due to lack of
26 work. It calls `on_work_started()` on construction and
27 `on_work_finished()` on destruction, ensuring proper work tracking.
28
29 The guard is useful when you need to keep an execution context
30 running while waiting for external events or when work will be
31 posted later.
32
33 @par RAII Semantics
34
35 @li Construction calls `ex.on_work_started()`.
36 @li Destruction calls `ex.on_work_finished()` if `owns_work()`.
37 @li Copy construction creates a new work reference (calls
38 `on_work_started()` again).
39 @li Move construction transfers ownership without additional calls.
40
41 @par Thread Safety
42
43 Distinct objects may be accessed concurrently. Access to a single
44 object requires external synchronization.
45
46 @par Example
47 @code
48 io_context ctx;
49
50 // Keep context running while we set things up
51 auto guard = make_work_guard(ctx);
52
53 std::thread t([&ctx]{ ctx.run(); });
54
55 // ... post work to ctx ...
56
57 // Allow context to complete when work is done
58 guard.reset();
59
60 t.join();
61 @endcode
62
63 @tparam Executor A type satisfying the executor concept.
64
65 @see make_work_guard, executor
66 */
67 template<executor Executor>
68 class executor_work_guard
69 {
70 Executor ex_;
71 bool owns_;
72
73 public:
74 /** The underlying executor type. */
75 using executor_type = Executor;
76
77 /** Construct a work guard.
78
79 Calls `ex.on_work_started()` to inform the executor that
80 work is outstanding.
81
82 @par Exception Safety
83 No-throw guarantee.
84
85 @par Postconditions
86 @li `owns_work() == true`
87 @li `get_executor() == ex`
88
89 @param ex The executor to hold work on. Moved into the guard.
90 */
91 explicit
92 9 executor_work_guard(Executor ex) noexcept
93 9 : ex_(std::move(ex))
94 9 , owns_(true)
95 {
96 9 ex_.on_work_started();
97 9 }
98
99 /** Copy constructor.
100
101 Creates a new work guard holding work on the same executor.
102 Calls `on_work_started()` on the executor.
103
104 @par Exception Safety
105 No-throw guarantee.
106
107 @par Postconditions
108 @li `owns_work() == other.owns_work()`
109 @li `get_executor() == other.get_executor()`
110
111 @param other The work guard to copy from.
112 */
113 2 executor_work_guard(executor_work_guard const& other) noexcept
114 2 : ex_(other.ex_)
115 2 , owns_(other.owns_)
116 {
117
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if(owns_)
118 1 ex_.on_work_started();
119 2 }
120
121 /** Move constructor.
122
123 Transfers work ownership from `other` to `*this`. Does not
124 call `on_work_started()` or `on_work_finished()`.
125
126 @par Exception Safety
127 No-throw guarantee.
128
129 @par Postconditions
130 @li `owns_work()` equals the prior value of `other.owns_work()`
131 @li `other.owns_work() == false`
132
133 @param other The work guard to move from.
134 */
135 1 executor_work_guard(executor_work_guard&& other) noexcept
136 1 : ex_(std::move(other.ex_))
137 1 , owns_(other.owns_)
138 {
139 1 other.owns_ = false;
140 1 }
141
142 /** Destructor.
143
144 If `owns_work()` is `true`, calls `on_work_finished()` on
145 the executor.
146
147 @par Exception Safety
148 No-throw guarantee.
149 */
150 12 ~executor_work_guard()
151 {
152
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 if(owns_)
153 7 ex_.on_work_finished();
154 12 }
155
156 executor_work_guard& operator=(executor_work_guard const&) = delete;
157
158 /** Return the underlying executor.
159
160 @par Exception Safety
161 No-throw guarantee.
162
163 @return A copy of the stored executor.
164 */
165 executor_type
166 5 get_executor() const noexcept
167 {
168 5 return ex_;
169 }
170
171 /** Return whether the guard owns work.
172
173 @par Exception Safety
174 No-throw guarantee.
175
176 @return `true` if this guard will call `on_work_finished()`
177 on destruction, `false` otherwise.
178 */
179 bool
180 12 owns_work() const noexcept
181 {
182 12 return owns_;
183 }
184
185 /** Release ownership of the work.
186
187 If `owns_work()` is `true`, calls `on_work_finished()` on
188 the executor and sets ownership to `false`. Otherwise, has
189 no effect.
190
191 @par Exception Safety
192 No-throw guarantee.
193
194 @par Postconditions
195 @li `owns_work() == false`
196 */
197 void
198 4 reset() noexcept
199 {
200
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if(owns_)
201 {
202 3 ex_.on_work_finished();
203 3 owns_ = false;
204 }
205 4 }
206 };
207
208 //------------------------------------------------
209
210 /** Create a work guard from an executor.
211
212 @par Exception Safety
213 No-throw guarantee.
214
215 @param ex The executor to create the guard for.
216
217 @return An `executor_work_guard` holding work on `ex`.
218
219 @see executor_work_guard
220 */
221 template<executor Executor>
222 executor_work_guard<Executor>
223 1 make_work_guard(Executor ex)
224 {
225 1 return executor_work_guard<Executor>(std::move(ex));
226 }
227
228 } // capy
229 } // boost
230
231 #endif
232