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

Generated by: LCOV version 2.3