userver: userver/engine/deadline.hpp Source File
Loading...
Searching...
No Matches
deadline.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/deadline.hpp
4/// @brief Internal representation of a deadline time point
5
6#include <chrono>
7#include <type_traits>
8
9#include <userver/utils/assert.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace engine {
14
15/// @brief Internal representation of a deadline time point
16class Deadline final {
17public:
18 using Clock = std::chrono::steady_clock;
19 using TimePoint = Clock::time_point;
20 using Duration = TimePoint::duration;
21
22 /// Creates an unreachable deadline
23 constexpr Deadline() = default;
24
25 /// Returns whether the deadline can be reached
26 constexpr bool IsReachable() const noexcept { return value_ != TimePoint{}; }
27
28 /// Returns whether the deadline is reached
29 bool IsReached() const noexcept;
30
31 /// Returns whether the deadline is reached. Will report false-negatives, will
32 /// never report false-positives.
33 bool IsSurelyReachedApprox() const noexcept;
34
35 /// Returns the duration of time left before the reachable deadline
36 Duration TimeLeft() const noexcept;
37
38 /// Returns the approximate duration of time left before the reachable
39 /// deadline. May be faster than TimeLeft.
40 /// @see utils::datetime::SteadyCoarseClock
41 Duration TimeLeftApprox() const noexcept;
42
43 /// Converts duration to a Deadline
44 template <typename Rep, typename Period>
45 static Deadline FromDuration(const std::chrono::duration<Rep, Period>& incoming_duration) noexcept {
46 using IncomingDuration = std::chrono::duration<Rep, Period>;
47
48 if (incoming_duration.count() < 0) {
49 return Deadline::Passed();
50 }
51
52 const auto now = TimePoint::clock::now();
53 constexpr auto max_now = TimePoint::clock::time_point::max();
54
55 // If:
56 // 1. incoming_duration would overflow Duration,
57 // 2. or adding it to 'now' would overflow,
58 // then set deadline to unreachable right away.
59
60 // Implementation strategy:
61 // 1. Check that resolution of Duration >= that of IncomingDuration.
62 static_assert(std::is_constructible_v<Duration, IncomingDuration>);
63
64 // 2. As it is higher, then the range is lower (or equal). So casting
65 // Duration::max to IncomingDuration is safe. Do a quick check
66 // that Duration{incoming_duration} won't overflow.
67 if (incoming_duration > std::chrono::duration_cast<IncomingDuration>(Duration::max())) {
68 OnDurationOverflow(std::chrono::duration_cast<std::chrono::duration<double>>(incoming_duration));
69 return Deadline{};
70 }
71
72 // 3. Check that now + Duration{incoming_duration} won't overflow.
73 UASSERT(max_now - now >= Duration{incoming_duration});
74
75 return Deadline(now + Duration{incoming_duration});
76 }
77
78 /// @brief Converts time point to a Deadline
79 ///
80 /// Non-steady clocks may produce inaccurate Deadlines. Prefer using
81 /// Deadline::FromDuration or std::chrono::steady_clock::time_point
82 /// if possible.
83 template <typename Clock, typename Duration>
84 static Deadline FromTimePoint(const std::chrono::time_point<Clock, Duration>& time_point) noexcept {
85 return FromDuration(time_point - Clock::now());
86 }
87
88 /// @cond
89 /// Specialization for the native time point type
90 constexpr static Deadline FromTimePoint(const TimePoint& time_point) { return Deadline(time_point); }
91 /// @endcond
92
93 /// A Deadline that is guaranteed to be IsReached
94 constexpr static Deadline Passed() noexcept { return Deadline{kPassed}; }
95
96 constexpr bool operator==(const Deadline& r) const noexcept { return value_ == r.value_; }
97
98 constexpr bool operator<(const Deadline& r) const noexcept {
99 if (!IsReachable()) return false;
100 if (!r.IsReachable()) return true;
101 return value_ < r.value_;
102 }
103
104private:
105 constexpr explicit Deadline(TimePoint value) noexcept : value_(value) {}
106
107 static void OnDurationOverflow(std::chrono::duration<double> incoming_duration);
108
109 static constexpr TimePoint kPassed = TimePoint::min();
110
111 TimePoint value_;
112};
113
114} // namespace engine
115
116USERVER_NAMESPACE_END