LCOV - code coverage report
Current view: top level - capy/ex - work_guard.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 100.0 % 31 31
Test Date: 2026-08-14 20:51:18 Functions: 97.7 % 44 43 1

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

Generated by: LCOV version 2.3