100.00% Lines (31/31) 100.00% Functions (8/8)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/capy 8   // Official repository: https://github.com/cppalliance/capy
9   // 9   //
10   10  
11   #ifndef BOOST_CAPY_WORK_GUARD_HPP 11   #ifndef BOOST_CAPY_WORK_GUARD_HPP
12   #define BOOST_CAPY_WORK_GUARD_HPP 12   #define BOOST_CAPY_WORK_GUARD_HPP
13   13  
14   #include <boost/capy/detail/config.hpp> 14   #include <boost/capy/detail/config.hpp>
15   #include <boost/capy/ex/execution_context.hpp> 15   #include <boost/capy/ex/execution_context.hpp>
16   #include <boost/capy/concept/executor.hpp> 16   #include <boost/capy/concept/executor.hpp>
17   17  
18   #include <utility> 18   #include <utility>
19   19  
20   namespace boost { 20   namespace boost {
21   namespace capy { 21   namespace capy {
22   22  
23   /** RAII guard that keeps an executor's context from completing. 23   /** RAII guard that keeps an executor's context from completing.
24   24  
25   This class holds "work" on an executor, preventing the associated 25   This class holds "work" on an executor, preventing the associated
26   execution context's `run()` function from returning due to lack of 26   execution context's `run()` function from returning due to lack of
27   work. It calls `on_work_started()` on construction and 27   work. It calls `on_work_started()` on construction and
28   `on_work_finished()` on destruction, ensuring proper work tracking. 28   `on_work_finished()` on destruction, ensuring proper work tracking.
29   29  
30   The guard is useful when you need to keep an execution context 30   The guard is useful when you need to keep an execution context
31   running while waiting for external events or when work is 31   running while waiting for external events or when work is
32   posted later. 32   posted later.
33   33  
34   @par RAII Semantics 34   @par RAII Semantics
35   35  
36   @li Construction calls `ex.on_work_started()`. 36   @li Construction calls `ex.on_work_started()`.
37   @li Destruction calls `ex.on_work_finished()` if `owns_work()`. 37   @li Destruction calls `ex.on_work_finished()` if `owns_work()`.
38   @li Copy construction creates a new work reference (calls 38   @li Copy construction creates a new work reference (calls
39   `on_work_started()` again). 39   `on_work_started()` again).
40   @li Move construction transfers ownership without additional calls. 40   @li Move construction transfers ownership without additional calls.
41   41  
42   @par Thread Safety 42   @par Thread Safety
43   43  
44   Distinct objects may be accessed concurrently. Access to a single 44   Distinct objects may be accessed concurrently. Access to a single
45   object requires external synchronization. 45   object requires external synchronization.
46   46  
47   @par Example 47   @par Example
48   @par !example work_guard 48   @par !example work_guard
49   49  
50   50  
51   @note The executor is returned by reference, allowing callers to 51   @note The executor is returned by reference, allowing callers to
52   manage the executor's lifetime directly. This is essential in 52   manage the executor's lifetime directly. This is essential in
53   coroutine-first designs where the executor often outlives individual 53   coroutine-first designs where the executor often outlives individual
54   coroutine frames. 54   coroutine frames.
55   55  
56   @tparam Ex A type satisfying the Executor concept. 56   @tparam Ex A type satisfying the Executor concept.
57   57  
58   @see make_work_guard, Executor 58   @see make_work_guard, Executor
59   */ 59   */
60   template<Executor Ex> 60   template<Executor Ex>
61   class work_guard 61   class work_guard
62   { 62   {
63   Ex ex_; 63   Ex ex_;
64   bool owns_; 64   bool owns_;
65   65  
66   public: 66   public:
67   /** Names the executor type this `work_guard<Ex>` guards. */ 67   /** Names the executor type this `work_guard<Ex>` guards. */
68   using executor_type = Ex; 68   using executor_type = Ex;
69   69  
70   /** Construct a work guard. 70   /** Construct a work guard.
71   71  
72   Calls `ex.on_work_started()` to inform the executor that 72   Calls `ex.on_work_started()` to inform the executor that
73   work is outstanding. 73   work is outstanding.
74   74  
75   @par Exception Safety 75   @par Exception Safety
76   No-throw guarantee. 76   No-throw guarantee.
77   77  
78   @par Postconditions 78   @par Postconditions
79   @li `owns_work() == true` 79   @li `owns_work() == true`
80   @li `executor() == ex` 80   @li `executor() == ex`
81   81  
82   @param ex The executor to hold work on. Moved into the guard. 82   @param ex The executor to hold work on. Moved into the guard.
83   */ 83   */
84   explicit 84   explicit
HITCBC 85   1962 work_guard(Ex ex) noexcept 85   1969 work_guard(Ex ex) noexcept
HITCBC 86   1962 : ex_(std::move(ex)) 86   1969 : ex_(std::move(ex))
HITCBC 87   1962 , owns_(true) 87   1969 , owns_(true)
88   { 88   {
HITCBC 89   1962 ex_.on_work_started(); 89   1969 ex_.on_work_started();
HITCBC 90   1962 } 90   1969 }
91   91  
92   /** Construct a copy. 92   /** Construct a copy.
93   93  
94   Creates a new work guard holding work on the same executor. 94   Creates a new work guard holding work on the same executor.
95   Calls `on_work_started()` on the executor. 95   Calls `on_work_started()` on the executor.
96   96  
97   @par Exception Safety 97   @par Exception Safety
98   No-throw guarantee. 98   No-throw guarantee.
99   99  
100   @par Postconditions 100   @par Postconditions
101   @li `owns_work() == other.owns_work()` 101   @li `owns_work() == other.owns_work()`
102   @li `executor() == other.executor()` 102   @li `executor() == other.executor()`
103   103  
104   @param other The work guard to copy from. 104   @param other The work guard to copy from.
105   */ 105   */
HITCBC 106   2 work_guard(work_guard const& other) noexcept 106   2 work_guard(work_guard const& other) noexcept
HITCBC 107   2 : ex_(other.ex_) 107   2 : ex_(other.ex_)
HITCBC 108   2 , owns_(other.owns_) 108   2 , owns_(other.owns_)
109   { 109   {
HITCBC 110   2 if(owns_) 110   2 if(owns_)
HITCBC 111   1 ex_.on_work_started(); 111   1 ex_.on_work_started();
HITCBC 112   2 } 112   2 }
113   113  
114   /** Construct by moving. 114   /** Construct by moving.
115   115  
116   Transfers work ownership from `other` to `*this`. Does not 116   Transfers work ownership from `other` to `*this`. Does not
117   call `on_work_started()` or `on_work_finished()`. 117   call `on_work_started()` or `on_work_finished()`.
118   118  
119   @par Exception Safety 119   @par Exception Safety
120   No-throw guarantee. 120   No-throw guarantee.
121   121  
122   @par Postconditions 122   @par Postconditions
123   @li `owns_work()` equals the prior value of `other.owns_work()` 123   @li `owns_work()` equals the prior value of `other.owns_work()`
124   @li `other.owns_work() == false` 124   @li `other.owns_work() == false`
125   125  
126   @param other The work guard to move from. 126   @param other The work guard to move from.
127   */ 127   */
HITCBC 128   1 work_guard(work_guard&& other) noexcept 128   1 work_guard(work_guard&& other) noexcept
HITCBC 129   1 : ex_(std::move(other.ex_)) 129   1 : ex_(std::move(other.ex_))
HITCBC 130   1 , owns_(other.owns_) 130   1 , owns_(other.owns_)
131   { 131   {
HITCBC 132   1 other.owns_ = false; 132   1 other.owns_ = false;
HITCBC 133   1 } 133   1 }
134   134  
135   /** Destructor. 135   /** Destructor.
136   136  
137   If `owns_work()` is `true`, calls `on_work_finished()` on 137   If `owns_work()` is `true`, calls `on_work_finished()` on
138   the executor. 138   the executor.
139   139  
140   @par Exception Safety 140   @par Exception Safety
141   No-throw guarantee. 141   No-throw guarantee.
142   */ 142   */
HITCBC 143   1965 ~work_guard() 143   1972 ~work_guard()
144   { 144   {
HITCBC 145   1965 if(owns_) 145   1972 if(owns_)
HITCBC 146   1959 ex_.on_work_finished(); 146   1966 ex_.on_work_finished();
HITCBC 147   1965 } 147   1972 }
148   148  
149   /** Copy assignment is disabled. 149   /** Copy assignment is disabled.
150   150  
151   A guard takes its work reference at construction and releases it at 151   A guard takes its work reference at construction and releases it at
152   destruction or through @ref reset. No operation rebinds an existing 152   destruction or through @ref reset. No operation rebinds an existing
153   guard to a different executor. 153   guard to a different executor.
154   154  
155   @param other The work guard that would be assigned from. 155   @param other The work guard that would be assigned from.
156   156  
157   @return A reference to `*this`. 157   @return A reference to `*this`.
158   */ 158   */
159   work_guard& operator=(work_guard const& other) = delete; 159   work_guard& operator=(work_guard const& other) = delete;
160   160  
161   /** Return the underlying executor by reference. 161   /** Return the underlying executor by reference.
162   162  
163   The reference remains valid for the lifetime of this guard, 163   The reference remains valid for the lifetime of this guard,
164   enabling callers to manage executor lifetime explicitly. 164   enabling callers to manage executor lifetime explicitly.
165   165  
166   @par Exception Safety 166   @par Exception Safety
167   No-throw guarantee. 167   No-throw guarantee.
168   168  
169   @return A reference to the stored executor. 169   @return A reference to the stored executor.
170   */ 170   */
171   executor_type const& 171   executor_type const&
HITCBC 172   3907 executor() const noexcept 172   3921 executor() const noexcept
173   { 173   {
HITCBC 174   3907 return ex_; 174   3921 return ex_;
175   } 175   }
176   176  
177   /** Return whether the guard owns work. 177   /** Return whether the guard owns work.
178   178  
179   @par Exception Safety 179   @par Exception Safety
180   No-throw guarantee. 180   No-throw guarantee.
181   181  
182   @return `true` if this guard calls `on_work_finished()` 182   @return `true` if this guard calls `on_work_finished()`
183   on destruction, `false` otherwise. 183   on destruction, `false` otherwise.
184   */ 184   */
185   bool 185   bool
HITCBC 186   12 owns_work() const noexcept 186   12 owns_work() const noexcept
187   { 187   {
HITCBC 188   12 return owns_; 188   12 return owns_;
189   } 189   }
190   190  
191   /** Release ownership of the work. 191   /** Release ownership of the work.
192   192  
193   If `owns_work()` is `true`, calls `on_work_finished()` on 193   If `owns_work()` is `true`, calls `on_work_finished()` on
194   the executor and sets ownership to `false`. Otherwise, has 194   the executor and sets ownership to `false`. Otherwise, has
195   no effect. 195   no effect.
196   196  
197   @par Exception Safety 197   @par Exception Safety
198   No-throw guarantee. 198   No-throw guarantee.
199   199  
200   @par Postconditions 200   @par Postconditions
201   @li `owns_work() == false` 201   @li `owns_work() == false`
202   */ 202   */
203   void 203   void
HITCBC 204   5 reset() noexcept 204   5 reset() noexcept
205   { 205   {
HITCBC 206   5 if(owns_) 206   5 if(owns_)
207   { 207   {
HITCBC 208   4 ex_.on_work_finished(); 208   4 ex_.on_work_finished();
HITCBC 209   4 owns_ = false; 209   4 owns_ = false;
210   } 210   }
HITCBC 211   5 } 211   5 }
212   }; 212   };
213   213  
214   /** Create a work guard from an executor. 214   /** Create a work guard from an executor.
215   215  
216   @par Exception Safety 216   @par Exception Safety
217   No-throw guarantee. 217   No-throw guarantee.
218   218  
219   @param ex The executor to create the guard for. 219   @param ex The executor to create the guard for.
220   220  
221   @return A `work_guard` holding work on `ex`. 221   @return A `work_guard` holding work on `ex`.
222   222  
223   @see work_guard 223   @see work_guard
224   */ 224   */
225   template<Executor Ex> 225   template<Executor Ex>
226   work_guard<Ex> 226   work_guard<Ex>
HITCBC 227   3 make_work_guard(Ex ex) 227   3 make_work_guard(Ex ex)
228   { 228   {
HITCBC 229   3 return work_guard<Ex>(std::move(ex)); 229   3 return work_guard<Ex>(std::move(ex));
230   } 230   }
231   231  
232   } // capy 232   } // capy
233   } // boost 233   } // boost
234   234  
235   #endif 235   #endif