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 20:48:05 Functions: 94.5 % 55 52

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

Generated by: LCOV version 2.3