Adds constexpr create functions for units.

This adds new constexpr create function for DataSize, DataRate,
TimeDelta and Timestamp. The names are capitalized to mirror the
naming scheme of the previously constexpr methods (Zero and
Infinity create functions). They are also kept longer since they
are not expected to be used in complex expressions.

Bug: webrtc:9574
Change-Id: I5950548718675050fc5d66699de295455c310861
Reviewed-on: https://webrtc-review.googlesource.com/91161
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24218}
diff --git a/api/units/data_rate.h b/api/units/data_rate.h
index 1122d5e..47a143c 100644
--- a/api/units/data_rate.h
+++ b/api/units/data_rate.h
@@ -44,6 +44,18 @@
   static constexpr DataRate Infinity() {
     return DataRate(data_rate_impl::kPlusInfinityVal);
   }
+  template <int64_t bps>
+  static constexpr DataRate BitsPerSec() {
+    static_assert(bps >= 0, "");
+    static_assert(bps < data_rate_impl::kPlusInfinityVal, "");
+    return DataRate(bps);
+  }
+  template <int64_t kbps>
+  static constexpr DataRate KilobitsPerSec() {
+    static_assert(kbps >= 0, "");
+    static_assert(kbps < data_rate_impl::kPlusInfinityVal / 1000, "");
+    return DataRate(kbps * 1000);
+  }
 
   template <
       typename T,
