100.00% Lines (8/8) 100.00% Functions (2/2)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Steve Gerbino 2   // Copyright (c) 2026 Steve Gerbino
3   // Copyright (c) 2026 Michael Vandeberg 3   // Copyright (c) 2026 Michael Vandeberg
4   // 4   //
5   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 6   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7   // 7   //
8   // Official repository: https://github.com/cppalliance/corosio 8   // Official repository: https://github.com/cppalliance/corosio
9   // 9   //
10   10  
11   #ifndef BOOST_COROSIO_TIMEOUT_HPP 11   #ifndef BOOST_COROSIO_TIMEOUT_HPP
12   #define BOOST_COROSIO_TIMEOUT_HPP 12   #define BOOST_COROSIO_TIMEOUT_HPP
13   13  
14   #include <boost/corosio/detail/config.hpp> 14   #include <boost/corosio/detail/config.hpp>
15   #include <boost/corosio/detail/timeout_awaitable.hpp> 15   #include <boost/corosio/detail/timeout_awaitable.hpp>
16   #include <boost/capy/concept/io_awaitable.hpp> 16   #include <boost/capy/concept/io_awaitable.hpp>
17   17  
18   #include <chrono> 18   #include <chrono>
19   #include <type_traits> 19   #include <type_traits>
20   #include <utility> 20   #include <utility>
21   21  
22   namespace boost::corosio { 22   namespace boost::corosio {
23   23  
24   /** Race an io_result-returning awaitable against a deadline. 24   /** Race an io_result-returning awaitable against a deadline.
25   25  
26   Starts the awaitable with an interposed stop token and arms a 26   Starts the awaitable with an interposed stop token and arms a
27   timer. If the awaitable finishes first, its result is returned 27   timer. If the awaitable finishes first, its result is returned
28   as-is (success, error, or exception). If the deadline passes 28   as-is (success, error, or exception). If the deadline passes
29   first, the awaitable is cancelled and an `io_result` whose 29   first, the awaitable is cancelled and an `io_result` whose
30   `ec` compares equal to `capy::cond::timeout` (with a 30   `ec` compares equal to `capy::cond::timeout` (with a
31   default-initialized payload) is produced. 31   default-initialized payload) is produced.
32   32  
33 - Exceptions from the inner awaitable always propagate; they are 33 + Exceptions from the inner awaitable always propagate to the caller.
34 - never swallowed by the timer.  
35   34  
36 - @par Preconditions 35 + @pre The awaiting coroutine's executor must belong to an
37 - The awaiting coroutine's executor must belong to an 36 + `io_context`. Any other execution context terminates with a
38 - `io_context`; any other execution context terminates with a 37 + diagnostic, because silently running without a timer would
39 - diagnostic. 38 + drop the requested timeout.
40   39  
41   @par Cancellation 40   @par Cancellation
42   If the parent's stop token is activated, the inner awaitable 41   If the parent's stop token is activated, the inner awaitable
43   is cancelled and its cancellation result is returned. Requesting 42   is cancelled and its cancellation result is returned. Requesting
44   stop from another thread requires a multi-threaded-capable 43   stop from another thread requires a multi-threaded-capable
45 - io_context; a context running in single_threaded mode 44 + `io_context`. A context running in `single_threaded` mode
46 - (auto-enabled at concurrency_hint == 1) does not permit 45 + (auto-enabled at `concurrency_hint` == 1) does not permit
47   cross-thread cancellation. 46   cross-thread cancellation.
48   47  
49   @par Example 48   @par Example
50   @par !example timeout 49   @par !example timeout
51   50  
52   @param a The awaitable to race against the deadline. 51   @param a The awaitable to race against the deadline.
53   @param dur The maximum duration to wait, measured from 52   @param dur The maximum duration to wait, measured from
54   suspension. 53   suspension.
55   54  
56   @return An awaitable yielding `io_result` matching the inner 55   @return An awaitable yielding `io_result` matching the inner
57   awaitable's result type. 56   awaitable's result type.
58   57  
59   @see delay 58   @see delay
60   */ 59   */
61   template<capy::IoAwaitable A, typename Rep, typename Period> 60   template<capy::IoAwaitable A, typename Rep, typename Period>
62   requires detail::is_io_result_v< 61   requires detail::is_io_result_v<
63   std::remove_cvref_t<capy::awaitable_result_t<A>>> && 62   std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
64   std::is_default_constructible_v< 63   std::is_default_constructible_v<
65   std::remove_cvref_t<capy::awaitable_result_t<A>>> 64   std::remove_cvref_t<capy::awaitable_result_t<A>>>
66   [[nodiscard]] auto 65   [[nodiscard]] auto
HITCBC 67   2055 timeout(A a, std::chrono::duration<Rep, Period> dur) 66   2055 timeout(A a, std::chrono::duration<Rep, Period> dur)
68   { 67   {
69   using namespace std::chrono; 68   using namespace std::chrono;
70   // Narrow reps wrap if nanoseconds::max() is converted into them; 69   // Narrow reps wrap if nanoseconds::max() is converted into them;
71   // a double comparison clamps safely in both directions. 70   // a double comparison clamps safely in both directions.
72   using dsec = duration<double>; 71   using dsec = duration<double>;
HITCBC 73   2055 auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)() 72   2055 auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)()
HITCBC 74   2053 : dsec(dur) <= dsec((nanoseconds::min)()) 73   2053 : dsec(dur) <= dsec((nanoseconds::min)())
HITCBC 75   2053 ? (nanoseconds::min)() 74   2053 ? (nanoseconds::min)()
HITCBC 76   2051 : duration_cast<nanoseconds>(dur); 75   2051 : duration_cast<nanoseconds>(dur);
HITCBC 77   4110 return detail::timeout_awaitable<A>(std::move(a), ns); 76   4110 return detail::timeout_awaitable<A>(std::move(a), ns);
78   } 77   }
79   78  
80   /** Race an io_result-returning awaitable against an absolute deadline. 79   /** Race an io_result-returning awaitable against an absolute deadline.
81   80  
82   Behaves as the duration overload with the deadline fixed at 81   Behaves as the duration overload with the deadline fixed at
83   `tp` instead of measured from suspension. 82   `tp` instead of measured from suspension.
84   83  
85   @param a The awaitable to race against the deadline. 84   @param a The awaitable to race against the deadline.
86   @param tp The steady-clock time point at which the awaitable 85   @param tp The steady-clock time point at which the awaitable
87   is cancelled. 86   is cancelled.
88   87  
89   @return An awaitable yielding `io_result` matching the inner 88   @return An awaitable yielding `io_result` matching the inner
90   awaitable's result type. 89   awaitable's result type.
91   90  
92   @see delay 91   @see delay
93   */ 92   */
94   template<capy::IoAwaitable A> 93   template<capy::IoAwaitable A>
95   requires detail::is_io_result_v< 94   requires detail::is_io_result_v<
96   std::remove_cvref_t<capy::awaitable_result_t<A>>> && 95   std::remove_cvref_t<capy::awaitable_result_t<A>>> &&
97   std::is_default_constructible_v< 96   std::is_default_constructible_v<
98   std::remove_cvref_t<capy::awaitable_result_t<A>>> 97   std::remove_cvref_t<capy::awaitable_result_t<A>>>
99   [[nodiscard]] auto 98   [[nodiscard]] auto
HITCBC 100   4 timeout(A a, std::chrono::steady_clock::time_point tp) 99   4 timeout(A a, std::chrono::steady_clock::time_point tp)
101   { 100   {
HITCBC 102   4 return detail::timeout_awaitable<A>(std::move(a), tp); 101   4 return detail::timeout_awaitable<A>(std::move(a), tp);
103   } 102   }
104   103  
105   } // namespace boost::corosio 104   } // namespace boost::corosio
106   105  
107   #endif 106   #endif