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) {