@@ -89,49 +101,53 @@
   }
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type kbps() const {
-    return rtc::dchecked_cast<T>((bps() + 500) / 1000);
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(UnsafeKilobitsPerSec());
   }
 
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type bps()
-      const {
-    if (IsInfinite()) {
-      return std::numeric_limits<T>::infinity();
-    } else {
-      return bits_per_sec_;
-    }
+  typename std::enable_if<std::is_floating_point<T>::value,
+                          T>::type constexpr bps() const {
+    return IsInfinite() ? std::numeric_limits<T>::infinity() : bits_per_sec_;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type kbps()
-      const {
+  typename std::enable_if<std::is_floating_point<T>::value,
+                          T>::type constexpr kbps() const {
     return bps<T>() * 1e-3;
   }
 
+  constexpr int64_t bps_or(int64_t fallback_value) const {
+    return IsFinite() ? bits_per_sec_ : fallback_value;
+  }
+  constexpr int64_t kbps_or(int64_t fallback_value) const {
+    return IsFinite() ? UnsafeKilobitsPerSec() : fallback_value;
+  }
+
   constexpr bool IsZero() const { return bits_per_sec_ == 0; }
   constexpr bool IsInfinite() const {
     return bits_per_sec_ == data_rate_impl::kPlusInfinityVal;
   }
   constexpr bool IsFinite() const { return !IsInfinite(); }
 
-  double operator/(const DataRate& other) const {
+  constexpr double operator/(const DataRate& other) const {
     return bps<double>() / other.bps<double>();
   }
-  bool operator==(const DataRate& other) const {
+  constexpr bool operator==(const DataRate& other) const {
     return bits_per_sec_ == other.bits_per_sec_;
   }
-  bool operator!=(const DataRate& other) const {
+  constexpr bool operator!=(const DataRate& other) const {
     return bits_per_sec_ != other.bits_per_sec_;
   }
-  bool operator<=(const DataRate& other) const {
+  constexpr bool operator<=(const DataRate& other) const {
     return bits_per_sec_ <= other.bits_per_sec_;
   }
-  bool operator>=(const DataRate& other) const {
+  constexpr bool operator>=(const DataRate& other) const {
     return bits_per_sec_ >= other.bits_per_sec_;
   }
-  bool operator>(const DataRate& other) const {
+  constexpr bool operator>(const DataRate& other) const {
     return bits_per_sec_ > other.bits_per_sec_;
   }
-  bool operator<(const DataRate& other) const {
+  constexpr bool operator<(const DataRate& other) const {
     return bits_per_sec_ < other.bits_per_sec_;
   }
 
@@ -140,6 +156,9 @@
   // more recognizable.
   explicit constexpr DataRate(int64_t bits_per_second)
       : bits_per_sec_(bits_per_second) {}
+  constexpr int64_t UnsafeKilobitsPerSec() const {
+    return (bits_per_sec_ + 500) / 1000;
+  }
   int64_t bits_per_sec_;
 };
 
diff --git a/api/units/data_rate_unittest.cc b/api/units/data_rate_unittest.cc
index b0cc013..9c91fd6 100644
--- a/api/units/data_rate_unittest.cc
+++ b/api/units/data_rate_unittest.cc
@@ -15,10 +15,19 @@
 namespace test {
 
 TEST(DataRateTest, ConstExpr) {
+  constexpr int64_t kValue = 12345;
   constexpr DataRate kDataRateZero = DataRate::Zero();
   constexpr DataRate kDataRateInf = DataRate::Infinity();
   static_assert(kDataRateZero.IsZero(), "");
   static_assert(kDataRateInf.IsInfinite(), "");
+  static_assert(kDataRateInf.bps_or(-1) == -1, "");
+  static_assert(kDataRateInf > kDataRateZero, "");
+
+  constexpr DataRate kDataRateBps = DataRate::BitsPerSec<kValue>();
+  constexpr DataRate kDataRateKbps = DataRate::KilobitsPerSec<kValue>();
+  static_assert(kDataRateBps.bps<double>() == kValue, "");
+  static_assert(kDataRateBps.bps_or(0) == kValue, "");
+  static_assert(kDataRateKbps.kbps_or(0) == kValue, "");
 }
 
 TEST(DataRateTest, GetBackSameValues) {
diff --git a/api/units/data_size.h b/api/units/data_size.h
index 6fe1259..00ab2ec 100644
--- a/api/units/data_size.h
+++ b/api/units/data_size.h
@@ -33,6 +33,12 @@
   static constexpr DataSize Infinity() {
     return DataSize(data_size_impl::kPlusInfinityVal);
   }
+  template <int64_t bytes>
+  static constexpr DataSize Bytes() {
+    static_assert(bytes >= 0, "");
+    static_assert(bytes < data_size_impl::kPlusInfinityVal, "");
+    return DataSize(bytes);
+  }
 
   template <
       typename T,
@@ -64,13 +70,13 @@
   }
 
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type bytes()
-      const {
-    if (IsInfinite()) {
-      return std::numeric_limits<T>::infinity();
-    } else {
-      return bytes_;
-    }
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  bytes() const {
+    return IsInfinite() ? std::numeric_limits<T>::infinity() : bytes_;
+  }
+
+  constexpr int64_t bytes_or(int64_t fallback_value) const {
+    return IsFinite() ? bytes_ : fallback_value;
   }
 
   constexpr bool IsZero() const { return bytes_ == 0; }
@@ -92,23 +98,27 @@
     bytes_ += other.bytes();
     return *this;
   }
-  double operator/(const DataSize& other) const {
+  constexpr double operator/(const DataSize& other) const {
     return bytes<double>() / other.bytes<double>();
   }
-  bool operator==(const DataSize& other) const {
+  constexpr bool operator==(const DataSize& other) const {
     return bytes_ == other.bytes_;
   }
-  bool operator!=(const DataSize& other) const {
+  constexpr bool operator!=(const DataSize& other) const {
     return bytes_ != other.bytes_;
   }
-  bool operator<=(const DataSize& other) const {
+  constexpr bool operator<=(const DataSize& other) const {
     return bytes_ <= other.bytes_;
   }
-  bool operator>=(const DataSize& other) const {
+  constexpr bool operator>=(const DataSize& other) const {
     return bytes_ >= other.bytes_;
   }
-  bool operator>(const DataSize& other) const { return bytes_ > other.bytes_; }
-  bool operator<(const DataSize& other) const { return bytes_ < other.bytes_; }
+  constexpr bool operator>(const DataSize& other) const {
+    return bytes_ > other.bytes_;
+  }
+  constexpr bool operator<(const DataSize& other) const {
+    return bytes_ < other.bytes_;
+  }
 
  private:
   explicit constexpr DataSize(int64_t bytes) : bytes_(bytes) {}
diff --git a/api/units/data_size_unittest.cc b/api/units/data_size_unittest.cc
index e8e1636..fe7f591 100644
--- a/api/units/data_size_unittest.cc
+++ b/api/units/data_size_unittest.cc
@@ -15,10 +15,18 @@
 namespace test {
 
 TEST(DataSizeTest, ConstExpr) {
+  constexpr int64_t kValue = 12345;
   constexpr DataSize kDataSizeZero = DataSize::Zero();
   constexpr DataSize kDataSizeInf = DataSize::Infinity();
   static_assert(kDataSizeZero.IsZero(), "");
   static_assert(kDataSizeInf.IsInfinite(), "");
+  static_assert(kDataSizeInf.bytes_or(-1) == -1, "");
+  static_assert(kDataSizeInf > kDataSizeZero, "");
+
+  constexpr DataSize kDataSize = DataSize::Bytes<kValue>();
+  static_assert(kDataSize.bytes_or(-1) == kValue, "");
+
+  EXPECT_EQ(kDataSize.bytes(), kValue);
 }
 
 TEST(DataSizeTest, GetBackSameValues) {
diff --git a/api/units/time_delta.h b/api/units/time_delta.h
index 1a636bd..1155eb5 100644
--- a/api/units/time_delta.h
+++ b/api/units/time_delta.h
@@ -42,6 +42,24 @@
   static constexpr TimeDelta MinusInfinity() {
     return TimeDelta(timedelta_impl::kMinusInfinityVal);
   }
+  template <int64_t seconds>
+  static constexpr TimeDelta Seconds() {
+    static_assert(seconds > timedelta_impl::kMinusInfinityVal / 1000000, "");
+    static_assert(seconds < timedelta_impl::kPlusInfinityVal / 1000000, "");
+    return TimeDelta(seconds * 1000000);
+  }
+  template <int64_t ms>
+  static constexpr TimeDelta Millis() {
+    static_assert(ms > timedelta_impl::kMinusInfinityVal / 1000, "");
+    static_assert(ms < timedelta_impl::kPlusInfinityVal / 1000, "");
+    return TimeDelta(ms * 1000);
+  }
+  template <int64_t us>
+  static constexpr TimeDelta Micros() {
+    static_assert(us > timedelta_impl::kMinusInfinityVal, "");
+    static_assert(us < timedelta_impl::kPlusInfinityVal, "");
+    return TimeDelta(us);
+  }
 
   template <
       typename T,
@@ -98,12 +116,13 @@
 
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
-    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500000 : -500000)) /
-                                 1000000);
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(UnsafeSeconds());
   }
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
-    return rtc::dchecked_cast<T>((us() + (us() >= 0 ? 500 : -500)) / 1000);
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(UnsafeMillis());
   }
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
@@ -118,32 +137,39 @@
   }
 
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
-      const {
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  seconds() const {
     return us<T>() * 1e-6;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
-      const {
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  ms() const {
     return us<T>() * 1e-3;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
-      const {
-    if (IsPlusInfinity()) {
-      return std::numeric_limits<T>::infinity();
-    } else if (IsMinusInfinity()) {
-      return -std::numeric_limits<T>::infinity();
-    } else {
-      return microseconds_;
-    }
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  us() const {
+    return IsPlusInfinity()
+               ? std::numeric_limits<T>::infinity()
+               : IsMinusInfinity() ? -std::numeric_limits<T>::infinity()
+                                   : microseconds_;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type ns()
-      const {
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  ns() const {
     return us<T>() * 1e3;
   }
 
+  constexpr int64_t seconds_or(int64_t fallback_value) const {
+    return IsFinite() ? UnsafeSeconds() : fallback_value;
+  }
+  constexpr int64_t ms_or(int64_t fallback_value) const {
+    return IsFinite() ? UnsafeMillis() : fallback_value;
+  }
+  constexpr int64_t us_or(int64_t fallback_value) const {
+    return IsFinite() ? microseconds_ : fallback_value;
+  }
+
   TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
   constexpr bool IsZero() const { return microseconds_ == 0; }
   constexpr bool IsFinite() const { return !IsInfinite(); }
@@ -171,30 +197,36 @@
     microseconds_ += other.us();
     return *this;
   }
-  double operator/(const TimeDelta& other) const {
+  constexpr double operator/(const TimeDelta& other) const {
     return us<double>() / other.us<double>();
   }
-  bool operator==(const TimeDelta& other) const {
+  constexpr bool operator==(const TimeDelta& other) const {
     return microseconds_ == other.microseconds_;
   }
-  bool operator!=(const TimeDelta& other) const {
+  constexpr bool operator!=(const TimeDelta& other) const {
     return microseconds_ != other.microseconds_;
   }
-  bool operator<=(const TimeDelta& other) const {
+  constexpr bool operator<=(const TimeDelta& other) const {
     return microseconds_ <= other.microseconds_;
   }
-  bool operator>=(const TimeDelta& other) const {
+  constexpr bool operator>=(const TimeDelta& other) const {
     return microseconds_ >= other.microseconds_;
   }
-  bool operator>(const TimeDelta& other) const {
+  constexpr bool operator>(const TimeDelta& other) const {
     return microseconds_ > other.microseconds_;
   }
-  bool operator<(const TimeDelta& other) const {
+  constexpr bool operator<(const TimeDelta& other) const {
     return microseconds_ < other.microseconds_;
   }
 
  private:
   explicit constexpr TimeDelta(int64_t us) : microseconds_(us) {}
+  constexpr int64_t UnsafeSeconds() const {
+    return (microseconds_ + (microseconds_ >= 0 ? 500000 : -500000)) / 1000000;
+  }
+  constexpr int64_t UnsafeMillis() const {
+    return (microseconds_ + (microseconds_ >= 0 ? 500 : -500)) / 1000;
+  }
   int64_t microseconds_;
 };
 
@@ -220,7 +252,6 @@
 inline TimeDelta operator/(const TimeDelta& delta, const int64_t& scalar) {
   return TimeDelta::us(delta.us() / scalar);
 }
-
 std::string ToString(const TimeDelta& value);
 }  // namespace webrtc
 
diff --git a/api/units/time_delta_unittest.cc b/api/units/time_delta_unittest.cc
index a858f78..9eddee7 100644
--- a/api/units/time_delta_unittest.cc
+++ b/api/units/time_delta_unittest.cc
@@ -15,12 +15,24 @@
 namespace webrtc {
 namespace test {
 TEST(TimeDeltaTest, ConstExpr) {
+  constexpr int64_t kValue = -12345;
   constexpr TimeDelta kTimeDeltaZero = TimeDelta::Zero();
   constexpr TimeDelta kTimeDeltaPlusInf = TimeDelta::PlusInfinity();
   constexpr TimeDelta kTimeDeltaMinusInf = TimeDelta::MinusInfinity();
   static_assert(kTimeDeltaZero.IsZero(), "");
   static_assert(kTimeDeltaPlusInf.IsPlusInfinity(), "");
   static_assert(kTimeDeltaMinusInf.IsMinusInfinity(), "");
+  static_assert(kTimeDeltaPlusInf.ms_or(-1) == -1, "");
+
+  static_assert(kTimeDeltaPlusInf > kTimeDeltaZero, "");
+
+  constexpr TimeDelta kTimeDeltaSeconds = TimeDelta::Seconds<kValue>();
+  constexpr TimeDelta kTimeDeltaMs = TimeDelta::Millis<kValue>();
+  constexpr TimeDelta kTimeDeltaUs = TimeDelta::Micros<kValue>();
+
+  static_assert(kTimeDeltaSeconds.seconds_or(0) == kValue, "");
+  static_assert(kTimeDeltaMs.ms_or(0) == kValue, "");
+  static_assert(kTimeDeltaUs.us_or(0) == kValue, "");
 }
 
 TEST(TimeDeltaTest, GetBackSameValues) {
diff --git a/api/units/timestamp.h b/api/units/timestamp.h
index 6f4dff8..1b5e84f 100644
--- a/api/units/timestamp.h
+++ b/api/units/timestamp.h
@@ -35,6 +35,24 @@
   static constexpr Timestamp Infinity() {
     return Timestamp(timestamp_impl::kPlusInfinityVal);
   }
+  template <int64_t seconds>
+  static constexpr Timestamp Seconds() {
+    static_assert(seconds >= 0, "");
+    static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, "");
+    return Timestamp(seconds * 1000000);
+  }
+  template <int64_t ms>
+  static constexpr Timestamp Millis() {
+    static_assert(ms >= 0, "");
+    static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, "");
+    return Timestamp(ms * 1000);
+  }
+  template <int64_t us>
+  static constexpr Timestamp Micros() {
+    static_assert(us >= 0, "");
+    static_assert(us < timestamp_impl::kPlusInfinityVal, "");
+    return Timestamp(us);
+  }
 
   template <
       typename T,
@@ -92,11 +110,13 @@
 
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const {
-    return rtc::dchecked_cast<T>((us() + 500000) / 1000000);
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(UnsafeSeconds());
   }
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type ms() const {
-    return rtc::dchecked_cast<T>((us() + 500) / 1000);
+    RTC_DCHECK(IsFinite());
+    return rtc::dchecked_cast<T>(UnsafeMillis());
   }
   template <typename T = int64_t>
   typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
@@ -105,23 +125,29 @@
   }
 
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type seconds()
-      const {
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  seconds() const {
     return us<T>() * 1e-6;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type ms()
-      const {
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  ms() const {
     return us<T>() * 1e-3;
   }
   template <typename T>
-  typename std::enable_if<std::is_floating_point<T>::value, T>::type us()
-      const {
-    if (IsInfinite()) {
-      return std::numeric_limits<T>::infinity();
-    } else {
-      return microseconds_;
-    }
+  constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
+  us() const {
+    return IsInfinite() ? std::numeric_limits<T>::infinity() : microseconds_;
+  }
+
+  constexpr int64_t seconds_or(int64_t fallback_value) const {
+    return IsFinite() ? UnsafeSeconds() : fallback_value;
+  }
+  constexpr int64_t ms_or(int64_t fallback_value) const {
+    return IsFinite() ? UnsafeMillis() : fallback_value;
+  }
+  constexpr int64_t us_or(int64_t fallback_value) const {
+    return IsFinite() ? microseconds_ : fallback_value;
   }
 
   constexpr bool IsInfinite() const {
@@ -145,27 +171,33 @@
     microseconds_ += other.us();
     return *this;
   }
-  bool operator==(const Timestamp& other) const {
+  constexpr bool operator==(const Timestamp& other) const {
     return microseconds_ == other.microseconds_;
   }
-  bool operator!=(const Timestamp& other) const {
+  constexpr bool operator!=(const Timestamp& other) const {
     return microseconds_ != other.microseconds_;
   }
-  bool operator<=(const Timestamp& other) const {
+  constexpr bool operator<=(const Timestamp& other) const {
     return microseconds_ <= other.microseconds_;
   }
-  bool operator>=(const Timestamp& other) const {
+  constexpr bool operator>=(const Timestamp& other) const {
     return microseconds_ >= other.microseconds_;
   }
-  bool operator>(const Timestamp& other) const {
+  constexpr bool operator>(const Timestamp& other) const {
     return microseconds_ > other.microseconds_;
   }
-  bool operator<(const Timestamp& other) const {
+  constexpr bool operator<(const Timestamp& other) const {
     return microseconds_ < other.microseconds_;
   }
 
  private:
   explicit constexpr Timestamp(int64_t us) : microseconds_(us) {}
+  constexpr int64_t UnsafeSeconds() const {
+    return (microseconds_ + 500000) / 1000000;
+  }
+  constexpr int64_t UnsafeMillis() const {
+    return (microseconds_ + 500) / 1000;
+  }
   int64_t microseconds_;
 };
 
diff --git a/api/units/timestamp_unittest.cc b/api/units/timestamp_unittest.cc
index 7dfe669..db894cc 100644
--- a/api/units/timestamp_unittest.cc
+++ b/api/units/timestamp_unittest.cc
@@ -14,8 +14,24 @@
 namespace webrtc {
 namespace test {
 TEST(TimestampTest, ConstExpr) {
+  constexpr int64_t kValue = 12345;
   constexpr Timestamp kTimestampInf = Timestamp::Infinity();
   static_assert(kTimestampInf.IsInfinite(), "");
+  static_assert(kTimestampInf.ms_or(-1) == -1, "");
+
+  constexpr Timestamp kTimestampSeconds = Timestamp::Seconds<kValue>();
+  constexpr Timestamp kTimestampMs = Timestamp::Millis<kValue>();
+  constexpr Timestamp kTimestampUs = Timestamp::Micros<kValue>();
+
+  static_assert(kTimestampSeconds.seconds_or(0) == kValue, "");
+  static_assert(kTimestampMs.ms_or(0) == kValue, "");
+  static_assert(kTimestampUs.us_or(0) == kValue, "");
+
+  static_assert(kTimestampMs > kTimestampUs, "");
+
+  EXPECT_EQ(kTimestampSeconds.seconds(), kValue);
+  EXPECT_EQ(kTimestampMs.ms(), kValue);
+  EXPECT_EQ(kTimestampUs.us(), kValue);
 }
 
 TEST(TimestampTest, GetBackSameValues) {