userver: userver/engine/deadline.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 {
17 public:
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(
46 const std::chrono::duration<Rep, Period>& incoming_duration) noexcept {
47 using IncomingDuration = std::chrono::duration<Rep, Period>;
48
49 if (incoming_duration.count() < 0) {
50 return Deadline::Passed();
51 }
52
53 const auto now = TimePoint::clock::now();
54 constexpr auto max_now = TimePoint::clock::time_point::max();
55
56 // If:
57 // 1. incoming_duration would overflow Duration,
58 // 2. or adding it to 'now' would overflow,
59 // then set deadline to unreachable right away.
60
61 // Implementation strategy:
62 // 1. Check that resolution of Duration >= that of IncomingDuration.
63 static_assert(std::is_constructible_v<Duration, IncomingDuration>);
64
65 // 2. As it is higher, then the range is lower (or equal). So casting
66 // Duration::max to IncomingDuration is safe. Do a quick check
67 // that Duration{incoming_duration} won't overflow.
68 if (incoming_duration >
69 std::chrono::duration_cast<IncomingDuration>(Duration::max())) {
70 OnDurationOverflow(
71 std::chrono::duration_cast<std::chrono::duration<double>>(
72 incoming_duration));
73 return Deadline{};
74 }
75
76 // 3. Check that now + Duration{incoming_duration} won't overflow.
77 UASSERT(max_now - now >= Duration{incoming_duration});
78
79 return Deadline(now + Duration{incoming_duration});
80 }
81
82 /// @brief Converts time point to a Deadline
83 ///
84 /// Non-steady clocks may produce inaccurate Deadlines. Prefer using
85 /// Deadline::FromDuration or std::chrono::steady_clock::time_point
86 /// if possible.
87 template <typename Clock, typename Duration>
88 static Deadline FromTimePoint(
89 const std::chrono::time_point<Clock, Duration>& time_point) noexcept {
90 return FromDuration(time_point - Clock::now());
91 }
92
93 /// @cond
94 /// Specialization for the native time point type
95 constexpr static Deadline FromTimePoint(const TimePoint& time_point) {
96 return Deadline(time_point);
97 }
98 /// @endcond
99
100 /// A Deadline that is guaranteed to be IsReached
101 constexpr static Deadline Passed() noexcept { return Deadline{kPassed}; }
102
103 constexpr bool operator==(const Deadline& r) const noexcept {
104 return value_ == r.value_;
105 }
106
107 constexpr bool operator<(const Deadline& r) const noexcept {
108 if (!IsReachable()) return false;
109 if (!r.IsReachable()) return true;
110 return value_ < r.value_;
111 }
112
113 private:
114 constexpr explicit Deadline(TimePoint value) noexcept : value_(value) {}
115
116 static void OnDurationOverflow(
117 std::chrono::duration<double> incoming_duration);
118
119 static constexpr TimePoint kPassed = TimePoint::min();
120
121 TimePoint value_;
122};
123
124} // namespace engine
125
126USERVER_NAMESPACE_END