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