LCOV - code coverage report
Current view: top level - boost/capy/ex - executor_work_guard.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 31 31
Test Date: 2026-01-15 18:27:21 Functions: 100.0 % 8 8

            Line data    Source code
       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 :         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           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            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
        

Generated by: LCOV version 2.3