LCOV - code coverage report
Current view: top level - capy/ex - work_guard.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 31 31
Test Date: 2026-02-12 16:53:28 Functions: 100.0 % 32 32

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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_WORK_GUARD_HPP
      11              : #define BOOST_CAPY_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              :     @note The executor is returned by reference, allowing callers to
      64              :     manage the executor's lifetime directly. This is essential in
      65              :     coroutine-first designs where the executor often outlives individual
      66              :     coroutine frames.
      67              : 
      68              :     @tparam Ex A type satisfying the Executor concept.
      69              : 
      70              :     @see make_work_guard, Executor
      71              : */
      72              : template<Executor Ex>
      73              : class work_guard
      74              : {
      75              :     Ex ex_;
      76              :     bool owns_;
      77              : 
      78              : public:
      79              :     /** The underlying executor type. */
      80              :     using executor_type = Ex;
      81              : 
      82              :     /** Construct a work guard.
      83              : 
      84              :         Calls `ex.on_work_started()` to inform the executor that
      85              :         work is outstanding.
      86              : 
      87              :         @par Exception Safety
      88              :         No-throw guarantee.
      89              : 
      90              :         @par Postconditions
      91              :         @li `owns_work() == true`
      92              :         @li `executor() == ex`
      93              : 
      94              :         @param ex The executor to hold work on. Moved into the guard.
      95              :     */
      96              :     explicit
      97         2024 :     work_guard(Ex ex) noexcept
      98         2024 :         : ex_(std::move(ex))
      99         2024 :         , owns_(true)
     100              :     {
     101         2024 :         ex_.on_work_started();
     102         2024 :     }
     103              : 
     104              :     /** Copy constructor.
     105              : 
     106              :         Creates a new work guard holding work on the same executor.
     107              :         Calls `on_work_started()` on the executor.
     108              : 
     109              :         @par Exception Safety
     110              :         No-throw guarantee.
     111              : 
     112              :         @par Postconditions
     113              :         @li `owns_work() == other.owns_work()`
     114              :         @li `executor() == other.executor()`
     115              : 
     116              :         @param other The work guard to copy from.
     117              :     */
     118            2 :     work_guard(work_guard const& other) noexcept
     119            2 :         : ex_(other.ex_)
     120            2 :         , owns_(other.owns_)
     121              :     {
     122            2 :         if(owns_)
     123            1 :             ex_.on_work_started();
     124            2 :     }
     125              : 
     126              :     /** Move constructor.
     127              : 
     128              :         Transfers work ownership from `other` to `*this`. Does not
     129              :         call `on_work_started()` or `on_work_finished()`.
     130              : 
     131              :         @par Exception Safety
     132              :         No-throw guarantee.
     133              : 
     134              :         @par Postconditions
     135              :         @li `owns_work()` equals the prior value of `other.owns_work()`
     136              :         @li `other.owns_work() == false`
     137              : 
     138              :         @param other The work guard to move from.
     139              :     */
     140            1 :     work_guard(work_guard&& other) noexcept
     141            1 :         : ex_(std::move(other.ex_))
     142            1 :         , owns_(other.owns_)
     143              :     {
     144            1 :         other.owns_ = false;
     145            1 :     }
     146              : 
     147              :     /** Destructor.
     148              : 
     149              :         If `owns_work()` is `true`, calls `on_work_finished()` on
     150              :         the executor.
     151              : 
     152              :         @par Exception Safety
     153              :         No-throw guarantee.
     154              :     */
     155         2027 :     ~work_guard()
     156              :     {
     157         2027 :         if(owns_)
     158         2022 :             ex_.on_work_finished();
     159         2027 :     }
     160              : 
     161              :     work_guard& operator=(work_guard const&) = delete;
     162              : 
     163              :     /** Return the underlying executor by reference.
     164              : 
     165              :         The reference remains valid for the lifetime of this guard,
     166              :         enabling callers to manage executor lifetime explicitly.
     167              : 
     168              :         @par Exception Safety
     169              :         No-throw guarantee.
     170              : 
     171              :         @return A reference to the stored executor.
     172              :     */
     173              :     executor_type const&
     174         4035 :     executor() const noexcept
     175              :     {
     176         4035 :         return ex_;
     177              :     }
     178              : 
     179              :     /** Return whether the guard owns work.
     180              : 
     181              :         @par Exception Safety
     182              :         No-throw guarantee.
     183              : 
     184              :         @return `true` if this guard will call `on_work_finished()`
     185              :             on destruction, `false` otherwise.
     186              :     */
     187              :     bool
     188           12 :     owns_work() const noexcept
     189              :     {
     190           12 :         return owns_;
     191              :     }
     192              : 
     193              :     /** Release ownership of the work.
     194              : 
     195              :         If `owns_work()` is `true`, calls `on_work_finished()` on
     196              :         the executor and sets ownership to `false`. Otherwise, has
     197              :         no effect.
     198              : 
     199              :         @par Exception Safety
     200              :         No-throw guarantee.
     201              : 
     202              :         @par Postconditions
     203              :         @li `owns_work() == false`
     204              :     */
     205              :     void
     206            4 :     reset() noexcept
     207              :     {
     208            4 :         if(owns_)
     209              :         {
     210            3 :             ex_.on_work_finished();
     211            3 :             owns_ = false;
     212              :         }
     213            4 :     }
     214              : };
     215              : 
     216              : //------------------------------------------------
     217              : 
     218              : /** Create a work guard from an executor.
     219              : 
     220              :     @par Exception Safety
     221              :     No-throw guarantee.
     222              : 
     223              :     @param ex The executor to create the guard for.
     224              : 
     225              :     @return A `work_guard` holding work on `ex`.
     226              : 
     227              :     @see work_guard
     228              : */
     229              : template<Executor Ex>
     230              : work_guard<Ex>
     231            1 : make_work_guard(Ex ex)
     232              : {
     233            1 :     return work_guard<Ex>(std::move(ex));
     234              : }
     235              : 
     236              : } // capy
     237              : } // boost
     238              : 
     239              : #endif
        

Generated by: LCOV version 2.3