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 to the caller. | 33 | Exceptions from the inner awaitable always propagate to the caller. | |||||
| 34 | 34 | |||||||
| 35 | @pre The awaiting coroutine's executor must belong to an | 35 | @pre The awaiting coroutine's executor must belong to an | |||||
| 36 | `io_context`. Any other execution context terminates with a | 36 | `io_context`. Any other execution context terminates with a | |||||
| 37 | diagnostic, because silently running without a timer would | 37 | diagnostic, because silently running without a timer would | |||||
| 38 | drop the requested timeout. | 38 | drop the requested timeout. | |||||
| 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 | @par !example timeout | 49 | @par !example timeout | |||||
| 50 | 50 | |||||||
| 51 | @param a The awaitable to race against the deadline. | 51 | @param a The awaitable to race against the deadline. | |||||
| 52 | @param dur The maximum duration to wait, measured from | 52 | @param dur The maximum duration to wait, measured from | |||||
| 53 | suspension. | 53 | suspension. | |||||
| 54 | 54 | |||||||
| 55 | @return An awaitable yielding `io_result` matching the inner | 55 | @return An awaitable yielding `io_result` matching the inner | |||||
| 56 | awaitable's result type. | 56 | awaitable's result type. | |||||
| 57 | 57 | |||||||
| 58 | @see delay | 58 | @see delay | |||||
| 59 | */ | 59 | */ | |||||
| 60 | template<capy::IoAwaitable A, typename Rep, typename Period> | 60 | template<capy::IoAwaitable A, typename Rep, typename Period> | |||||
| 61 | requires detail::is_io_result_v< | 61 | requires detail::is_io_result_v< | |||||
| 62 | std::remove_cvref_t<capy::awaitable_result_t<A>>> && | 62 | std::remove_cvref_t<capy::awaitable_result_t<A>>> && | |||||
| 63 | std::is_default_constructible_v< | 63 | std::is_default_constructible_v< | |||||
| 64 | std::remove_cvref_t<capy::awaitable_result_t<A>>> | 64 | std::remove_cvref_t<capy::awaitable_result_t<A>>> | |||||
| 65 | [[nodiscard]] auto | 65 | [[nodiscard]] auto | |||||
| HITCBC | 66 | 2055 | timeout(A a, std::chrono::duration<Rep, Period> dur) | 66 | 2055 | timeout(A a, std::chrono::duration<Rep, Period> dur) | ||
| 67 | { | 67 | { | |||||
| 68 | using namespace std::chrono; | 68 | using namespace std::chrono; | |||||
| 69 | // Narrow reps wrap if nanoseconds::max() is converted into them; | 69 | // Narrow reps wrap if nanoseconds::max() is converted into them; | |||||
| 70 | // a double comparison clamps safely in both directions. | 70 | // a double comparison clamps safely in both directions. | |||||
| 71 | using dsec = duration<double>; | 71 | using dsec = duration<double>; | |||||
| HITCBC | 72 | 2055 | auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)() | 72 | 2055 | auto ns = dsec(dur) >= dsec((nanoseconds::max)()) ? (nanoseconds::max)() | ||
| HITCBC | 73 | 2053 | : dsec(dur) <= dsec((nanoseconds::min)()) | 73 | 2053 | : dsec(dur) <= dsec((nanoseconds::min)()) | ||
| HITCBC | 74 | 2053 | ? (nanoseconds::min)() | 74 | 2053 | ? (nanoseconds::min)() | ||
| HITCBC | 75 | 2051 | : duration_cast<nanoseconds>(dur); | 75 | 2051 | : duration_cast<nanoseconds>(dur); | ||
| HITCBC | 76 | 4110 | return detail::timeout_awaitable<A>(std::move(a), ns); | 76 | 4110 | return detail::timeout_awaitable<A>(std::move(a), ns); | ||
| 77 | } | 77 | } | |||||
| 78 | 78 | |||||||
| 79 | /** Race an io_result-returning awaitable against an absolute deadline. | 79 | /** Race an io_result-returning awaitable against an absolute deadline. | |||||
| 80 | 80 | |||||||
| 81 | Behaves as the duration overload with the deadline fixed at | 81 | Behaves as the duration overload with the deadline fixed at | |||||
| 82 | `tp` instead of measured from suspension. | 82 | `tp` instead of measured from suspension. | |||||
| 83 | 83 | |||||||
| 84 | @param a The awaitable to race against the deadline. | 84 | @param a The awaitable to race against the deadline. | |||||
| 85 | @param tp The steady-clock time point at which the awaitable | 85 | @param tp The steady-clock time point at which the awaitable | |||||
| 86 | is cancelled. | 86 | is cancelled. | |||||
| 87 | 87 | |||||||
| 88 | @return An awaitable yielding `io_result` matching the inner | 88 | @return An awaitable yielding `io_result` matching the inner | |||||
| 89 | awaitable's result type. | 89 | awaitable's result type. | |||||
| 90 | 90 | |||||||
| 91 | @see delay | 91 | @see delay | |||||
| 92 | */ | 92 | */ | |||||
| 93 | template<capy::IoAwaitable A> | 93 | template<capy::IoAwaitable A> | |||||
| 94 | requires detail::is_io_result_v< | 94 | requires detail::is_io_result_v< | |||||
| 95 | std::remove_cvref_t<capy::awaitable_result_t<A>>> && | 95 | std::remove_cvref_t<capy::awaitable_result_t<A>>> && | |||||
| 96 | std::is_default_constructible_v< | 96 | std::is_default_constructible_v< | |||||
| 97 | std::remove_cvref_t<capy::awaitable_result_t<A>>> | 97 | std::remove_cvref_t<capy::awaitable_result_t<A>>> | |||||
| 98 | [[nodiscard]] auto | 98 | [[nodiscard]] auto | |||||
| HITCBC | 99 | 4 | timeout(A a, std::chrono::steady_clock::time_point tp) | 99 | 4 | timeout(A a, std::chrono::steady_clock::time_point tp) | ||
| 100 | { | 100 | { | |||||
| HITCBC | 101 | 4 | return detail::timeout_awaitable<A>(std::move(a), tp); | 101 | 4 | return detail::timeout_awaitable<A>(std::move(a), tp); | ||
| 102 | } | 102 | } | |||||
| 103 | 103 | |||||||
| 104 | } // namespace boost::corosio | 104 | } // namespace boost::corosio | |||||
| 105 | 105 | |||||||
| 106 | #endif | 106 | #endif | |||||