| // Copyright 2021 gRPC authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef GRPC_CORE_LIB_GPRPP_TIME_H |
| #define GRPC_CORE_LIB_GPRPP_TIME_H |
| |
| #include <grpc/support/port_platform.h> |
| |
| #include <stdint.h> |
| |
| #include <limits> |
| #include <ostream> |
| #include <string> |
| |
| #include <grpc/event_engine/event_engine.h> |
| #include <grpc/impl/codegen/gpr_types.h> |
| #include <grpc/support/time.h> |
| |
| #include "src/core/lib/gpr/time_precise.h" |
| #include "src/core/lib/gpr/useful.h" |
| |
| namespace grpc_core { |
| |
| namespace time_detail { |
| |
| inline int64_t MillisAdd(int64_t a, int64_t b) { |
| if (a == std::numeric_limits<int64_t>::max() || |
| b == std::numeric_limits<int64_t>::max()) { |
| return std::numeric_limits<int64_t>::max(); |
| } |
| if (a == std::numeric_limits<int64_t>::min() || |
| b == std::numeric_limits<int64_t>::min()) { |
| return std::numeric_limits<int64_t>::min(); |
| } |
| return SaturatingAdd(a, b); |
| } |
| |
| constexpr inline int64_t MillisMul(int64_t millis, int64_t mul) { |
| return millis >= std::numeric_limits<int64_t>::max() / mul |
| ? std::numeric_limits<int64_t>::max() |
| : millis <= std::numeric_limits<int64_t>::min() / mul |
| ? std::numeric_limits<int64_t>::min() |
| : millis * mul; |
| } |
| |
| } // namespace time_detail |
| |
| class Duration; |
| |
| // Timestamp represents a discrete point in time. |
| class Timestamp { |
| public: |
| constexpr Timestamp() = default; |
| // Constructs a Timestamp from a gpr_timespec. |
| static Timestamp FromTimespecRoundDown(gpr_timespec t); |
| static Timestamp FromTimespecRoundUp(gpr_timespec t); |
| |
| // Construct a Timestamp from a gpr_cycle_counter. |
| static Timestamp FromCycleCounterRoundUp(gpr_cycle_counter c); |
| static Timestamp FromCycleCounterRoundDown(gpr_cycle_counter c); |
| |
| static constexpr Timestamp FromMillisecondsAfterProcessEpoch(int64_t millis) { |
| return Timestamp(millis); |
| } |
| |
| static constexpr Timestamp ProcessEpoch() { return Timestamp(0); } |
| |
| static constexpr Timestamp InfFuture() { |
| return Timestamp(std::numeric_limits<int64_t>::max()); |
| } |
| |
| static constexpr Timestamp InfPast() { |
| return Timestamp(std::numeric_limits<int64_t>::min()); |
| } |
| |
| constexpr bool operator==(Timestamp other) const { |
| return millis_ == other.millis_; |
| } |
| constexpr bool operator!=(Timestamp other) const { |
| return millis_ != other.millis_; |
| } |
| constexpr bool operator<(Timestamp other) const { |
| return millis_ < other.millis_; |
| } |
| constexpr bool operator<=(Timestamp other) const { |
| return millis_ <= other.millis_; |
| } |
| constexpr bool operator>(Timestamp other) const { |
| return millis_ > other.millis_; |
| } |
| constexpr bool operator>=(Timestamp other) const { |
| return millis_ >= other.millis_; |
| } |
| Timestamp& operator+=(Duration duration); |
| |
| bool is_process_epoch() const { return millis_ == 0; } |
| |
| uint64_t milliseconds_after_process_epoch() const { return millis_; } |
| |
| gpr_timespec as_timespec(gpr_clock_type type) const; |
| |
| std::string ToString() const; |
| |
| private: |
| explicit constexpr Timestamp(int64_t millis) : millis_(millis) {} |
| |
| int64_t millis_ = 0; |
| }; |
| |
| // Duration represents a span of time. |
| class Duration { |
| public: |
| constexpr Duration() noexcept : millis_(0) {} |
| |
| static Duration FromTimespec(gpr_timespec t); |
| static Duration FromSecondsAndNanoseconds(int64_t seconds, int32_t nanos); |
| static Duration FromSecondsAsDouble(double seconds); |
| |
| static constexpr Duration Zero() { return Duration(0); } |
| |
| // Smallest representatable positive duration. |
| static constexpr Duration Epsilon() { return Duration(1); } |
| |
| static constexpr Duration NegativeInfinity() { |
| return Duration(std::numeric_limits<int64_t>::min()); |
| } |
| |
| static constexpr Duration Infinity() { |
| return Duration(std::numeric_limits<int64_t>::max()); |
| } |
| |
| static constexpr Duration Hours(int64_t hours) { |
| return Minutes(time_detail::MillisMul(hours, 60)); |
| } |
| |
| static constexpr Duration Minutes(int64_t minutes) { |
| return Seconds(time_detail::MillisMul(minutes, 60)); |
| } |
| |
| static constexpr Duration Seconds(int64_t seconds) { |
| return Milliseconds(time_detail::MillisMul(seconds, GPR_MS_PER_SEC)); |
| } |
| |
| static constexpr Duration Milliseconds(int64_t millis) { |
| return Duration(millis); |
| } |
| |
| static constexpr Duration MicrosecondsRoundDown(int64_t micros) { |
| return Duration(micros / GPR_US_PER_MS); |
| } |
| |
| static constexpr Duration NanosecondsRoundDown(int64_t nanos) { |
| return Duration(nanos / GPR_NS_PER_MS); |
| } |
| |
| static constexpr Duration MicrosecondsRoundUp(int64_t micros) { |
| return Duration(micros / GPR_US_PER_MS + (micros % GPR_US_PER_MS != 0)); |
| } |
| |
| static constexpr Duration NanosecondsRoundUp(int64_t nanos) { |
| return Duration(nanos / GPR_NS_PER_MS + (nanos % GPR_NS_PER_MS != 0)); |
| } |
| |
| constexpr bool operator==(Duration other) const { |
| return millis_ == other.millis_; |
| } |
| constexpr bool operator!=(Duration other) const { |
| return millis_ != other.millis_; |
| } |
| constexpr bool operator<(Duration other) const { |
| return millis_ < other.millis_; |
| } |
| constexpr bool operator<=(Duration other) const { |
| return millis_ <= other.millis_; |
| } |
| constexpr bool operator>(Duration other) const { |
| return millis_ > other.millis_; |
| } |
| constexpr bool operator>=(Duration other) const { |
| return millis_ >= other.millis_; |
| } |
| Duration& operator/=(int64_t divisor) { |
| if (millis_ == std::numeric_limits<int64_t>::max()) { |
| *this = divisor < 0 ? NegativeInfinity() : Infinity(); |
| } else if (millis_ == std::numeric_limits<int64_t>::min()) { |
| *this = divisor < 0 ? Infinity() : NegativeInfinity(); |
| } else { |
| millis_ /= divisor; |
| } |
| return *this; |
| } |
| Duration& operator*=(double multiplier); |
| Duration& operator+=(Duration other) { |
| millis_ += other.millis_; |
| return *this; |
| } |
| |
| constexpr int64_t millis() const { return millis_; } |
| double seconds() const { return static_cast<double>(millis_) / 1000.0; } |
| |
| // NOLINTNEXTLINE: google-explicit-constructor |
| operator grpc_event_engine::experimental::EventEngine::Duration() const; |
| |
| gpr_timespec as_timespec() const; |
| |
| std::string ToString() const; |
| |
| // Returns the duration in the JSON form corresponding to a |
| // google.protobuf.Duration proto, as defined here: |
| // https://developers.google.com/protocol-buffers/docs/proto3#json |
| std::string ToJsonString() const; |
| |
| private: |
| explicit constexpr Duration(int64_t millis) : millis_(millis) {} |
| |
| int64_t millis_; |
| }; |
| |
| inline Duration operator+(Duration lhs, Duration rhs) { |
| return Duration::Milliseconds( |
| time_detail::MillisAdd(lhs.millis(), rhs.millis())); |
| } |
| |
| inline Duration operator-(Duration lhs, Duration rhs) { |
| return Duration::Milliseconds( |
| time_detail::MillisAdd(lhs.millis(), -rhs.millis())); |
| } |
| |
| inline Timestamp operator+(Timestamp lhs, Duration rhs) { |
| return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd( |
| lhs.milliseconds_after_process_epoch(), rhs.millis())); |
| } |
| |
| inline Timestamp operator-(Timestamp lhs, Duration rhs) { |
| return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd( |
| lhs.milliseconds_after_process_epoch(), -rhs.millis())); |
| } |
| |
| inline Timestamp operator+(Duration lhs, Timestamp rhs) { return rhs + lhs; } |
| |
| inline Duration operator-(Timestamp lhs, Timestamp rhs) { |
| return Duration::Milliseconds( |
| time_detail::MillisAdd(lhs.milliseconds_after_process_epoch(), |
| -rhs.milliseconds_after_process_epoch())); |
| } |
| |
| inline Duration operator*(Duration lhs, double rhs) { |
| if (lhs == Duration::Infinity()) { |
| return rhs < 0 ? Duration::NegativeInfinity() : Duration::Infinity(); |
| } |
| if (lhs == Duration::NegativeInfinity()) { |
| return rhs < 0 ? Duration::Infinity() : Duration::NegativeInfinity(); |
| } |
| return Duration::FromSecondsAsDouble(lhs.millis() * rhs / 1000.0); |
| } |
| |
| inline Duration operator*(double lhs, Duration rhs) { return rhs * lhs; } |
| |
| inline Duration operator/(Duration lhs, int64_t rhs) { |
| lhs /= rhs; |
| return lhs; |
| } |
| |
| inline Duration Duration::FromSecondsAndNanoseconds(int64_t seconds, |
| int32_t nanos) { |
| return Seconds(seconds) + NanosecondsRoundDown(nanos); |
| } |
| |
| inline Duration Duration::FromSecondsAsDouble(double seconds) { |
| double millis = seconds * 1000.0; |
| if (millis >= static_cast<double>(std::numeric_limits<int64_t>::max())) { |
| return Infinity(); |
| } |
| if (millis <= static_cast<double>(std::numeric_limits<int64_t>::min())) { |
| return NegativeInfinity(); |
| } |
| return Milliseconds(static_cast<int64_t>(millis)); |
| } |
| |
| inline Duration& Duration::operator*=(double multiplier) { |
| *this = *this * multiplier; |
| return *this; |
| } |
| |
| inline Timestamp& Timestamp::operator+=(Duration duration) { |
| return *this = (*this + duration); |
| } |
| |
| void TestOnlySetProcessEpoch(gpr_timespec epoch); |
| |
| std::ostream& operator<<(std::ostream& out, Timestamp timestamp); |
| std::ostream& operator<<(std::ostream& out, Duration duration); |
| |
| } // namespace grpc_core |
| |
| #endif // GRPC_CORE_LIB_GPRPP_TIME_H |