tvl-depot/absl/time/duration.cc

916 lines
30 KiB
C++
Raw Normal View History

2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
//
// 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.
Export of internal Abseil changes. -- 7a6ff16a85beb730c172d5d25cf1b5e1be885c56 by Laramie Leavitt <lar@google.com>: Internal change. PiperOrigin-RevId: 254454546 -- ff8f9bafaefc26d451f576ea4a06d150aed63f6f by Andy Soffer <asoffer@google.com>: Internal changes PiperOrigin-RevId: 254451562 -- deefc5b651b479ce36f0b4ef203e119c0c8936f2 by CJ Johnson <johnsoncj@google.com>: Account for subtracting unsigned values from the size of InlinedVector PiperOrigin-RevId: 254450625 -- 3c677316a27bcadc17e41957c809ca472d5fef14 by Andy Soffer <asoffer@google.com>: Add C++17's std::make_from_tuple to absl/utility/utility.h PiperOrigin-RevId: 254411573 -- 4ee3536a918830eeec402a28fc31a62c7c90b940 by CJ Johnson <johnsoncj@google.com>: Adds benchmark for the rest of the InlinedVector public API PiperOrigin-RevId: 254408378 -- e5a21a00700ee83498ff1efbf649169756463ee4 by CJ Johnson <johnsoncj@google.com>: Updates the definition of InlinedVector::shrink_to_fit() to be exception safe and adds exception safety tests for it. PiperOrigin-RevId: 254401387 -- 2ea82e72b86d82d78b4e4712a63a55981b53c64b by Laramie Leavitt <lar@google.com>: Use absl::InsecureBitGen in place of std::mt19937 in tests absl/random/...distribution_test.cc PiperOrigin-RevId: 254289444 -- fa099e02c413a7ffda732415e8105cad26a90337 by Andy Soffer <asoffer@google.com>: Internal changes PiperOrigin-RevId: 254286334 -- ce34b7f36933b30cfa35b9c9a5697a792b5666e4 by Andy Soffer <asoffer@google.com>: Internal changes PiperOrigin-RevId: 254273059 -- 6f9c473da7c2090c2e85a37c5f00622e8a912a89 by Jorg Brown <jorg@google.com>: Change absl::container_internal::CompressedTuple to instantiate its internal Storage class with the name of the type it's holding, rather than the name of the Tuple. This is not an externally-visible change, other than less compiler memory is used and less debug information is generated. PiperOrigin-RevId: 254269285 -- 8bd3c186bf2fc0c55d8a2dd6f28a5327502c9fba by Andy Soffer <asoffer@google.com>: Adding short-hand IntervalClosed for IntervalClosedClosed and IntervalOpen for IntervalOpenOpen. PiperOrigin-RevId: 254252419 -- ea957f99b6a04fccd42aa05605605f3b44b1ecfd by Abseil Team <absl-team@google.com>: Do not directly use __SIZEOF_INT128__. In order to avoid linker errors when building with clang-cl (__fixunsdfti, __udivti3 and __fixunssfti are undefined), this CL uses ABSL_HAVE_INTRINSIC_INT128 which is not defined for clang-cl. PiperOrigin-RevId: 254250739 -- 89ab385cd26b34d64130bce856253aaba96d2345 by Andy Soffer <asoffer@google.com>: Internal changes PiperOrigin-RevId: 254242321 -- cffc793d93eca6d6bdf7de733847b6ab4a255ae9 by CJ Johnson <johnsoncj@google.com>: Adds benchmark for InlinedVector::reserve(size_type) PiperOrigin-RevId: 254199226 -- c90c7a9fa3c8f0c9d5114036979548b055ea2f2a by Gennadiy Rozental <rogeeff@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 254072387 -- c4c388beae016c9570ab54ffa1d52660e4a85b7b by Laramie Leavitt <lar@google.com>: Internal cleanup. PiperOrigin-RevId: 254062381 -- d3c992e221cc74e5372d0c8fa410170b6a43c062 by Tom Manshreck <shreck@google.com>: Update distributions.h to Abseil standards PiperOrigin-RevId: 254054946 -- d15ad0035c34ef11b14fadc5a4a2d3ec415f5518 by CJ Johnson <johnsoncj@google.com>: Removes functions with only one caller from the implementation details of InlinedVector by manually inlining the definitions PiperOrigin-RevId: 254005427 -- 2f37e807efc3a8ef1f4b539bdd379917d4151520 by Andy Soffer <asoffer@google.com>: Initial release of Abseil Random PiperOrigin-RevId: 253999861 -- 24ed1694b6430791d781ed533a8f8ccf6cac5856 by CJ Johnson <johnsoncj@google.com>: Updates the definition of InlinedVector::assign(...)/InlinedVector::operator=(...) to new, exception-safe implementations with exception safety tests to boot PiperOrigin-RevId: 253993691 -- 5613d95f5a7e34a535cfaeadce801441e990843e by CJ Johnson <johnsoncj@google.com>: Adds benchmarks for InlinedVector::shrink_to_fit() PiperOrigin-RevId: 253989647 -- 2a96ddfdac40bbb8cb6a7f1aeab90917067c6e63 by Abseil Team <absl-team@google.com>: Initial release of Abseil Random PiperOrigin-RevId: 253927497 -- bf1aff8fc9ffa921ad74643e9525ecf25b0d8dc1 by Andy Soffer <asoffer@google.com>: Initial release of Abseil Random PiperOrigin-RevId: 253920512 -- bfc03f4a3dcda3cf3a4b84bdb84cda24e3394f41 by Laramie Leavitt <lar@google.com>: Internal change. PiperOrigin-RevId: 253886486 -- 05036cfcc078ca7c5f581a00dfb0daed568cbb69 by Eric Fiselier <ericwf@google.com>: Don't include `winsock2.h` because it drags in `windows.h` and friends, and they define awful macros like OPAQUE, ERROR, and more. This has the potential to break abseil users. Instead we only forward declare `timeval` and require Windows users include `winsock2.h` themselves. This is both inconsistent and poor QoI, but so including 'windows.h' is bad too. PiperOrigin-RevId: 253852615 GitOrigin-RevId: 7a6ff16a85beb730c172d5d25cf1b5e1be885c56 Change-Id: Icd6aff87da26f29ec8915da856f051129987cef6
2019-06-21 22:11:42 +02:00
#if defined(_MSC_VER)
#include <winsock2.h> // for timeval
#endif
2017-09-19 22:54:40 +02:00
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cerrno>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <functional>
#include <limits>
#include <string>
#include "absl/base/casts.h"
2017-09-19 22:54:40 +02:00
#include "absl/numeric/int128.h"
#include "absl/time/time.h"
namespace absl {
namespace {
using time_internal::kTicksPerNanosecond;
using time_internal::kTicksPerSecond;
constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
// Can't use std::isinfinite() because it doesn't exist on windows.
inline bool IsFinite(double d) {
Export of internal Abseil changes. -- cd076f55c1fa600131f6dda392533dfe61679fc0 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 224008762 -- e05f62b01286d51044ff86ec6ef565749b9faf82 by Abseil Team <absl-team@google.com>: Create a pow10() test helper function to compute guaranteed-precise double values of 10^x. Not all standard libraries ship bit-accurate pow() functions, causing tests to fail that rely on expected values generated by it. PiperOrigin-RevId: 223883762 -- fd88e5e3f7ab80f7f5df9fd1488cd58b4573be69 by Abseil Team <absl-team@google.com>: Remove some absl:: qualifications to work around inline namespace bugs on MSVC 2015. PiperOrigin-RevId: 223869642 -- 6276cfff969d596edd36a2bbaba65ee045808903 by Abseil Team <absl-team@google.com>: Update absl/memory/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223854224 -- 359de9afc7a34c975fd3e0cbc52afd96637d97bd by Chris Kennelly <ckennelly@google.com>: Mark spinlock_benchmark_common as alwayslink = 1. PiperOrigin-RevId: 223844536 -- 450cd8cbe2789a6d54ed1eb87170259bb334f8b9 by Abseil Team <absl-team@google.com>: Support .* (pointer-to-member dereference) expressions in demangle.cc. PiperOrigin-RevId: 223826797 -- 772ca92179c3634f3e31a80bbc272ed8022e3572 by Abseil Team <absl-team@google.com>: Fix misspellings in absl::variant comments and replace a ' with a `. PiperOrigin-RevId: 223807911 -- 35dcdc2fbf299d195658aac101887f6dcad1de2f by Abseil Team <absl-team@google.com>: Bug fix in CMakeLists.txt file (SRCS --> HDRS). The compressed_tuple header-only library is being defined with the SRCS parameter instead of the HDRS parameter and this has been observed to cause some builds on some platforms to attempt to create a static library from it which fails since there are no .cc sources. PiperOrigin-RevId: 223805367 -- 4a57a3d2045bb137c0c97958e45ce425190b8d3e by Chris Kennelly <ckennelly@google.com>: Add test that absl::make_unique value initializes memory. PiperOrigin-RevId: 223801819 -- dfe8289d7f4dcc6bb568a26aaf192a89e896bdfd by Chris Kennelly <ckennelly@google.com>: SpinLock: Use exchange to avoid missing wakeups. The default fast path for SpinLock::Unlock does not use an atomic. If the SpinLock becomes contended while we are unlocking between lockword_.load and lockword_.store, we will fail to wake up the new waiter. This can cause unexpected latency spikes. PiperOrigin-RevId: 223800369 -- 9b9d35df786482f0016f77dd31691eff81503d23 by Abseil Team <absl-team@google.com>: Update absl/hash/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223755819 -- c2014e2704b87e7cdce2d2a0287c7e2397752296 by Abseil Team <absl-team@google.com>: Update absl/debugging/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223751986 -- d83a4e09126400e3fd80645cb03ee558f532271e by Derek Mauro <dmauro@google.com>: Cleanup synchronization benchmarks. PiperOrigin-RevId: 223589416 -- fad140b473586531b5b12843f942ec27dfcf5e93 by CJ Johnson <johnsoncj@google.com>: Makes unifies the order of forward_iterator and input_iterator overloads PiperOrigin-RevId: 223580660 -- 6cd7c96faa7cc5f79f574e35a1b13837ef187d05 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223561629 -- bd2e545356b0f548af0e3c14bb2f7f0e712e49d0 by Shaindel Schwartz <shaindel@google.com>: Remove misleading comments. try_emplace() does not exist for the hash_set containers. PiperOrigin-RevId: 223543089 -- 0cd380a53b587eb7aacc4003a4a3bbb6c78d7c10 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 223512551 -- 7156dfee599cb72e9adddfe0e6ae07a95ddf10bb by Greg Miller <jgm@google.com>: Fixes UB that would result from constructing, multiplying, or dividing a Duration with a double "NaN" value. This CL changes the absl::Duration *implementation* to return an InfiniteDuration value that has the same sign as the given NaN. PiperOrigin-RevId: 223407499 -- 196b7d18609958267951882baf7f9429e49bcafa by CJ Johnson <johnsoncj@google.com>: Addresses NVCC+MSVC compilation bug where `inlined_capacity()` was not considered valid in constexpr PiperOrigin-RevId: 223397718 GitOrigin-RevId: cd076f55c1fa600131f6dda392533dfe61679fc0 Change-Id: I5423ca6470f661a7c6f73aa8fee49990446f157f
2018-12-04 20:01:12 +01:00
if (std::isnan(d)) return false;
2017-09-19 22:54:40 +02:00
return d != std::numeric_limits<double>::infinity() &&
d != -std::numeric_limits<double>::infinity();
}
Export of internal Abseil changes. -- cd076f55c1fa600131f6dda392533dfe61679fc0 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 224008762 -- e05f62b01286d51044ff86ec6ef565749b9faf82 by Abseil Team <absl-team@google.com>: Create a pow10() test helper function to compute guaranteed-precise double values of 10^x. Not all standard libraries ship bit-accurate pow() functions, causing tests to fail that rely on expected values generated by it. PiperOrigin-RevId: 223883762 -- fd88e5e3f7ab80f7f5df9fd1488cd58b4573be69 by Abseil Team <absl-team@google.com>: Remove some absl:: qualifications to work around inline namespace bugs on MSVC 2015. PiperOrigin-RevId: 223869642 -- 6276cfff969d596edd36a2bbaba65ee045808903 by Abseil Team <absl-team@google.com>: Update absl/memory/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223854224 -- 359de9afc7a34c975fd3e0cbc52afd96637d97bd by Chris Kennelly <ckennelly@google.com>: Mark spinlock_benchmark_common as alwayslink = 1. PiperOrigin-RevId: 223844536 -- 450cd8cbe2789a6d54ed1eb87170259bb334f8b9 by Abseil Team <absl-team@google.com>: Support .* (pointer-to-member dereference) expressions in demangle.cc. PiperOrigin-RevId: 223826797 -- 772ca92179c3634f3e31a80bbc272ed8022e3572 by Abseil Team <absl-team@google.com>: Fix misspellings in absl::variant comments and replace a ' with a `. PiperOrigin-RevId: 223807911 -- 35dcdc2fbf299d195658aac101887f6dcad1de2f by Abseil Team <absl-team@google.com>: Bug fix in CMakeLists.txt file (SRCS --> HDRS). The compressed_tuple header-only library is being defined with the SRCS parameter instead of the HDRS parameter and this has been observed to cause some builds on some platforms to attempt to create a static library from it which fails since there are no .cc sources. PiperOrigin-RevId: 223805367 -- 4a57a3d2045bb137c0c97958e45ce425190b8d3e by Chris Kennelly <ckennelly@google.com>: Add test that absl::make_unique value initializes memory. PiperOrigin-RevId: 223801819 -- dfe8289d7f4dcc6bb568a26aaf192a89e896bdfd by Chris Kennelly <ckennelly@google.com>: SpinLock: Use exchange to avoid missing wakeups. The default fast path for SpinLock::Unlock does not use an atomic. If the SpinLock becomes contended while we are unlocking between lockword_.load and lockword_.store, we will fail to wake up the new waiter. This can cause unexpected latency spikes. PiperOrigin-RevId: 223800369 -- 9b9d35df786482f0016f77dd31691eff81503d23 by Abseil Team <absl-team@google.com>: Update absl/hash/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223755819 -- c2014e2704b87e7cdce2d2a0287c7e2397752296 by Abseil Team <absl-team@google.com>: Update absl/debugging/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223751986 -- d83a4e09126400e3fd80645cb03ee558f532271e by Derek Mauro <dmauro@google.com>: Cleanup synchronization benchmarks. PiperOrigin-RevId: 223589416 -- fad140b473586531b5b12843f942ec27dfcf5e93 by CJ Johnson <johnsoncj@google.com>: Makes unifies the order of forward_iterator and input_iterator overloads PiperOrigin-RevId: 223580660 -- 6cd7c96faa7cc5f79f574e35a1b13837ef187d05 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223561629 -- bd2e545356b0f548af0e3c14bb2f7f0e712e49d0 by Shaindel Schwartz <shaindel@google.com>: Remove misleading comments. try_emplace() does not exist for the hash_set containers. PiperOrigin-RevId: 223543089 -- 0cd380a53b587eb7aacc4003a4a3bbb6c78d7c10 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 223512551 -- 7156dfee599cb72e9adddfe0e6ae07a95ddf10bb by Greg Miller <jgm@google.com>: Fixes UB that would result from constructing, multiplying, or dividing a Duration with a double "NaN" value. This CL changes the absl::Duration *implementation* to return an InfiniteDuration value that has the same sign as the given NaN. PiperOrigin-RevId: 223407499 -- 196b7d18609958267951882baf7f9429e49bcafa by CJ Johnson <johnsoncj@google.com>: Addresses NVCC+MSVC compilation bug where `inlined_capacity()` was not considered valid in constexpr PiperOrigin-RevId: 223397718 GitOrigin-RevId: cd076f55c1fa600131f6dda392533dfe61679fc0 Change-Id: I5423ca6470f661a7c6f73aa8fee49990446f157f
2018-12-04 20:01:12 +01:00
inline bool IsValidDivisor(double d) {
if (std::isnan(d)) return false;
return d != 0.0;
}
2017-09-19 22:54:40 +02:00
// Can't use std::round() because it is only available in C++11.
// Note that we ignore the possibility of floating-point over/underflow.
template <typename Double>
inline double Round(Double d) {
return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5);
}
// *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) {
if (*ticks < 0) {
--*sec;
*ticks += kTicksPerSecond;
}
}
// Makes a uint128 from the absolute value of the given scalar.
inline uint128 MakeU128(int64_t a) {
uint128 u128 = 0;
if (a < 0) {
++u128;
++a; // Makes it safe to negate 'a'
a = -a;
}
u128 += static_cast<uint64_t>(a);
return u128;
}
// Makes a uint128 count of ticks out of the absolute value of the Duration.
inline uint128 MakeU128Ticks(Duration d) {
int64_t rep_hi = time_internal::GetRepHi(d);
uint32_t rep_lo = time_internal::GetRepLo(d);
if (rep_hi < 0) {
++rep_hi;
rep_hi = -rep_hi;
rep_lo = kTicksPerSecond - rep_lo;
}
uint128 u128 = static_cast<uint64_t>(rep_hi);
u128 *= static_cast<uint64_t>(kTicksPerSecond);
u128 += rep_lo;
return u128;
}
// Breaks a uint128 of ticks into a Duration.
inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) {
int64_t rep_hi;
uint32_t rep_lo;
const uint64_t h64 = Uint128High64(u128);
const uint64_t l64 = Uint128Low64(u128);
if (h64 == 0) { // fastpath
const uint64_t hi = l64 / kTicksPerSecond;
rep_hi = static_cast<int64_t>(hi);
rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond);
} else {
// kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond).
// Any positive tick count whose high 64 bits are >= kMaxRepHi64
// is not representable as a Duration. A negative tick count can
// have its high 64 bits == kMaxRepHi64 but only when the low 64
// bits are all zero, otherwise it is not representable either.
const uint64_t kMaxRepHi64 = 0x77359400UL;
if (h64 >= kMaxRepHi64) {
if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
// Avoid trying to represent -kint64min below.
return time_internal::MakeDuration(kint64min);
}
return is_neg ? -InfiniteDuration() : InfiniteDuration();
}
const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond);
const uint128 hi = u128 / kTicksPerSecond128;
rep_hi = static_cast<int64_t>(Uint128Low64(hi));
rep_lo =
static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128));
}
if (is_neg) {
rep_hi = -rep_hi;
if (rep_lo != 0) {
--rep_hi;
rep_lo = kTicksPerSecond - rep_lo;
}
}
return time_internal::MakeDuration(rep_hi, rep_lo);
}
// 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.
2018-04-18 14:56:39 +02:00
inline uint64_t EncodeTwosComp(int64_t v) {
return absl::bit_cast<uint64_t>(v);
}
inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); }
2017-09-19 22:54:40 +02:00
// 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) {
double c = a_hi + b_hi;
if (c >= kint64max) {
*d = InfiniteDuration();
return false;
}
if (c <= kint64min) {
*d = -InfiniteDuration();
return false;
}
*d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
return true;
}
// 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 {
uint128 operator()(uint128 a, uint128 b) const {
// b hi is always zero because it originated as an int64_t.
assert(Uint128High64(b) == 0);
// Fastpath to avoid the expensive overflow check with division.
if (Uint128High64(a) == 0) {
return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0)
? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b))
: a * b;
}
return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b;
}
};
// 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) {
const uint128 a = MakeU128Ticks(d);
const uint128 b = MakeU128(r);
const uint128 q = Operation<uint128>()(a, b);
const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0);
return MakeDurationFromU128(q, is_neg);
}
// 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) {
Operation<double> op;
double hi_doub = op(time_internal::GetRepHi(d), r);
double lo_doub = op(time_internal::GetRepLo(d), r);
double hi_int = 0;
double hi_frac = std::modf(hi_doub, &hi_int);
// Moves hi's fractional bits to lo.
lo_doub /= kTicksPerSecond;
lo_doub += hi_frac;
double lo_int = 0;
double lo_frac = std::modf(lo_doub, &lo_int);
// Rolls lo into hi if necessary.
int64_t lo64 = Round(lo_frac * kTicksPerSecond);
Duration ans;
if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
int64_t hi64 = time_internal::GetRepHi(ans);
if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
hi64 = time_internal::GetRepHi(ans);
lo64 %= kTicksPerSecond;
NormalizeTicks(&hi64, &lo64);
return time_internal::MakeDuration(hi64, lo64);
}
// 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) {
// Bail if num or den is an infinity.
if (time_internal::IsInfiniteDuration(num) ||
time_internal::IsInfiniteDuration(den))
return false;
int64_t num_hi = time_internal::GetRepHi(num);
uint32_t num_lo = time_internal::GetRepLo(num);
int64_t den_hi = time_internal::GetRepHi(den);
uint32_t den_lo = time_internal::GetRepLo(den);
if (den_hi == 0 && den_lo == kTicksPerNanosecond) {
// Dividing by 1ns
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) {
*q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond;
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
return true;
}
} else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) {
// Dividing by 100ns (common when converting to Universal time)
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) {
*q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond);
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
return true;
}
} else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) {
// Dividing by 1us
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) {
*q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond);
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
return true;
}
} else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) {
// Dividing by 1ms
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) {
*q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond);
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
return true;
}
} else if (den_hi > 0 && den_lo == 0) {
// Dividing by positive multiple of 1s
if (num_hi >= 0) {
if (den_hi == 1) {
*q = num_hi;
*rem = time_internal::MakeDuration(0, num_lo);
return true;
}
*q = num_hi / den_hi;
*rem = time_internal::MakeDuration(num_hi % den_hi, num_lo);
return true;
}
if (num_lo != 0) {
num_hi += 1;
}
int64_t quotient = num_hi / den_hi;
int64_t rem_sec = num_hi % den_hi;
if (rem_sec > 0) {
rem_sec -= den_hi;
quotient += 1;
}
if (num_lo != 0) {
rem_sec -= 1;
}
*q = quotient;
*rem = time_internal::MakeDuration(rem_sec, num_lo);
return true;
}
return false;
}
} // namespace
namespace time_internal {
// 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.
int64_t IDivDuration(bool satq, const Duration num, const Duration den,
Duration* rem) {
int64_t q = 0;
if (IDivFastPath(num, den, &q, rem)) {
return q;
}
const bool num_neg = num < ZeroDuration();
const bool den_neg = den < ZeroDuration();
const bool quotient_neg = num_neg != den_neg;
if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
*rem = num_neg ? -InfiniteDuration() : InfiniteDuration();
return quotient_neg ? kint64min : kint64max;
}
if (time_internal::IsInfiniteDuration(den)) {
*rem = num;
return 0;
}
const uint128 a = MakeU128Ticks(num);
const uint128 b = MakeU128Ticks(den);
uint128 quotient128 = a / b;
if (satq) {
// Limits the quotient to the range of int64_t.
if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) {
quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min))
: uint128(static_cast<uint64_t>(kint64max));
}
}
const uint128 remainder128 = a - quotient128 * b;
*rem = MakeDurationFromU128(remainder128, num_neg);
if (!quotient_neg || quotient128 == 0) {
return Uint128Low64(quotient128) & kint64max;
}
// The quotient needs to be negated, but we need to carefully handle
// quotient128s with the top bit on.
return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1;
}
} // namespace time_internal
//
// Additive operators.
//
Duration& Duration::operator+=(Duration rhs) {
if (time_internal::IsInfiniteDuration(*this)) return *this;
if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs;
const int64_t orig_rep_hi = rep_hi_;
rep_hi_ =
DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_));
if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) {
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1);
rep_lo_ -= kTicksPerSecond;
}
rep_lo_ += rhs.rep_lo_;
if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) {
return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration();
}
return *this;
}
Duration& Duration::operator-=(Duration rhs) {
if (time_internal::IsInfiniteDuration(*this)) return *this;
if (time_internal::IsInfiniteDuration(rhs)) {
return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
}
const int64_t orig_rep_hi = rep_hi_;
rep_hi_ =
DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_));
if (rep_lo_ < rhs.rep_lo_) {
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1);
rep_lo_ += kTicksPerSecond;
}
rep_lo_ -= rhs.rep_lo_;
if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) {
return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration();
}
return *this;
}
//
// Multiplicative operators.
//
Duration& Duration::operator*=(int64_t r) {
if (time_internal::IsInfiniteDuration(*this)) {
const bool is_neg = (r < 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
return *this = ScaleFixed<SafeMultiply>(*this, r);
}
Duration& Duration::operator*=(double r) {
if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
return *this = ScaleDouble<std::multiplies>(*this, r);
}
Duration& Duration::operator/=(int64_t r) {
if (time_internal::IsInfiniteDuration(*this) || r == 0) {
const bool is_neg = (r < 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
return *this = ScaleFixed<std::divides>(*this, r);
}
Duration& Duration::operator/=(double r) {
Export of internal Abseil changes. -- cd076f55c1fa600131f6dda392533dfe61679fc0 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 224008762 -- e05f62b01286d51044ff86ec6ef565749b9faf82 by Abseil Team <absl-team@google.com>: Create a pow10() test helper function to compute guaranteed-precise double values of 10^x. Not all standard libraries ship bit-accurate pow() functions, causing tests to fail that rely on expected values generated by it. PiperOrigin-RevId: 223883762 -- fd88e5e3f7ab80f7f5df9fd1488cd58b4573be69 by Abseil Team <absl-team@google.com>: Remove some absl:: qualifications to work around inline namespace bugs on MSVC 2015. PiperOrigin-RevId: 223869642 -- 6276cfff969d596edd36a2bbaba65ee045808903 by Abseil Team <absl-team@google.com>: Update absl/memory/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223854224 -- 359de9afc7a34c975fd3e0cbc52afd96637d97bd by Chris Kennelly <ckennelly@google.com>: Mark spinlock_benchmark_common as alwayslink = 1. PiperOrigin-RevId: 223844536 -- 450cd8cbe2789a6d54ed1eb87170259bb334f8b9 by Abseil Team <absl-team@google.com>: Support .* (pointer-to-member dereference) expressions in demangle.cc. PiperOrigin-RevId: 223826797 -- 772ca92179c3634f3e31a80bbc272ed8022e3572 by Abseil Team <absl-team@google.com>: Fix misspellings in absl::variant comments and replace a ' with a `. PiperOrigin-RevId: 223807911 -- 35dcdc2fbf299d195658aac101887f6dcad1de2f by Abseil Team <absl-team@google.com>: Bug fix in CMakeLists.txt file (SRCS --> HDRS). The compressed_tuple header-only library is being defined with the SRCS parameter instead of the HDRS parameter and this has been observed to cause some builds on some platforms to attempt to create a static library from it which fails since there are no .cc sources. PiperOrigin-RevId: 223805367 -- 4a57a3d2045bb137c0c97958e45ce425190b8d3e by Chris Kennelly <ckennelly@google.com>: Add test that absl::make_unique value initializes memory. PiperOrigin-RevId: 223801819 -- dfe8289d7f4dcc6bb568a26aaf192a89e896bdfd by Chris Kennelly <ckennelly@google.com>: SpinLock: Use exchange to avoid missing wakeups. The default fast path for SpinLock::Unlock does not use an atomic. If the SpinLock becomes contended while we are unlocking between lockword_.load and lockword_.store, we will fail to wake up the new waiter. This can cause unexpected latency spikes. PiperOrigin-RevId: 223800369 -- 9b9d35df786482f0016f77dd31691eff81503d23 by Abseil Team <absl-team@google.com>: Update absl/hash/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223755819 -- c2014e2704b87e7cdce2d2a0287c7e2397752296 by Abseil Team <absl-team@google.com>: Update absl/debugging/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 223751986 -- d83a4e09126400e3fd80645cb03ee558f532271e by Derek Mauro <dmauro@google.com>: Cleanup synchronization benchmarks. PiperOrigin-RevId: 223589416 -- fad140b473586531b5b12843f942ec27dfcf5e93 by CJ Johnson <johnsoncj@google.com>: Makes unifies the order of forward_iterator and input_iterator overloads PiperOrigin-RevId: 223580660 -- 6cd7c96faa7cc5f79f574e35a1b13837ef187d05 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223561629 -- bd2e545356b0f548af0e3c14bb2f7f0e712e49d0 by Shaindel Schwartz <shaindel@google.com>: Remove misleading comments. try_emplace() does not exist for the hash_set containers. PiperOrigin-RevId: 223543089 -- 0cd380a53b587eb7aacc4003a4a3bbb6c78d7c10 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 223512551 -- 7156dfee599cb72e9adddfe0e6ae07a95ddf10bb by Greg Miller <jgm@google.com>: Fixes UB that would result from constructing, multiplying, or dividing a Duration with a double "NaN" value. This CL changes the absl::Duration *implementation* to return an InfiniteDuration value that has the same sign as the given NaN. PiperOrigin-RevId: 223407499 -- 196b7d18609958267951882baf7f9429e49bcafa by CJ Johnson <johnsoncj@google.com>: Addresses NVCC+MSVC compilation bug where `inlined_capacity()` was not considered valid in constexpr PiperOrigin-RevId: 223397718 GitOrigin-RevId: cd076f55c1fa600131f6dda392533dfe61679fc0 Change-Id: I5423ca6470f661a7c6f73aa8fee49990446f157f
2018-12-04 20:01:12 +01:00
if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
2017-09-19 22:54:40 +02:00
const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0);
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
}
return *this = ScaleDouble<std::divides>(*this, r);
}
Duration& Duration::operator%=(Duration rhs) {
time_internal::IDivDuration(false, *this, rhs, this);
return *this;
}
double FDivDuration(Duration num, Duration den) {
// Arithmetic with infinity is sticky.
if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
return (num < ZeroDuration()) == (den < ZeroDuration())
? std::numeric_limits<double>::infinity()
: -std::numeric_limits<double>::infinity();
}
if (time_internal::IsInfiniteDuration(den)) return 0.0;
double a =
static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond +
time_internal::GetRepLo(num);
double b =
static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond +
time_internal::GetRepLo(den);
return a / b;
}
//
// Trunc/Floor/Ceil.
//
Duration Trunc(Duration d, Duration unit) {
return d - (d % unit);
}
Duration Floor(const Duration d, const Duration unit) {
const absl::Duration td = Trunc(d, unit);
return td <= d ? td : td - AbsDuration(unit);
}
Duration Ceil(const Duration d, const Duration unit) {
const absl::Duration td = Trunc(d, unit);
return td >= d ? td : td + AbsDuration(unit);
}
//
// Factory functions.
//
Duration DurationFromTimespec(timespec ts) {
if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
int64_t ticks = ts.tv_nsec * kTicksPerNanosecond;
return time_internal::MakeDuration(ts.tv_sec, ticks);
}
return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec);
}
Duration DurationFromTimeval(timeval tv) {
if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond;
return time_internal::MakeDuration(tv.tv_sec, ticks);
}
return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec);
}
//
// Conversion to other duration types.
//
int64_t ToInt64Nanoseconds(Duration d) {
if (time_internal::GetRepHi(d) >= 0 &&
time_internal::GetRepHi(d) >> 33 == 0) {
return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
(time_internal::GetRepLo(d) / kTicksPerNanosecond);
}
return d / Nanoseconds(1);
}
int64_t ToInt64Microseconds(Duration d) {
if (time_internal::GetRepHi(d) >= 0 &&
time_internal::GetRepHi(d) >> 43 == 0) {
return (time_internal::GetRepHi(d) * 1000 * 1000) +
(time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
}
return d / Microseconds(1);
}
int64_t ToInt64Milliseconds(Duration d) {
if (time_internal::GetRepHi(d) >= 0 &&
time_internal::GetRepHi(d) >> 53 == 0) {
return (time_internal::GetRepHi(d) * 1000) +
(time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
}
return d / Milliseconds(1);
}
int64_t ToInt64Seconds(Duration d) {
int64_t hi = time_internal::GetRepHi(d);
if (time_internal::IsInfiniteDuration(d)) return hi;
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
return hi;
}
int64_t ToInt64Minutes(Duration d) {
int64_t hi = time_internal::GetRepHi(d);
if (time_internal::IsInfiniteDuration(d)) return hi;
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
return hi / 60;
}
int64_t ToInt64Hours(Duration d) {
int64_t hi = time_internal::GetRepHi(d);
if (time_internal::IsInfiniteDuration(d)) return hi;
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
return hi / (60 * 60);
}
double ToDoubleNanoseconds(Duration d) {
return FDivDuration(d, Nanoseconds(1));
}
double ToDoubleMicroseconds(Duration d) {
return FDivDuration(d, Microseconds(1));
}
double ToDoubleMilliseconds(Duration d) {
return FDivDuration(d, Milliseconds(1));
}
double ToDoubleSeconds(Duration d) {
return FDivDuration(d, Seconds(1));
}
double ToDoubleMinutes(Duration d) {
return FDivDuration(d, Minutes(1));
}
double ToDoubleHours(Duration d) {
return FDivDuration(d, Hours(1));
}
timespec ToTimespec(Duration d) {
timespec ts;
if (!time_internal::IsInfiniteDuration(d)) {
int64_t rep_hi = time_internal::GetRepHi(d);
uint32_t rep_lo = time_internal::GetRepLo(d);
if (rep_hi < 0) {
// Tweak the fields so that unsigned division of rep_lo
// maps to truncation (towards zero) for the timespec.
rep_lo += kTicksPerNanosecond - 1;
if (rep_lo >= kTicksPerSecond) {
rep_hi += 1;
rep_lo -= kTicksPerSecond;
}
}
ts.tv_sec = rep_hi;
if (ts.tv_sec == rep_hi) { // no time_t narrowing
ts.tv_nsec = rep_lo / kTicksPerNanosecond;
return ts;
}
}
if (d >= ZeroDuration()) {
ts.tv_sec = std::numeric_limits<time_t>::max();
ts.tv_nsec = 1000 * 1000 * 1000 - 1;
} else {
ts.tv_sec = std::numeric_limits<time_t>::min();
ts.tv_nsec = 0;
}
return ts;
}
timeval ToTimeval(Duration d) {
timeval tv;
timespec ts = ToTimespec(d);
if (ts.tv_sec < 0) {
// Tweak the fields so that positive division of tv_nsec
// maps to truncation (towards zero) for the timeval.
ts.tv_nsec += 1000 - 1;
if (ts.tv_nsec >= 1000 * 1000 * 1000) {
ts.tv_sec += 1;
ts.tv_nsec -= 1000 * 1000 * 1000;
}
}
tv.tv_sec = ts.tv_sec;
if (tv.tv_sec != ts.tv_sec) { // narrowing
if (ts.tv_sec < 0) {
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
tv.tv_usec = 0;
} else {
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
tv.tv_usec = 1000 * 1000 - 1;
}
return tv;
}
tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
return tv;
}
Changes imported from Abseil "staging" branch: - b527a3e4b36b644ac424e3c525b1cd393f6f6c40 Fix some typos in the usage examples by Jorg Brown <jorg@google.com> - 82be4a9adf3bb0ddafc0d46274969c99afffe870 Fix typo in optional.h comment. by Abseil Team <absl-team@google.com> - d6ee63bf8fc51fba074c23b33cebc28c808d7f07 Remove internal-only identifiers from code. by Daniel Katz <katzdm@google.com> - f9c3ad2f0d73f53b21603638af8b4bed636e79f4 Use easier understandable names for absl::StartsWith and ... by Abseil Team <absl-team@google.com> - 7c16c14fefee89c927b8789d6043c4691bcffc9b Add -Wno-missing-prototypes back to the LLVM copts. by Derek Mauro <dmauro@google.com> - 2f4b7d2e50c7023240242f1e15db60ccd7e8768d IWYU | absl/strings by Juemin Yang <jueminyang@google.com> - a99cbcc1daa34a2d6a2bb26de275e05173cc77e9 IWYU | absl/type by Juemin Yang <jueminyang@google.com> - 12e1146d0fc76c071d7e0ebaabb62f0a984fae66 Use LLVM_FLAGS and LLVM_TEST_FLAGS when --compiler=llvm. by Derek Mauro <dmauro@google.com> - cd6bea616abda558d0bace5bd77455662a233688 IWYU | absl/debugging by Juemin Yang <jueminyang@google.com> - d9a7382e59d46a8581b6b7a31cd5a48bb89326e9 IWYU | absl/synchronization by Juemin Yang <jueminyang@google.com> - 07ec7d6d5a4a666f4183c5d0ed9c342baa7b24bc IWYU | absl/numeric by Juemin Yang <jueminyang@google.com> - 12bfe40051f4270f8707e191af5652f83f2f750c Remove the RoundTrip{Float,Double}ToBuffer routines from ... by Jorg Brown <jorg@google.com> - eeb4fd67c9d97f66cb9475c3c5e51ab132f1c810 Adds conversion functions for converting between absl/tim... by Greg Miller <jgm@google.com> - 59a2108d05d4ea85dc5cc11e49b2cd2335d4295a Change Substitute to use %.6g formatting rather than 15/1... by Jorg Brown <jorg@google.com> - 394becb48e0fcd161642cdaac5120d32567e0ef8 IWYU | absl/meta by Juemin Yang <jueminyang@google.com> - 1e5da6e8da336699b2469dcf6dda025b9b0ec4c9 Rewrite atomic_hook.h to not use std::atomic<T*> under Wi... by Greg Falcon <gfalcon@google.com> GitOrigin-RevId: b527a3e4b36b644ac424e3c525b1cd393f6f6c40 Change-Id: I14e331d91c956ef045ac7927091a9f179716de0c
2017-09-24 17:20:48 +02:00
std::chrono::nanoseconds ToChronoNanoseconds(Duration d) {
return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
}
std::chrono::microseconds ToChronoMicroseconds(Duration d) {
return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
}
std::chrono::milliseconds ToChronoMilliseconds(Duration d) {
return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
}
std::chrono::seconds ToChronoSeconds(Duration d) {
return time_internal::ToChronoDuration<std::chrono::seconds>(d);
}
std::chrono::minutes ToChronoMinutes(Duration d) {
return time_internal::ToChronoDuration<std::chrono::minutes>(d);
}
std::chrono::hours ToChronoHours(Duration d) {
return time_internal::ToChronoDuration<std::chrono::hours>(d);
}
2017-09-19 22:54:40 +02:00
//
// To/From string formatting.
2017-09-19 22:54:40 +02:00
//
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) {
do {
--width;
*--ep = '0' + (v % 10); // contiguous digits
2017-09-19 22:54:40 +02:00
} while (v /= 10);
while (--width >= 0) *--ep = '0'; // zero pad
return ep;
}
// 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 {
const char* abbr;
int prec;
double pow10;
};
const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
const DisplayUnit kDisplaySec = {"s", 11, 1e11};
const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
const DisplayUnit kDisplayHour = {"h", -1, 0.0}; // prec ignored
void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
char buf[sizeof("2562047788015216")]; // hours in max duration
char* const ep = buf + sizeof(buf);
char* bp = Format64(ep, 0, n);
if (*bp != '0' || bp + 1 != ep) {
out->append(bp, ep - bp);
out->append(unit.abbr);
}
}
// 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) {
const int buf_size = std::numeric_limits<double>::digits10;
const int prec = std::min(buf_size, unit.prec);
char buf[buf_size]; // also large enough to hold integer part
char* ep = buf + sizeof(buf);
double d = 0;
int64_t frac_part = Round(std::modf(n, &d) * unit.pow10);
int64_t int_part = d;
if (int_part != 0 || frac_part != 0) {
char* bp = Format64(ep, 0, int_part); // always < 1000
out->append(bp, ep - bp);
if (frac_part != 0) {
out->push_back('.');
bp = Format64(ep, prec, frac_part);
while (ep[-1] == '0') --ep;
out->append(bp, ep - bp);
}
out->append(unit.abbr);
}
}
} // 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
2017-09-19 22:54:40 +02:00
// case, durations less than one second format use a smaller unit
// (milli-, micro-, or nanoseconds) to ensure that the leading digit
// is non-zero. The zero duration formats as 0, with no unit.
std::string FormatDuration(Duration d) {
const Duration min_duration = Seconds(kint64min);
if (d == min_duration) {
// Avoid needing to negate kint64min by directly returning what the
// following code should produce in that case.
return "-2562047788015215h30m8s";
}
std::string s;
if (d < ZeroDuration()) {
s.append("-");
d = -d;
}
if (d == InfiniteDuration()) {
s.append("inf");
} else if (d < Seconds(1)) {
// Special case for durations with a magnitude < 1 second. The duration
// is printed as a fraction of a single unit, e.g., "1.2ms".
if (d < Microseconds(1)) {
AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano);
} else if (d < Milliseconds(1)) {
AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro);
} else {
AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli);
}
} else {
AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour);
AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin);
AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec);
}
if (s.empty() || s == "-") {
s = "0";
}
return s;
}
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, int64_t* int_part,
int64_t* frac_part, int64_t* frac_scale) {
*int_part = 0;
*frac_part = 0;
*frac_scale = 1; // invariant: *frac_part < *frac_scale
const char* start = *dpp;
for (; std::isdigit(**dpp); *dpp += 1) {
const int d = **dpp - '0'; // contiguous digits
if (*int_part > kint64max / 10) return false;
*int_part *= 10;
if (*int_part > kint64max - d) return false;
*int_part += d;
}
const bool int_part_empty = (*dpp == start);
if (**dpp != '.') return !int_part_empty;
for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) {
const int d = **dpp - '0'; // contiguous digits
if (*frac_scale <= kint64max / 10) {
*frac_part *= 10;
*frac_part += d;
*frac_scale *= 10;
}
}
return !int_part_empty || *frac_scale != 1;
2017-09-19 22:54:40 +02:00
}
// 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
2017-09-19 22:54:40 +02:00
// unconsumed char.
bool ConsumeDurationUnit(const char** start, Duration* unit) {
const char *s = *start;
bool ok = true;
if (strncmp(s, "ns", 2) == 0) {
s += 2;
*unit = Nanoseconds(1);
} else if (strncmp(s, "us", 2) == 0) {
s += 2;
*unit = Microseconds(1);
} else if (strncmp(s, "ms", 2) == 0) {
s += 2;
*unit = Milliseconds(1);
} else if (strncmp(s, "s", 1) == 0) {
s += 1;
*unit = Seconds(1);
} else if (strncmp(s, "m", 1) == 0) {
s += 1;
*unit = Minutes(1);
} else if (strncmp(s, "h", 1) == 0) {
s += 1;
*unit = Hours(1);
} else {
ok = false;
}
*start = s;
return ok;
}
} // namespace
// From Go's doc at https://golang.org/pkg/time/#ParseDuration
Export of internal Abseil changes. -- 5dc8d7504b7c11710b19365a6582c288c8992366 by Derek Mauro <dmauro@google.com>: Fix constexpr Span::last under MSVC and add Span constexpr tests. PiperOrigin-RevId: 237515952 -- 5ea8c146e653bbc49ff7e698699478242df7de35 by Derek Mauro <dmauro@google.com>: Implement Span::first and Span::last from C++20. https://github.com/abseil/abseil-cpp/pull/274 PiperOrigin-RevId: 237494399 -- 08db3417f1d8fe4556255d57a2f0df51b09bdd9a by Derek Mauro <dmauro@google.com>: HTTPS in more URLs. PiperOrigin-RevId: 237486823 -- 83ec63a7f8e47b62af619546f9f7b3bf72e74e86 by Derek Mauro <dmauro@google.com>: Changed HTTP URLs to HTTPS where possible. https://github.com/abseil/abseil-cpp/pull/270 PiperOrigin-RevId: 237445310 -- 220bf279c14cb31efa239500d1a70e0ac0c32e3c by Abseil Team <absl-team@google.com>: Support parsing decltype(nullptr) as a type. PiperOrigin-RevId: 237336739 -- ced234bbe78f5d495c3f6f6a9c2e0a95f7c080a5 by Gennadiy Rozental <rogeeff@google.com>: Introduce internal interface for setting environment variable value in scope PiperOrigin-RevId: 237275806 -- 1f1acb4e294af24d9f7598e85163d5e1d9958ae9 by Samuel Benzaquen <sbenza@google.com>: Avoid using aliases in the SFINAE expressions to make it more compatible with MSVC. Turn on the tests in MSVC. PiperOrigin-RevId: 237261456 -- 06cf7de6250a0572ef90fa1176f742ca0451ce71 by Derek Mauro <dmauro@google.com>: Fix unused variable warning. PiperOrigin-RevId: 237108006 GitOrigin-RevId: 5dc8d7504b7c11710b19365a6582c288c8992366 Change-Id: Ife5182c80942945c4e8700844c8febb482d6ad82
2019-03-08 23:06:50 +01:00
// [ParseDuration] parses a duration string. A duration string is
2017-09-19 22:54:40 +02:00
// 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(const std::string& dur_string, Duration* d) {
const char* start = dur_string.c_str();
int sign = 1;
if (*start == '-' || *start == '+') {
sign = *start == '-' ? -1 : 1;
++start;
}
// Can't parse a duration from an empty std::string.
if (*start == '\0') {
return false;
}
// Special case for a std::string of "0".
if (*start == '0' && *(start + 1) == '\0') {
*d = ZeroDuration();
return true;
}
if (strcmp(start, "inf") == 0) {
*d = sign * InfiniteDuration();
return true;
}
Duration dur;
while (*start != '\0') {
int64_t int_part;
int64_t frac_part;
int64_t frac_scale;
2017-09-19 22:54:40 +02:00
Duration unit;
if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) ||
2017-09-19 22:54:40 +02:00
!ConsumeDurationUnit(&start, &unit)) {
return false;
}
if (int_part != 0) dur += sign * int_part * unit;
if (frac_part != 0) dur += sign * frac_part * unit / frac_scale;
2017-09-19 22:54:40 +02:00
}
*d = dur;
return true;
}
Export of internal Abseil changes. -- bdce7e57e9e886eff1114d0266781b443f7ec639 by Derek Mauro <dmauro@google.com>: Change {Get|Set}EnvironmentVariable to {Get|Set}EnvironmentVariableA for compatibility with /DUNICODE. PiperOrigin-RevId: 239229514 -- 2276ed502326a044a84060d34eb19d499e3a3be2 by Derek Mauro <dmauro@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 239228622 -- a462efb970ff43b08a362ef2343fb75ac1295a50 by Derek Mauro <dmauro@google.com>: Adding linking of CoreFoundation to CMakeLists in absl/time. Import https://github.com/abseil/abseil-cpp/pull/280. Fix #283 PiperOrigin-RevId: 239220785 -- fc23327b97f940c682aae1956cf7a1bf87f88c06 by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of gcc (8.3.0 today) with libstdc++ and bazel. PiperOrigin-RevId: 239220448 -- 418c08a8f6a53e63b84e39473035774417ca3aa7 by Derek Mauro <dmauro@google.com>: Disable part of the variant exeception safety test on move assignment when using versions of libstd++ that contain a bug. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7 PiperOrigin-RevId: 239062455 -- 799722217aeda79679577843c91d5be62cbcbb42 by Matt Calabrese <calabrese@google.com>: Add internal-only IsSwappable traits corresponding to std::is_swappable and std::is_nothrow_swappable, which are used with the swap implementations of optional and variant. PiperOrigin-RevId: 239049448 -- aa46a036038a3de5c68ac5e5d3b4bf76f818d2ea by CJ Johnson <johnsoncj@google.com>: Make InlinedVectorStorage constructor explicit PiperOrigin-RevId: 239044361 -- 17949715b3aa21c794701f69f2154e91b6acabc3 by CJ Johnson <johnsoncj@google.com>: Add absl namesapce to internal/inlined_vector.h PiperOrigin-RevId: 239030789 -- 834628325953078cc08ed10d23bb8890e5bec897 by Derek Mauro <dmauro@google.com>: Add test script that uses Docker to build Abseil with gcc-4.8, libstdc++, and cmake. PiperOrigin-RevId: 239028433 -- 80fe24149ed73ed2ced995ad1e372fb060c60427 by CJ Johnson <johnsoncj@google.com>: Factors data members of InlinedVector into an impl type called InlinedVectorStorage so that (in future changes) the contents of a vector can be grouped together with a single pointer. PiperOrigin-RevId: 239021086 -- 585331436d5d4d79f845e45dcf79d918a0dc6169 by Derek Mauro <dmauro@google.com>: Add -Wno-missing-field-initializers to gcc compiler flags. gcc-4.x has spurious missing field initializer warnings. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750 PiperOrigin-RevId: 239017217 -- 94602fe4e33ee3a552a7f2939c0f57a992f55075 by Abseil Team <absl-team@google.com>: Formatting fixes. PiperOrigin-RevId: 238983038 -- a1c1b63c08505574e0a8c491561840cecb2bb93e by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libc++ and bazel. PiperOrigin-RevId: 238669118 -- e525f8d20bc2f79a0d69336b902f63858f3bff9d by Derek Mauro <dmauro@google.com>: Disable the test optionalTest.InPlaceTSFINAEBug until libc++ is updated. PiperOrigin-RevId: 238661703 -- f99a2a0b5ec424a059678f7f226600f137b4c74e by Derek Mauro <dmauro@google.com>: Correct the check for the FlatHashMap-Any test bug (list conditions instead of platforms when possible) PiperOrigin-RevId: 238653344 -- 777928035dbcbf39f361eb7d10dc3696822f692f by Jon Cohen <cohenjon@google.com>: Add install rules for Abseil CMake. These are attempted to be limited to in-project installation. This serves two purposes -- first it's morally the same as using Abseil in-source, except you don't have to rebuild us every time. Second, the presence of an install rule makes life massively simpler for package manager maintainers. Currently this doesn't install absl tests or testonly libraries. This can be added in a follow-up patch. Fixes #38, Fixes #80, Closes #182 PiperOrigin-RevId: 238645836 -- ded1c6ce697c191b7a6ff14572b3e6d183117b2c by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libstdc++ and bazel. PiperOrigin-RevId: 238517815 GitOrigin-RevId: bdce7e57e9e886eff1114d0266781b443f7ec639 Change-Id: I6f745869cb8ef63851891ccac05ae9a7dd241c4f
2019-03-19 19:14:01 +01:00
-- f28d30df5769bb832dec3ff36d2fcd2bcdf494a3 by Shaindel Schwartz <shaindel@google.com>: Internal change PiperOrigin-RevId: 201046831 -- 711715a78b7e53dfaafd4d7f08a74e76db22af88 by Mark Barolak <mbar@google.com>: Internal fix PiperOrigin-RevId: 201043684 -- 64b53edd6bf1fa48f74e7f5d33f00f80d5089147 by Shaindel Schwartz <shaindel@google.com>: Remove extra whitespace PiperOrigin-RevId: 201041989 -- 0bdd2a0b33657b688e4a04aeba9ebba47e4dc6ca by Shaindel Schwartz <shaindel@google.com>: Whitespace fix. PiperOrigin-RevId: 201034413 -- 3deb0ac296ef1b74c4789e114a8a8bf53253f26b by Shaindel Schwartz <shaindel@google.com>: Scrub build tags. No functional changes. PiperOrigin-RevId: 201032927 -- da75d0f8b73baa7e8f4e9a092bba546012ed3b71 by Alex Strelnikov <strel@google.com>: Internal change. PiperOrigin-RevId: 201026131 -- 6815d80caa19870d0c441b6b9816c68db41393a5 by Tom Manshreck <shreck@google.com>: Add documentation for our LTS snapshot branches PiperOrigin-RevId: 201025191 -- 64c3b02006f39e6a8127bbabf9ec947fb45b6504 by Greg Falcon <gfalcon@google.com>: Provide absl::from_chars for double and float types. This is a forward-compatible implementation of std::from_chars from C++17. This provides exact "round_to_nearest" conversions, and has some nice properties: * Works with string_view (it can convert numbers from non-NUL-terminated buffers) * Never allocates memory * Faster than the standard library strtod() in our toolchain * Uses integer math in its calculations, so is unaffected by floating point environment * Unaffected by C locale Also change SimpleAtod/SimpleAtoi to use this new API under the hood. PiperOrigin-RevId: 201003324 -- 542869258eb100779497c899103dc96aced52749 by Greg Falcon <gfalcon@google.com>: Internal change PiperOrigin-RevId: 200999200 -- 3aba192775c7f80e2cd7f221b0a73537823c54ea by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 200947470 -- daf9b9feedd748d5364a4c06165b7cb7604d3e1e by Mark Barolak <mbar@google.com>: Add an absl:: qualification to a usage of base_internal::SchedulingMode outside of an absl:: namespace. PiperOrigin-RevId: 200748234 -- a8d265290a22d629f3d9bf9f872c204200bfe8c8 by Mark Barolak <mbar@google.com>: Add a missing namespace closing comment to optional.h. PiperOrigin-RevId: 200739934 -- f05af8ee1c6b864dad2df7c907d424209a3e3202 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 200719115 GitOrigin-RevId: f28d30df5769bb832dec3ff36d2fcd2bcdf494a3 Change-Id: Ie4fa601078fd4aa57286372611f1d114fdec82c0
2018-06-18 22:18:53 +02:00
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
2017-09-19 22:54:40 +02:00
return ParseDuration(text, dst);
}
Export of internal Abseil changes. -- ac7508120c60dfe689c40929e416b6a486f83ee3 by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 206912089 -- bd709faba88565367b6d337466e6456481b5f3e8 by Matt Calabrese <calabrese@google.com>: Implement `std::experimental::is_detected` in type_traits internals and move `is_detected_convertible` from variant's internals to type_traits internals. This is in preparation of creating workarounds for broken standard traits. PiperOrigin-RevId: 206825598 -- 0dbddea569370eb9b6348cee172d1874f9046eb4 by Jorg Brown <jorg@google.com>: Support users who turn on floating-point conversion warnings PiperOrigin-RevId: 206813209 -- 30991f757c8f0100584619d8a9c41897d029f112 by Jorg Brown <jorg@google.com>: Speed up the absl::Seconds() function for floating-point values, roughly by 4.5x, since we can take advantage of the fact that we're just taking a floating-point number and splitting it into its integral and fractional parts. PiperOrigin-RevId: 206806270 -- 6883837176838aa5a517e7a8cb4c99afd24c0d12 by Jon Cohen <cohenjon@google.com>: Remove the DISABLE_INSTALL from absl_container. It doesn't do anything. PiperOrigin-RevId: 206802544 -- 92ab14fed06e6dd1f01a0284bd7f95d3e2c0c3d8 by Jon Cohen <cohenjon@google.com>: Internal change PiperOrigin-RevId: 206776244 -- 17b76c7f364ac562d9e0faeca0320f63aa3fdb85 by Jorg Brown <jorg@google.com>: Fix absl/strings:numbers_test flakiness due to exceeding the 1-minute timeout PiperOrigin-RevId: 206763175 -- 6637843f2e198b8efd90e5577fbc86bdea43b2cc by Abseil Team <absl-team@google.com>: Adds templated allocator to absl::FixedArray with corresponding tests PiperOrigin-RevId: 206354178 -- bced22f81add828c9b4c60eb45554d36c22e2f96 by Abseil Team <absl-team@google.com>: Adds templated allocator to absl::FixedArray with corresponding tests PiperOrigin-RevId: 206347377 -- 75be14a71d2d5e335812d5b7670120271fb5bd79 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 206326935 -- 6929e43f4c7898b1f51e441911a19092a06fbf97 by Abseil Team <absl-team@google.com>: Adds templated allocator to absl::FixedArray with corresponding tests PiperOrigin-RevId: 206326368 -- 55ae34b75ff029eb267f9519e577bab8a575b487 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 206233448 -- 6950a8ccddf35d451eec2d02cd28a797c8b7cf6a by Matt Kulukundis <kfm@google.com>: Internal change PiperOrigin-RevId: 206035613 GitOrigin-RevId: ac7508120c60dfe689c40929e416b6a486f83ee3 Change-Id: I675605abbedab6b3ac9aa82195cbd059ff7c82b1
2018-08-01 13:34:12 +02:00
std::string UnparseFlag(Duration d) { return FormatDuration(d); }
2017-09-19 22:54:40 +02:00
} // namespace absl