diff options
Diffstat (limited to 'absl/time')
-rw-r--r-- | absl/time/duration.cc | 8 | ||||
-rw-r--r-- | absl/time/duration_test.cc | 34 | ||||
-rw-r--r-- | absl/time/time.h | 5 |
3 files changed, 45 insertions, 2 deletions
diff --git a/absl/time/duration.cc b/absl/time/duration.cc index 2950c7cdc632..b77d5ec9006d 100644 --- a/absl/time/duration.cc +++ b/absl/time/duration.cc @@ -78,10 +78,16 @@ 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) { + if (std::isnan(d)) return false; return d != std::numeric_limits<double>::infinity() && d != -std::numeric_limits<double>::infinity(); } +inline bool IsValidDivisor(double d) { + if (std::isnan(d)) return false; + return d != 0.0; +} + // 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> @@ -455,7 +461,7 @@ Duration& Duration::operator/=(int64_t r) { } Duration& Duration::operator/=(double r) { - if (time_internal::IsInfiniteDuration(*this) || r == 0.0) { + if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) { const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); } diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc index 775da91e6929..61f3c5c07fa1 100644 --- a/absl/time/duration_test.cc +++ b/absl/time/duration_test.cc @@ -803,6 +803,40 @@ TEST(Duration, DivisionByZero) { EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero)); } +TEST(Duration, NaN) { + // Note that IEEE 754 does not define the behavior of a nan's sign when it is + // copied, so the code below allows for either + or - InfiniteDuration. +#define TEST_NAN_HANDLING(NAME, NAN) \ + do { \ + const auto inf = absl::InfiniteDuration(); \ + auto x = NAME(NAN); \ + EXPECT_TRUE(x == inf || x == -inf); \ + auto y = NAME(42); \ + y *= NAN; \ + EXPECT_TRUE(y == inf || y == -inf); \ + auto z = NAME(42); \ + z /= NAN; \ + EXPECT_TRUE(z == inf || z == -inf); \ + } while (0) + + const double nan = std::numeric_limits<double>::quiet_NaN(); + TEST_NAN_HANDLING(absl::Nanoseconds, nan); + TEST_NAN_HANDLING(absl::Microseconds, nan); + TEST_NAN_HANDLING(absl::Milliseconds, nan); + TEST_NAN_HANDLING(absl::Seconds, nan); + TEST_NAN_HANDLING(absl::Minutes, nan); + TEST_NAN_HANDLING(absl::Hours, nan); + + TEST_NAN_HANDLING(absl::Nanoseconds, -nan); + TEST_NAN_HANDLING(absl::Microseconds, -nan); + TEST_NAN_HANDLING(absl::Milliseconds, -nan); + TEST_NAN_HANDLING(absl::Seconds, -nan); + TEST_NAN_HANDLING(absl::Minutes, -nan); + TEST_NAN_HANDLING(absl::Hours, -nan); + +#undef TEST_NAN_HANDLING +} + TEST(Duration, Range) { const absl::Duration range = ApproxYears(100 * 1e9); const absl::Duration range_future = range; diff --git a/absl/time/time.h b/absl/time/time.h index 3fa9378fc849..b86abf27b045 100644 --- a/absl/time/time.h +++ b/absl/time/time.h @@ -69,6 +69,7 @@ #include <winsock2.h> #endif #include <chrono> // NOLINT(build/c++11) +#include <cmath> #include <cstdint> #include <ctime> #include <ostream> @@ -411,10 +412,12 @@ Duration Milliseconds(T n) { } template <typename T, time_internal::EnableIfFloat<T> = 0> Duration Seconds(T n) { - if (n >= 0) { + if (n >= 0) { // Note: `NaN >= 0` is false. if (n >= (std::numeric_limits<int64_t>::max)()) return InfiniteDuration(); return time_internal::MakePosDoubleDuration(n); } else { + if (std::isnan(n)) + return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration(); if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration(); return -time_internal::MakePosDoubleDuration(-n); } |