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

            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_EX_STOP_TOKEN_SUPPORT_HPP
      11              : #define BOOST_CAPY_EX_STOP_TOKEN_SUPPORT_HPP
      12              : 
      13              : #include <boost/capy/detail/config.hpp>
      14              : #include <boost/capy/ex/any_coro.hpp>
      15              : #include <boost/capy/ex/get_stop_token.hpp>
      16              : 
      17              : #include <coroutine>
      18              : #if BOOST_CAPY_HAS_STOP_TOKEN
      19              : #include <stop_token>
      20              : #endif
      21              : #include <type_traits>
      22              : 
      23              : namespace boost {
      24              : namespace capy {
      25              : 
      26              : #if BOOST_CAPY_HAS_STOP_TOKEN
      27              : 
      28              : /** CRTP mixin that adds stop token support to a promise type.
      29              : 
      30              :     Inherit from this class to enable two capabilities in your coroutine:
      31              : 
      32              :     1. **Stop token storage** — The mixin stores the `std::stop_token`
      33              :        that was passed when your coroutine was awaited.
      34              : 
      35              :     2. **Stop token access** — Coroutine code can retrieve the token via
      36              :        `co_await get_stop_token()`.
      37              : 
      38              :     @tparam Derived The derived promise type (CRTP pattern).
      39              : 
      40              :     @par Basic Usage
      41              : 
      42              :     For coroutines that only need to access their stop token:
      43              : 
      44              :     @code
      45              :     struct my_task
      46              :     {
      47              :         struct promise_type : stop_token_support<promise_type>
      48              :         {
      49              :             my_task get_return_object();
      50              :             std::suspend_always initial_suspend() noexcept;
      51              :             std::suspend_always final_suspend() noexcept;
      52              :             void return_void();
      53              :             void unhandled_exception();
      54              :         };
      55              : 
      56              :         // ... awaitable interface ...
      57              :     };
      58              : 
      59              :     my_task example()
      60              :     {
      61              :         auto token = co_await get_stop_token();
      62              :         // Use token...
      63              :     }
      64              :     @endcode
      65              : 
      66              :     @par Custom Awaitable Transformation
      67              : 
      68              :     If your promise needs to transform awaitables (e.g., for affinity or
      69              :     logging), override `transform_awaitable` instead of `await_transform`:
      70              : 
      71              :     @code
      72              :     struct promise_type : stop_token_support<promise_type>
      73              :     {
      74              :         any_executor_ref ex_;
      75              : 
      76              :         template<typename A>
      77              :         auto transform_awaitable(A&& a)
      78              :         {
      79              :             // Your custom transformation logic
      80              :             return make_affine(std::forward<A>(a), ex_);
      81              :         }
      82              :     };
      83              :     @endcode
      84              : 
      85              :     The mixin's `await_transform` intercepts @ref get_stop_token_tag and
      86              :     delegates all other awaitables to your `transform_awaitable`.
      87              : 
      88              :     @par Making Your Coroutine Stoppable
      89              : 
      90              :     The mixin handles the "inside the coroutine" part—accessing the token.
      91              :     To receive a token when your coroutine is awaited (satisfying
      92              :     @ref IoAwaitable), implement the stoppable `await_suspend`
      93              :     overload on your coroutine return type:
      94              : 
      95              :     @code
      96              :     struct my_task
      97              :     {
      98              :         struct promise_type : stop_token_support<promise_type> { ... };
      99              : 
     100              :         std::coroutine_handle<promise_type> h_;
     101              : 
     102              :         // Stoppable await_suspend receives and stores the token
     103              :         template<class Ex>
     104              :         any_coro await_suspend(any_coro cont, Ex const& ex, std::stop_token token)
     105              :         {
     106              :             h_.promise().set_stop_token(token);  // Store via mixin API
     107              :             // ... rest of suspend logic ...
     108              :         }
     109              :     };
     110              :     @endcode
     111              : 
     112              :     @par Thread Safety
     113              :     The stop token is stored during `await_suspend` and read during
     114              :     `co_await get_stop_token()`. These occur on the same logical thread
     115              :     of execution, so no synchronization is required.
     116              : 
     117              :     @see get_stop_token
     118              :     @see get_stop_token_tag
     119              :     @see IoAwaitable
     120              : */
     121              : template<typename Derived>
     122              : class stop_token_support
     123              : {
     124              :     std::stop_token stop_token_;
     125              : 
     126              : public:
     127              :     /** Store a stop token for later retrieval.
     128              : 
     129              :         Call this from your coroutine type's stoppable `await_suspend`
     130              :         overload to make the token available via `co_await get_stop_token()`.
     131              : 
     132              :         @param token The stop token to store.
     133              :     */
     134          185 :     void set_stop_token(std::stop_token token) noexcept
     135              :     {
     136          185 :         stop_token_ = token;
     137          185 :     }
     138              : 
     139              :     /** Return the stored stop token.
     140              : 
     141              :         @return The stop token, or a default-constructed token if none was set.
     142              :     */
     143          101 :     std::stop_token const& stop_token() const noexcept
     144              :     {
     145          101 :         return stop_token_;
     146              :     }
     147              : 
     148              :     /** Transform an awaitable before co_await.
     149              : 
     150              :         Override this in your derived promise type to customize how
     151              :         awaitables are transformed. The default implementation passes
     152              :         the awaitable through unchanged.
     153              : 
     154              :         @param a The awaitable expression from `co_await a`.
     155              : 
     156              :         @return The transformed awaitable.
     157              :     */
     158              :     template<typename A>
     159              :     decltype(auto) transform_awaitable(A&& a)
     160              :     {
     161              :         return std::forward<A>(a);
     162              :     }
     163              : 
     164              :     /** Intercept co_await expressions.
     165              : 
     166              :         This function handles @ref get_stop_token_tag specially, returning
     167              :         an awaiter that yields the stored stop token. All other awaitables
     168              :         are delegated to @ref transform_awaitable.
     169              : 
     170              :         @param t The awaited expression.
     171              : 
     172              :         @return An awaiter for the expression.
     173              :     */
     174              :     template<typename T>
     175          114 :     auto await_transform(T&& t)
     176              :     {
     177              :         if constexpr (std::is_same_v<std::decay_t<T>, get_stop_token_tag>)
     178              :         {
     179              :             struct awaiter
     180              :             {
     181              :                 std::stop_token token_;
     182              : 
     183           13 :                 bool await_ready() const noexcept
     184              :                 {
     185           13 :                     return true;
     186              :                 }
     187              : 
     188            1 :                 void await_suspend(any_coro) const noexcept
     189              :                 {
     190            1 :                 }
     191              : 
     192           12 :                 std::stop_token await_resume() const noexcept
     193              :                 {
     194           12 :                     return token_;
     195              :                 }
     196              :             };
     197           14 :             return awaiter{stop_token_};
     198              :         }
     199              :         else
     200              :         {
     201           25 :             return static_cast<Derived*>(this)->transform_awaitable(
     202          100 :                 std::forward<T>(t));
     203              :         }
     204              :     }
     205              : };
     206              : 
     207              : #endif // BOOST_CAPY_HAS_STOP_TOKEN
     208              : 
     209              : } // namespace capy
     210              : } // namespace boost
     211              : 
     212              : #endif
        

Generated by: LCOV version 2.3