76 constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
77 constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
80 inline bool IsFinite(
double d) {
81 if (std::isnan(d))
return false;
82 return d != std::numeric_limits<double>::infinity() &&
83 d != -std::numeric_limits<double>::infinity();
86 inline bool IsValidDivisor(
double d) {
87 if (std::isnan(d))
return false;
93 template <
typename Double>
94 inline double Round(Double d) {
95 return d < 0 ? std::ceil(d - 0.5) :
std::floor(d + 0.5);
101 inline void NormalizeTicks(int64_t*
sec, int64_t* ticks) {
109 inline uint128 MakeU128(int64_t
a) {
116 u128 +=
static_cast<uint64_t
>(
a);
121 inline uint128 MakeU128Ticks(Duration d) {
129 uint128 u128 =
static_cast<uint64_t
>(rep_hi);
136 inline Duration MakeDurationFromU128(
uint128 u128,
bool is_neg) {
143 rep_hi =
static_cast<int64_t
>(hi);
151 const uint64_t kMaxRepHi64 = 0x77359400UL;
152 if (h64 >= kMaxRepHi64) {
153 if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
160 const uint128 hi = u128 / kTicksPerSecond128;
163 static_cast<uint32_t
>(
Uint128Low64(u128 - hi * kTicksPerSecond128));
183 inline uint64_t EncodeTwosComp(int64_t
v) {
186 inline int64_t DecodeTwosComp(uint64_t
v) {
return absl::bit_cast<int64_t>(
v); }
194 inline bool SafeAddRepHi(
double a_hi,
double b_hi, Duration* d) {
195 double c = a_hi + b_hi;
196 if (c >= kint64max) {
200 if (c <= kint64min) {
210 template <
typename Ignored>
211 struct SafeMultiply {
227 template <
template <
typename>
class Operation>
228 inline Duration ScaleFixed(Duration d, int64_t r) {
229 const uint128 a = MakeU128Ticks(d);
231 const uint128 q = Operation<uint128>()(a, b);
233 return MakeDurationFromU128(q, is_neg);
238 template <
template <
typename>
class Operation>
239 inline Duration ScaleDouble(Duration d,
double r) {
240 Operation<double> op;
245 double hi_frac = std::modf(hi_doub, &hi_int);
252 double lo_frac = std::modf(lo_doub, &lo_int);
258 if (!SafeAddRepHi(hi_int, lo_int, &ans))
return ans;
263 NormalizeTicks(&hi64, &lo64);
270 inline bool IDivFastPath(
const Duration num,
const Duration den, int64_t* q,
284 if (num_hi >= 0 && num_hi < (kint64max -
kTicksPerSecond) / 1000000000) {
291 if (num_hi >= 0 && num_hi < (kint64max -
kTicksPerSecond) / 10000000) {
310 }
else if (den_hi > 0 && den_lo == 0) {
318 *q = num_hi / den_hi;
325 int64_t quotient = num_hi / den_hi;
326 int64_t rem_sec = num_hi % den_hi;
344 namespace time_internal {
353 if (IDivFastPath(num, den, &q, rem)) {
359 const bool quotient_neg = num_neg != den_neg;
363 return quotient_neg ? kint64min : kint64max;
370 const uint128 a = MakeU128Ticks(num);
371 const uint128 b = MakeU128Ticks(den);
376 if (quotient128 >
uint128(static_cast<uint64_t>(kint64max))) {
377 quotient128 = quotient_neg ?
uint128(static_cast<uint64_t>(kint64min))
378 :
uint128(static_cast<uint64_t>(kint64max));
382 const uint128 remainder128 = a - quotient128 *
b;
383 *rem = MakeDurationFromU128(remainder128, num_neg);
385 if (!quotient_neg || quotient128 == 0) {
390 return -
static_cast<int64_t
>(
Uint128Low64(quotient128 - 1) & kint64max) - 1;
402 const int64_t orig_rep_hi = rep_hi_;
404 DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.
rep_hi_));
406 rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1);
410 if (rhs.
rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) {
421 const int64_t orig_rep_hi = rep_hi_;
423 DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.
rep_hi_));
425 rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1);
429 if (rhs.
rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) {
441 const bool is_neg = (r < 0) != (rep_hi_ < 0);
444 return *
this = ScaleFixed<SafeMultiply>(*
this, r);
449 const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
452 return *
this = ScaleDouble<std::multiplies>(*
this, r);
457 const bool is_neg = (r < 0) != (rep_hi_ < 0);
460 return *
this = ScaleFixed<std::divides>(*
this, r);
465 const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
468 return *
this = ScaleDouble<std::divides>(*
this, r);
480 ? std::numeric_limits<double>::infinity()
481 : -std::numeric_limits<double>::infinity();
499 return d - (d % unit);
517 if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
525 if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
576 return hi / (60 * 60);
613 if (ts.tv_sec == rep_hi) {
619 ts.tv_sec = std::numeric_limits<time_t>::max();
620 ts.tv_nsec = 1000 * 1000 * 1000 - 1;
622 ts.tv_sec = std::numeric_limits<time_t>::min();
634 ts.tv_nsec += 1000 - 1;
635 if (ts.tv_nsec >= 1000 * 1000 * 1000) {
637 ts.tv_nsec -= 1000 * 1000 * 1000;
640 tv.tv_sec = ts.tv_sec;
641 if (tv.tv_sec != ts.tv_sec) {
643 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
646 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
647 tv.tv_usec = 1000 * 1000 - 1;
651 tv.tv_usec =
static_cast<int>(ts.tv_nsec / 1000);
656 return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
659 return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
662 return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
665 return time_internal::ToChronoDuration<std::chrono::seconds>(d);
668 return time_internal::ToChronoDuration<std::chrono::minutes>(d);
671 return time_internal::ToChronoDuration<std::chrono::hours>(d);
683 char* Format64(
char* ep,
int width, int64_t
v) {
686 *--ep =
'0' + (v % 10);
688 while (--width >= 0) *--ep =
'0';
710 const DisplayUnit kDisplayNano = {
"ns", 2, 1e2};
711 const DisplayUnit kDisplayMicro = {
"us", 5, 1e5};
712 const DisplayUnit kDisplayMilli = {
"ms", 8, 1e8};
713 const DisplayUnit kDisplaySec = {
"s", 11, 1e11};
714 const DisplayUnit kDisplayMin = {
"m", -1, 0.0};
715 const DisplayUnit kDisplayHour = {
"h", -1, 0.0};
717 void AppendNumberUnit(std::string*
out, int64_t
n, DisplayUnit unit) {
718 char buf[
sizeof(
"2562047788015216")];
719 char*
const ep =
buf +
sizeof(
buf);
720 char* bp = Format64(ep, 0, n);
721 if (*bp !=
'0' || bp + 1 != ep) {
722 out->append(bp, ep - bp);
723 out->append(unit.abbr);
729 void AppendNumberUnit(std::string* out,
double n, DisplayUnit unit) {
730 const int buf_size = std::numeric_limits<double>::digits10;
731 const int prec = std::min(buf_size, unit.prec);
733 char* ep = buf +
sizeof(
buf);
735 int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
736 int64_t int_part = d;
737 if (int_part != 0 || frac_part != 0) {
738 char* bp = Format64(ep, 0, int_part);
739 out->append(bp, ep - bp);
740 if (frac_part != 0) {
742 bp = Format64(ep, prec, frac_part);
743 while (ep[-1] ==
'0') --ep;
744 out->append(bp, ep - bp);
746 out->append(unit.abbr);
760 if (d == min_duration) {
763 return "-2562047788015215h30m8s";
787 if (s.empty() || s ==
"-") {
798 bool ConsumeDurationNumber(
const char** dpp, int64_t* int_part,
799 int64_t* frac_part, int64_t* frac_scale) {
803 const char* start = *dpp;
804 for (; std::isdigit(**dpp); *dpp += 1) {
805 const int d = **dpp -
'0';
806 if (*int_part > kint64max / 10)
return false;
808 if (*int_part > kint64max - d)
return false;
811 const bool int_part_empty = (*dpp == start);
812 if (**dpp !=
'.')
return !int_part_empty;
813 for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) {
814 const int d = **dpp -
'0';
815 if (*frac_scale <= kint64max / 10) {
821 return !int_part_empty || *frac_scale != 1;
828 bool ConsumeDurationUnit(
const char** start,
Duration* unit) {
829 const char *s = *start;
831 if (strncmp(s,
"ns", 2) == 0) {
834 }
else if (strncmp(s,
"us", 2) == 0) {
837 }
else if (strncmp(s,
"ms", 2) == 0) {
840 }
else if (strncmp(s,
"s", 1) == 0) {
843 }
else if (strncmp(s,
"m", 1) == 0) {
846 }
else if (strncmp(s,
"h", 1) == 0) {
864 const char* start = dur_string.c_str();
867 if (*start ==
'-' || *start ==
'+') {
868 sign = *start ==
'-' ? -1 : 1;
873 if (*start ==
'\0') {
878 if (*start ==
'0' && *(start + 1) ==
'\0') {
883 if (strcmp(start,
"inf") == 0) {
889 while (*start !=
'\0') {
894 if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) ||
895 !ConsumeDurationUnit(&start, &unit)) {
898 if (int_part != 0) dur += sign * int_part * unit;
899 if (frac_part != 0) dur += sign * frac_part * unit / frac_scale;
constexpr int64_t kTicksPerNanosecond
timespec ToTimespec(Duration d)
std::chrono::microseconds ToChronoMicroseconds(Duration d)
int64_t ToInt64Minutes(Duration d)
constexpr int64_t kTicksPerSecond
double ToDoubleMinutes(Duration d)
constexpr Duration Hours(int64_t n)
constexpr uint64_t Uint128High64(uint128 v)
Duration DurationFromTimespec(timespec ts)
int64_t ToInt64Microseconds(Duration d)
std::string UnparseFlag(const T &v)
double ToDoubleMicroseconds(Duration d)
int64_t IDivDuration(bool satq, const Duration num, const Duration den, Duration *rem)
double ToDoubleSeconds(Duration d)
Dest bit_cast(const Source &source)
std::chrono::minutes ToChronoMinutes(Duration d)
constexpr Duration Microseconds(int64_t n)
Duration Floor(const Duration d, const Duration unit)
constexpr uint64_t Uint128Low64(uint128 v)
std::pair< uint64_t, uint64_t > uint128
std::chrono::duration< std::int_fast64_t > seconds
constexpr Duration Milliseconds(int64_t n)
timeval ToTimeval(Duration d)
int64_t ToInt64Nanoseconds(Duration d)
int64_t ToInt64Seconds(Duration d)
Duration & operator%=(Duration rhs)
int64_t ToInt64Hours(Duration d)
double ToDoubleNanoseconds(Duration d)
constexpr Duration MakeDuration(int64_t hi, uint32_t lo)
std::chrono::seconds ToChronoSeconds(Duration d)
std::chrono::hours ToChronoHours(Duration d)
std::string FormatDuration(Duration d)
int64_t IDivDuration(Duration num, Duration den, Duration *rem)
constexpr Duration Minutes(int64_t n)
double ToDoubleMilliseconds(Duration d)
std::chrono::milliseconds ToChronoMilliseconds(Duration d)
Duration & operator/=(int64_t r)
const uint128 kuint128max
int64_t ToInt64Milliseconds(Duration d)
constexpr uint32_t GetRepLo(Duration d)
bool ParseFlag(absl::string_view input, T *dst, std::string *error)
double FDivDuration(Duration num, Duration den)
constexpr Duration Seconds(int64_t n)
Duration Trunc(Duration d, Duration unit)
Duration & operator-=(Duration d)
constexpr int64_t GetRepHi(Duration d)
Duration & operator+=(Duration d)
Duration DurationFromTimeval(timeval tv)
constexpr Duration Nanoseconds(int64_t n)
double ToDoubleHours(Duration d)
Duration AbsDuration(Duration d)
constexpr Duration InfiniteDuration()
Duration & operator*=(int64_t r)
constexpr Duration ZeroDuration()
Duration Ceil(const Duration d, const Duration unit)
constexpr bool IsInfiniteDuration(Duration d)
bool ParseDuration(const std::string &dur_string, Duration *d)
std::chrono::nanoseconds ToChronoNanoseconds(Duration d)