Makes all units and operations constexpr

Since RTC_DCHECK was made constexpr compatible, we can now
make the unit classes fully constexpr.

Bug: webrtc:9883
Change-Id: I18973c2f318449869cf0bd45699c41be53fba806
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/167722
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Ali Tofigh <alito@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30403}
diff --git a/api/units/data_rate.h b/api/units/data_rate.h
index 0d3d653..78c2e0e 100644
--- a/api/units/data_rate.h
+++ b/api/units/data_rate.h
@@ -65,7 +65,7 @@
     return ToFraction<8, T>();
   }
   template <typename T = int64_t>
-  T kbps() const {
+  constexpr T kbps() const {
     return ToFraction<1000, T>();
   }
   constexpr int64_t bps_or(int64_t fallback_value) const {
@@ -84,7 +84,7 @@
 };
 
 namespace data_rate_impl {
-inline int64_t Microbits(const DataSize& size) {
+inline constexpr int64_t Microbits(const DataSize& size) {
   constexpr int64_t kMaxBeforeConversion =
       std::numeric_limits<int64_t>::max() / 8000000;
   RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion)
@@ -92,7 +92,7 @@
   return size.bytes() * 8000000;
 }
 
-inline int64_t MillibytePerSec(const DataRate& size) {
+inline constexpr int64_t MillibytePerSec(const DataRate& size) {
   constexpr int64_t kMaxBeforeConversion =
       std::numeric_limits<int64_t>::max() / (1000 / 8);
   RTC_DCHECK_LE(size.bps(), kMaxBeforeConversion)
@@ -101,31 +101,36 @@
 }
 }  // namespace data_rate_impl
 
-inline DataRate operator/(const DataSize size, const TimeDelta duration) {
+inline constexpr DataRate operator/(const DataSize size,
+                                    const TimeDelta duration) {
   return DataRate::bps(data_rate_impl::Microbits(size) / duration.us());
 }
-inline TimeDelta operator/(const DataSize size, const DataRate rate) {
+inline constexpr TimeDelta operator/(const DataSize size, const DataRate rate) {
   return TimeDelta::us(data_rate_impl::Microbits(size) / rate.bps());
 }
-inline DataSize operator*(const DataRate rate, const TimeDelta duration) {
+inline constexpr DataSize operator*(const DataRate rate,
+                                    const TimeDelta duration) {
   int64_t microbits = rate.bps() * duration.us();
   return DataSize::bytes((microbits + 4000000) / 8000000);
 }
-inline DataSize operator*(const TimeDelta duration, const DataRate rate) {
+inline constexpr DataSize operator*(const TimeDelta duration,
+                                    const DataRate rate) {
   return rate * duration;
 }
 
-inline DataSize operator/(const DataRate rate, const Frequency frequency) {
+inline constexpr DataSize operator/(const DataRate rate,
+                                    const Frequency frequency) {
   int64_t millihertz = frequency.millihertz<int64_t>();
   // Note that the value is truncated here reather than rounded, potentially
   // introducing an error of .5 bytes if rounding were expected.
   return DataSize::bytes(data_rate_impl::MillibytePerSec(rate) / millihertz);
 }
-inline Frequency operator/(const DataRate rate, const DataSize size) {
+inline constexpr Frequency operator/(const DataRate rate, const DataSize size) {
   return Frequency::millihertz(data_rate_impl::MillibytePerSec(rate) /
                                size.bytes());
 }
-inline DataRate operator*(const DataSize size, const Frequency frequency) {
+inline constexpr DataRate operator*(const DataSize size,
+                                    const Frequency frequency) {
   RTC_DCHECK(frequency.IsZero() ||
              size.bytes() <= std::numeric_limits<int64_t>::max() / 8 /
                                  frequency.millihertz<int64_t>());
@@ -133,7 +138,8 @@
       size.bytes() * 8 * frequency.millihertz<int64_t>();
   return DataRate::bps((millibits_per_second + 500) / 1000);
 }
-inline DataRate operator*(const Frequency frequency, const DataSize size) {
+inline constexpr DataRate operator*(const Frequency frequency,
+                                    const DataSize size) {
   return size * frequency;
 }
 
diff --git a/api/units/data_size.h b/api/units/data_size.h
index ca4c1da..d294016 100644
--- a/api/units/data_size.h
+++ b/api/units/data_size.h
@@ -32,12 +32,12 @@
   }
 
   template <typename T>
-  static DataSize bytes(T bytes) {
+  static constexpr DataSize bytes(T bytes) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromValue(bytes);
   }
   template <typename T = int64_t>
-  T bytes() const {
+  constexpr T bytes() const {
     return ToValue<T>();
   }
 
diff --git a/api/units/frequency.h b/api/units/frequency.h
index aa54cb5..45561f4 100644
--- a/api/units/frequency.h
+++ b/api/units/frequency.h
@@ -32,21 +32,21 @@
     return FromFraction(1000, hertz);
   }
   template <typename T>
-  static Frequency hertz(T hertz) {
+  static constexpr Frequency hertz(T hertz) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromFraction(1000, hertz);
   }
   template <typename T>
-  static Frequency millihertz(T hertz) {
+  static constexpr Frequency millihertz(T hertz) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromValue(hertz);
   }
   template <typename T = int64_t>
-  T hertz() const {
+  constexpr T hertz() const {
     return ToFraction<1000, T>();
   }
   template <typename T = int64_t>
-  T millihertz() const {
+  constexpr T millihertz() const {
     return ToValue<T>();
   }
 
@@ -56,7 +56,8 @@
   static constexpr bool one_sided = true;
 };
 
-inline Frequency operator/(int64_t nominator, const TimeDelta& interval) {
+inline constexpr Frequency operator/(int64_t nominator,
+                                     const TimeDelta& interval) {
   constexpr int64_t kKiloPerMicro = 1000 * 1000000;
   RTC_DCHECK_LE(nominator, std::numeric_limits<int64_t>::max() / kKiloPerMicro);
   RTC_CHECK(interval.IsFinite());
@@ -64,7 +65,8 @@
   return Frequency::millihertz(nominator * kKiloPerMicro / interval.us());
 }
 
-inline TimeDelta operator/(int64_t nominator, const Frequency& frequency) {
+inline constexpr TimeDelta operator/(int64_t nominator,
+                                     const Frequency& frequency) {
   constexpr int64_t kMegaPerMilli = 1000000 * 1000;
   RTC_DCHECK_LE(nominator, std::numeric_limits<int64_t>::max() / kMegaPerMilli);
   RTC_CHECK(frequency.IsFinite());
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
index 0c3fd9d..030974f 100644
--- a/api/units/time_delta.h
+++ b/api/units/time_delta.h
@@ -46,34 +46,34 @@
     return FromValue(us);
   }
   template <typename T>
-  static TimeDelta seconds(T seconds) {
+  static constexpr TimeDelta seconds(T seconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromFraction(1'000'000, seconds);
   }
   template <typename T>
-  static TimeDelta ms(T milliseconds) {
+  static constexpr TimeDelta ms(T milliseconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromFraction(1000, milliseconds);
   }
   template <typename T>
-  static TimeDelta us(T microseconds) {
+  static constexpr TimeDelta us(T microseconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromValue(microseconds);
   }
   template <typename T = int64_t>
-  T seconds() const {
+  constexpr T seconds() const {
     return ToFraction<1000000, T>();
   }
   template <typename T = int64_t>
-  T ms() const {
+  constexpr T ms() const {
     return ToFraction<1000, T>();
   }
   template <typename T = int64_t>
-  T us() const {
+  constexpr T us() const {
     return ToValue<T>();
   }
   template <typename T = int64_t>
-  T ns() const {
+  constexpr T ns() const {
     return ToMultiple<1000, T>();
   }
 
@@ -87,7 +87,9 @@
     return ToValueOr(fallback_value);
   }
 
-  TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
+  constexpr TimeDelta Abs() const {
+    return us() < 0 ? TimeDelta::us(-us()) : *this;
+  }
 
  private:
   friend class rtc_units_impl::UnitBase<TimeDelta>;
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
index e12e99d..f9ed408 100644
--- a/api/units/timestamp.h
+++ b/api/units/timestamp.h
@@ -44,30 +44,30 @@
   }
 
   template <typename T>
-  static Timestamp seconds(T seconds) {
+  static constexpr Timestamp seconds(T seconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromFraction(1'000'000, seconds);
   }
   template <typename T>
-  static Timestamp ms(T milliseconds) {
+  static constexpr Timestamp ms(T milliseconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromFraction(1000, milliseconds);
   }
   template <typename T>
-  static Timestamp us(T microseconds) {
+  static constexpr Timestamp us(T microseconds) {
     static_assert(std::is_arithmetic<T>::value, "");
     return FromValue(microseconds);
   }
   template <typename T = int64_t>
-  T seconds() const {
+  constexpr T seconds() const {
     return ToFraction<1000000, T>();
   }
   template <typename T = int64_t>
-  T ms() const {
+  constexpr T ms() const {
     return ToFraction<1000, T>();
   }
   template <typename T = int64_t>
-  T us() const {
+  constexpr T us() const {
     return ToValue<T>();
   }
 
@@ -81,7 +81,7 @@
     return ToValueOr(fallback_value);
   }
 
-  Timestamp operator+(const TimeDelta delta) const {
+  constexpr Timestamp operator+(const TimeDelta delta) const {
     if (IsPlusInfinity() || delta.IsPlusInfinity()) {
       RTC_DCHECK(!IsMinusInfinity());
       RTC_DCHECK(!delta.IsMinusInfinity());
@@ -93,7 +93,7 @@
     }
     return Timestamp::us(us() + delta.us());
   }
-  Timestamp operator-(const TimeDelta delta) const {
+  constexpr Timestamp operator-(const TimeDelta delta) const {
     if (IsPlusInfinity() || delta.IsMinusInfinity()) {
       RTC_DCHECK(!IsMinusInfinity());
       RTC_DCHECK(!delta.IsPlusInfinity());
@@ -105,7 +105,7 @@
     }
     return Timestamp::us(us() - delta.us());
   }
-  TimeDelta operator-(const Timestamp other) const {
+  constexpr TimeDelta operator-(const Timestamp other) const {
     if (IsPlusInfinity() || other.IsMinusInfinity()) {
       RTC_DCHECK(!IsMinusInfinity());
       RTC_DCHECK(!other.IsPlusInfinity());
@@ -117,11 +117,11 @@
     }
     return TimeDelta::us(us() - other.us());
   }
-  Timestamp& operator-=(const TimeDelta delta) {
+  constexpr Timestamp& operator-=(const TimeDelta delta) {
     *this = *this - delta;
     return *this;
   }
-  Timestamp& operator+=(const TimeDelta delta) {
+  constexpr Timestamp& operator+=(const TimeDelta delta) {
     *this = *this + delta;
     return *this;
   }
diff --git a/rtc_base/units/unit_base.h b/rtc_base/units/unit_base.h
index b988f28..7196bae 100644
--- a/rtc_base/units/unit_base.h
+++ b/rtc_base/units/unit_base.h
@@ -68,21 +68,21 @@
   constexpr bool operator<(const Unit_T& other) const {
     return value_ < other.value_;
   }
-  Unit_T RoundTo(const Unit_T& resolution) const {
+  constexpr Unit_T RoundTo(const Unit_T& resolution) const {
     RTC_DCHECK(IsFinite());
     RTC_DCHECK(resolution.IsFinite());
     RTC_DCHECK_GT(resolution.value_, 0);
     return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) *
            resolution.value_;
   }
-  Unit_T RoundUpTo(const Unit_T& resolution) const {
+  constexpr Unit_T RoundUpTo(const Unit_T& resolution) const {
     RTC_DCHECK(IsFinite());
     RTC_DCHECK(resolution.IsFinite());
     RTC_DCHECK_GT(resolution.value_, 0);
     return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) *
            resolution.value_;
   }
-  Unit_T RoundDownTo(const Unit_T& resolution) const {
+  constexpr Unit_T RoundDownTo(const Unit_T& resolution) const {
     RTC_DCHECK(IsFinite());
     RTC_DCHECK(resolution.IsFinite());
     RTC_DCHECK_GT(resolution.value_, 0);
@@ -132,7 +132,8 @@
   }
 
   template <typename T = int64_t>
-  typename std::enable_if<std::is_integral<T>::value, T>::type ToValue() const {
+  constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+  ToValue() const {
     RTC_DCHECK(IsFinite());
     return rtc::dchecked_cast<T>(value_);
   }
@@ -150,8 +151,8 @@
   }
 
   template <int64_t Denominator, typename T = int64_t>
-  typename std::enable_if<std::is_integral<T>::value, T>::type ToFraction()
-      const {
+  constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+  ToFraction() const {
     RTC_DCHECK(IsFinite());
     if (Unit_T::one_sided) {
       return rtc::dchecked_cast<T>(
@@ -175,8 +176,8 @@
   }
 
   template <int64_t Factor, typename T = int64_t>
-  typename std::enable_if<std::is_integral<T>::value, T>::type ToMultiple()
-      const {
+  constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
+  ToMultiple() const {
     RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor);
     RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor);
     return rtc::dchecked_cast<T>(ToValue() * Factor);
@@ -200,9 +201,9 @@
     return std::numeric_limits<int64_t>::min();
   }
 
-  Unit_T& AsSubClassRef() { return reinterpret_cast<Unit_T&>(*this); }
+  constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); }
   constexpr const Unit_T& AsSubClassRef() const {
-    return reinterpret_cast<const Unit_T&>(*this);
+    return static_cast<const Unit_T&>(*this);
   }
   // Assumes that n >= 0 and d > 0.
   static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) {
@@ -222,14 +223,14 @@
 template <class Unit_T>
 class RelativeUnit : public UnitBase<Unit_T> {
  public:
-  Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
+  constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
     return std::max(min_value,
                     std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value));
   }
-  void Clamp(Unit_T min_value, Unit_T max_value) {
+  constexpr void Clamp(Unit_T min_value, Unit_T max_value) {
     *this = Clamped(min_value, max_value);
   }
-  Unit_T operator+(const Unit_T other) const {
+  constexpr Unit_T operator+(const Unit_T other) const {
     if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
       RTC_DCHECK(!this->IsMinusInfinity());
       RTC_DCHECK(!other.IsMinusInfinity());
@@ -241,7 +242,7 @@
     }
     return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
   }
-  Unit_T operator-(const Unit_T other) const {
+  constexpr Unit_T operator-(const Unit_T other) const {
     if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
       RTC_DCHECK(!this->IsMinusInfinity());
       RTC_DCHECK(!other.IsPlusInfinity());
@@ -253,11 +254,11 @@
     }
     return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
   }
-  Unit_T& operator+=(const Unit_T other) {
+  constexpr Unit_T& operator+=(const Unit_T other) {
     *this = *this + other;
     return this->AsSubClassRef();
   }
-  Unit_T& operator-=(const Unit_T other) {
+  constexpr Unit_T& operator-=(const Unit_T other) {
     *this = *this - other;
     return this->AsSubClassRef();
   }
@@ -266,18 +267,18 @@
            other.template ToValue<double>();
   }
   template <typename T>
-  typename std::enable_if<std::is_arithmetic<T>::value, Unit_T>::type operator/(
-      const T& scalar) const {
+  constexpr typename std::enable_if<std::is_arithmetic<T>::value, Unit_T>::type
+  operator/(const T& scalar) const {
     return UnitBase<Unit_T>::FromValue(
         std::round(UnitBase<Unit_T>::template ToValue<int64_t>() / scalar));
   }
-  Unit_T operator*(const double scalar) const {
+  constexpr Unit_T operator*(double scalar) const {
     return UnitBase<Unit_T>::FromValue(std::round(this->ToValue() * scalar));
   }
-  Unit_T operator*(const int64_t scalar) const {
+  constexpr Unit_T operator*(int64_t scalar) const {
     return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
   }
-  Unit_T operator*(const int32_t scalar) const {
+  constexpr Unit_T operator*(int32_t scalar) const {
     return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
   }
 
@@ -286,17 +287,15 @@
 };
 
 template <class Unit_T>
-inline Unit_T operator*(const double scalar, const RelativeUnit<Unit_T> other) {
+inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) {
   return other * scalar;
 }
 template <class Unit_T>
-inline Unit_T operator*(const int64_t scalar,
-                        const RelativeUnit<Unit_T> other) {
+inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) {
   return other * scalar;
 }
 template <class Unit_T>
-inline Unit_T operator*(const int32_t& scalar,
-                        const RelativeUnit<Unit_T> other) {
+inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) {
   return other * scalar;
 }
 
diff --git a/rtc_base/units/unit_base_unittest.cc b/rtc_base/units/unit_base_unittest.cc
index ccb5ce0..02ead7c 100644
--- a/rtc_base/units/unit_base_unittest.cc
+++ b/rtc_base/units/unit_base_unittest.cc
@@ -43,6 +43,10 @@
   static constexpr bool one_sided = false;
   using RelativeUnit<TestUnit>::RelativeUnit;
 };
+constexpr TestUnit TestUnitAddKilo(TestUnit value, int add_kilo) {
+  value += TestUnit::FromKilo(add_kilo);
+  return value;
+}
 }  // namespace
 namespace test {
 TEST(UnitBaseTest, ConstExpr) {
@@ -62,6 +66,8 @@
 
   static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, "");
   static_assert(kTestUnitValue.ToValueOr(0) == kValue, "");
+  static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000,
+                "");
 }
 
 TEST(UnitBaseTest, GetBackSameValues) {
diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc
index e4e4f8d..232cf06 100644
--- a/test/scenario/scenario.cc
+++ b/test/scenario/scenario.cc
@@ -30,7 +30,6 @@
 namespace webrtc {
 namespace test {
 namespace {
-const Timestamp kSimulatedStartTime = Timestamp::seconds(100000);
 
 std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
     std::string file_name) {