blob: a8e07790c34b900700ba04e07b8455450fb7e025 [file] [log] [blame]
// 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