Commit ae87b773 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

constexpr TimeDelta::operator/

The mul/div operators are tricky. operator/ works when |a| is small
enough (in absolute value) to deterministically not risk overflow.

operator*() on the other hand doesn't because of a limitation in
__builtin_mul_overflow. We could do some template hacking to make
operator*(a) == operator/(1.0/a) when |a| is a constant expression.

Bug: 761570
Change-Id: I9906edfc049017ad19872e4a586b2ec675404850
Reviewed-on: https://chromium-review.googlesource.com/886344Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarYuri Wiitala <miu@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532947}
parent fb27199b
...@@ -218,7 +218,9 @@ class BASE_EXPORT TimeDelta { ...@@ -218,7 +218,9 @@ class BASE_EXPORT TimeDelta {
} }
constexpr TimeDelta operator-() const { return TimeDelta(-delta_); } constexpr TimeDelta operator-() const { return TimeDelta(-delta_); }
// Computations with numeric types. // Computations with numeric types. operator*() isn't constexpr because of a
// limitation around __builtin_mul_overflow (but operator/(1.0/a) works for
// |a|'s of "reasonable" size -- i.e. that don't risk overflow).
template <typename T> template <typename T>
TimeDelta operator*(T a) const { TimeDelta operator*(T a) const {
CheckedNumeric<int64_t> rv(delta_); CheckedNumeric<int64_t> rv(delta_);
...@@ -231,7 +233,7 @@ class BASE_EXPORT TimeDelta { ...@@ -231,7 +233,7 @@ class BASE_EXPORT TimeDelta {
return TimeDelta(std::numeric_limits<int64_t>::max()); return TimeDelta(std::numeric_limits<int64_t>::max());
} }
template <typename T> template <typename T>
TimeDelta operator/(T a) const { constexpr TimeDelta operator/(T a) const {
CheckedNumeric<int64_t> rv(delta_); CheckedNumeric<int64_t> rv(delta_);
rv /= a; rv /= a;
if (rv.IsValid()) if (rv.IsValid())
...@@ -247,7 +249,7 @@ class BASE_EXPORT TimeDelta { ...@@ -247,7 +249,7 @@ class BASE_EXPORT TimeDelta {
return *this = (*this * a); return *this = (*this * a);
} }
template <typename T> template <typename T>
TimeDelta& operator/=(T a) { constexpr TimeDelta& operator/=(T a) {
return *this = (*this / a); return *this = (*this / a);
} }
......
...@@ -1322,70 +1322,82 @@ TEST(TimeDelta, NumericOperators) { ...@@ -1322,70 +1322,82 @@ TEST(TimeDelta, NumericOperators) {
constexpr double d = 0.5; constexpr double d = 0.5;
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) * d)); (TimeDelta::FromMilliseconds(1000) * d));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) / d)); (TimeDelta::FromMilliseconds(1000) / d),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) *= d)); (TimeDelta::FromMilliseconds(1000) *= d));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) /= d)); (TimeDelta::FromMilliseconds(1000) /= d),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(d * TimeDelta::FromMilliseconds(1000))); (d * TimeDelta::FromMilliseconds(1000)));
constexpr float f = 0.5; constexpr float f = 0.5;
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) * f)); (TimeDelta::FromMilliseconds(1000) * f));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) / f)); (TimeDelta::FromMilliseconds(1000) / f),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) *= f)); (TimeDelta::FromMilliseconds(1000) *= f));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) /= f)); (TimeDelta::FromMilliseconds(1000) /= f),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(f * TimeDelta::FromMilliseconds(1000))); (f * TimeDelta::FromMilliseconds(1000)));
constexpr int i = 2; constexpr int i = 2;
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) * i)); (TimeDelta::FromMilliseconds(1000) * i));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) / i)); (TimeDelta::FromMilliseconds(1000) / i),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) *= i)); (TimeDelta::FromMilliseconds(1000) *= i));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) /= i)); (TimeDelta::FromMilliseconds(1000) /= i),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(i * TimeDelta::FromMilliseconds(1000))); (i * TimeDelta::FromMilliseconds(1000)));
constexpr int64_t i64 = 2; constexpr int64_t i64 = 2;
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) * i64)); (TimeDelta::FromMilliseconds(1000) * i64));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) / i64)); (TimeDelta::FromMilliseconds(1000) / i64),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) *= i64)); (TimeDelta::FromMilliseconds(1000) *= i64));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) /= i64)); (TimeDelta::FromMilliseconds(1000) /= i64),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(i64 * TimeDelta::FromMilliseconds(1000))); (i64 * TimeDelta::FromMilliseconds(1000)));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) * 0.5)); (TimeDelta::FromMilliseconds(1000) * 0.5));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) / 0.5)); (TimeDelta::FromMilliseconds(1000) / 0.5),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(TimeDelta::FromMilliseconds(1000) *= 0.5)); (TimeDelta::FromMilliseconds(1000) *= 0.5));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), static_assert(TimeDelta::FromMilliseconds(2000) ==
(TimeDelta::FromMilliseconds(1000) /= 0.5)); (TimeDelta::FromMilliseconds(1000) /= 0.5),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(500), EXPECT_EQ(TimeDelta::FromMilliseconds(500),
(0.5 * TimeDelta::FromMilliseconds(1000))); (0.5 * TimeDelta::FromMilliseconds(1000)));
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) * 2)); (TimeDelta::FromMilliseconds(1000) * 2));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) / 2)); (TimeDelta::FromMilliseconds(1000) / 2),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(TimeDelta::FromMilliseconds(1000) *= 2)); (TimeDelta::FromMilliseconds(1000) *= 2));
EXPECT_EQ(TimeDelta::FromMilliseconds(500), static_assert(TimeDelta::FromMilliseconds(500) ==
(TimeDelta::FromMilliseconds(1000) /= 2)); (TimeDelta::FromMilliseconds(1000) /= 2),
"");
EXPECT_EQ(TimeDelta::FromMilliseconds(2000), EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
(2 * TimeDelta::FromMilliseconds(1000))); (2 * TimeDelta::FromMilliseconds(1000)));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment