// Copyright 2017 The Abseil 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 // // https://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. // The implementation of the absl::Duration class, which is declared in // //absl/time.h. This class behaves like a numeric type; it has no public // methods and is used only through the operators defined here. // // Implementation notes: // // An absl::Duration is represented as // // rep_hi_ : (int64_t) Whole seconds // rep_lo_ : (uint32_t) Fractions of a second // // The seconds value (rep_hi_) may be positive or negative as appropriate. // The fractional seconds (rep_lo_) is always a positive offset from rep_hi_. // The API for Duration guarantees at least nanosecond resolution, which // means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds. // However, to utilize more of the available 32 bits of space in rep_lo_, // we instead store quarters of a nanosecond in rep_lo_ resulting in a max // value of 4B - 1. This allows us to correctly handle calculations like // 0.5 nanos + 0.5 nanos = 1 nano. The following example shows the actual // Duration rep using quarters of a nanosecond. // // 2.5 sec = {rep_hi_=2, rep_lo_=2000000000} // lo = 4 * 500000000 // -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000} // // Infinite durations are represented as Durations with the rep_lo_ field set // to all 1s. // // +InfiniteDuration: // rep_hi_ : kint64max // rep_lo_ : ~0U // // -InfiniteDuration: // rep_hi_ : kint64min // rep_lo_ : ~0U // // Arithmetic overflows/underflows to +/- infinity and saturates. #if defined(_MSC_VER) #include <winsock2.h> // for timeval #endif #include <algorithm> #include <cassert> #include <chrono> // NOLINT(build/c++11) #include <cmath> #include <cstdint> #include <cstdlib> #include <cstring> #include <ctime> #include <functional> #include <limits> #include <string> #include "absl/base/attributes.h" #include "absl/base/casts.h" #include "absl/base/config.h" #include "absl/numeric/int128.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" #include "absl/time/time.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { kTicksPerNanosecond; kTicksPerSecond; constexpr int64_t kint64max = …; constexpr int64_t kint64min = …; // Can't use std::isinfinite() because it doesn't exist on windows. inline bool IsFinite(double d) { … } inline bool IsValidDivisor(double d) { … } // *sec may be positive or negative. *ticks must be in the range // -kTicksPerSecond < *ticks < kTicksPerSecond. If *ticks is negative it // will be normalized to a positive value by adjusting *sec accordingly. inline void NormalizeTicks(int64_t* sec, int64_t* ticks) { … } // Makes a uint128 from the absolute value of the given scalar. inline uint128 MakeU128(int64_t a) { … } // Makes a uint128 count of ticks out of the absolute value of the Duration. inline uint128 MakeU128Ticks(Duration d) { … } // Breaks a uint128 of ticks into a Duration. inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) { … } // Convert between int64_t and uint64_t, preserving representation. This // allows us to do arithmetic in the unsigned domain, where overflow has // well-defined behavior. See operator+=() and operator-=(). // // C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef // name intN_t designates a signed integer type with width N, no padding // bits, and a two's complement representation." So, we can convert to // and from the corresponding uint64_t value using a bit cast. inline uint64_t EncodeTwosComp(int64_t v) { … } inline int64_t DecodeTwosComp(uint64_t v) { … } // Note: The overflow detection in this function is done using greater/less *or // equal* because kint64max/min is too large to be represented exactly in a // double (which only has 53 bits of precision). In order to avoid assigning to // rep->hi a double value that is too large for an int64_t (and therefore is // undefined), we must consider computations that equal kint64max/min as a // double as overflow cases. inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) { … } // A functor that's similar to std::multiplies<T>, except this returns the max // T value instead of overflowing. This is only defined for uint128. template <typename Ignored> struct SafeMultiply { … }; // Scales (i.e., multiplies or divides, depending on the Operation template) // the Duration d by the int64_t r. template <template <typename> class Operation> inline Duration ScaleFixed(Duration d, int64_t r) { … } // Scales (i.e., multiplies or divides, depending on the Operation template) // the Duration d by the double r. template <template <typename> class Operation> inline Duration ScaleDouble(Duration d, double r) { … } // Tries to divide num by den as fast as possible by looking for common, easy // cases. If the division was done, the quotient is in *q and the remainder is // in *rem and true will be returned. inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q, Duration* rem) { … } } // namespace namespace { int64_t IDivSlowPath(bool satq, const Duration num, const Duration den, Duration* rem) { … } // The 'satq' argument indicates whether the quotient should saturate at the // bounds of int64_t. If it does saturate, the difference will spill over to // the remainder. If it does not saturate, the remainder remain accurate, // but the returned quotient will over/underflow int64_t and should not be used. ABSL_ATTRIBUTE_ALWAYS_INLINE inline int64_t IDivDurationImpl(bool satq, const Duration num, const Duration den, Duration* rem) { … } } // namespace int64_t IDivDuration(Duration num, Duration den, Duration* rem) { … } // // Additive operators. // Duration& Duration::operator+=(Duration rhs) { … } Duration& Duration::operator-=(Duration rhs) { … } // // Multiplicative operators. // Duration& Duration::operator*=(int64_t r) { … } Duration& Duration::operator*=(double r) { … } Duration& Duration::operator/=(int64_t r) { … } Duration& Duration::operator/=(double r) { … } Duration& Duration::operator%=(Duration rhs) { … } double FDivDuration(Duration num, Duration den) { … } // // Trunc/Floor/Ceil. // Duration Trunc(Duration d, Duration unit) { … } Duration Floor(const Duration d, const Duration unit) { … } Duration Ceil(const Duration d, const Duration unit) { … } // // Factory functions. // Duration DurationFromTimespec(timespec ts) { … } Duration DurationFromTimeval(timeval tv) { … } // // Conversion to other duration types. // int64_t ToInt64Nanoseconds(Duration d) { … } int64_t ToInt64Microseconds(Duration d) { … } int64_t ToInt64Milliseconds(Duration d) { … } int64_t ToInt64Seconds(Duration d) { … } int64_t ToInt64Minutes(Duration d) { … } int64_t ToInt64Hours(Duration d) { … } double ToDoubleNanoseconds(Duration d) { … } double ToDoubleMicroseconds(Duration d) { … } double ToDoubleMilliseconds(Duration d) { … } double ToDoubleSeconds(Duration d) { … } double ToDoubleMinutes(Duration d) { … } double ToDoubleHours(Duration d) { … } timespec ToTimespec(Duration d) { … } timeval ToTimeval(Duration d) { … } std::chrono::nanoseconds ToChronoNanoseconds(Duration d) { … } std::chrono::microseconds ToChronoMicroseconds(Duration d) { … } std::chrono::milliseconds ToChronoMilliseconds(Duration d) { … } std::chrono::seconds ToChronoSeconds(Duration d) { … } std::chrono::minutes ToChronoMinutes(Duration d) { … } std::chrono::hours ToChronoHours(Duration d) { … } // // To/From string formatting. // namespace { // Formats a positive 64-bit integer in the given field width. Note that // it is up to the caller of Format64() to ensure that there is sufficient // space before ep to hold the conversion. char* Format64(char* ep, int width, int64_t v) { … } // Helpers for FormatDuration() that format 'n' and append it to 'out' // followed by the given 'unit'. If 'n' formats to "0", nothing is // appended (not even the unit). // A type that encapsulates how to display a value of a particular unit. For // values that are displayed with fractional parts, the precision indicates // where to round the value. The precision varies with the display unit because // a Duration can hold only quarters of a nanosecond, so displaying information // beyond that is just noise. // // For example, a microsecond value of 42.00025xxxxx should not display beyond 5 // fractional digits, because it is in the noise of what a Duration can // represent. struct DisplayUnit { … }; ABSL_CONST_INIT const DisplayUnit kDisplayNano = …; ABSL_CONST_INIT const DisplayUnit kDisplayMicro = …; ABSL_CONST_INIT const DisplayUnit kDisplayMilli = …; ABSL_CONST_INIT const DisplayUnit kDisplaySec = …; ABSL_CONST_INIT const DisplayUnit kDisplayMin = …; // prec ignored ABSL_CONST_INIT const DisplayUnit kDisplayHour = …; // prec ignored void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) { … } // Note: unit.prec is limited to double's digits10 value (typically 15) so it // always fits in buf[]. void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) { … } } // namespace // From Go's doc at https://golang.org/pkg/time/#Duration.String // [FormatDuration] returns a string representing the duration in the // form "72h3m0.5s". Leading zero units are omitted. As a special // case, durations less than one second format use a smaller unit // (milli-, micro-, or nanoseconds) to ensure that the leading digit // is non-zero. // Unlike Go, we format the zero duration as 0, with no unit. std::string FormatDuration(Duration d) { … } namespace { // A helper for ParseDuration() that parses a leading number from the given // string and stores the result in *int_part/*frac_part/*frac_scale. The // given string pointer is modified to point to the first unconsumed char. bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part, int64_t* frac_part, int64_t* frac_scale) { … } // A helper for ParseDuration() that parses a leading unit designator (e.g., // ns, us, ms, s, m, h) from the given string and stores the resulting unit // in "*unit". The given string pointer is modified to point to the first // unconsumed char. bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) { … } } // namespace // From Go's doc at https://golang.org/pkg/time/#ParseDuration // [ParseDuration] parses a duration string. A duration string is // a possibly signed sequence of decimal numbers, each with optional // fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". // Valid time units are "ns", "us" "ms", "s", "m", "h". bool ParseDuration(absl::string_view dur_sv, Duration* d) { … } bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) { … } std::string AbslUnparseFlag(Duration d) { … } bool ParseFlag(const std::string& text, Duration* dst, std::string* ) { … } std::string UnparseFlag(Duration d) { … } ABSL_NAMESPACE_END } // namespace absl