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}
This commit is contained in:
Sebastian Jansson
2020-01-29 10:44:51 +01:00
committed by Commit Bot
parent 48be482d73
commit d7fade5738
8 changed files with 79 additions and 65 deletions

View File

@ -65,7 +65,7 @@ class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
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 @@ class DataRate final : public rtc_units_impl::RelativeUnit<DataRate> {
};
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 @@ inline int64_t Microbits(const DataSize& size) {
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 @@ inline int64_t MillibytePerSec(const DataRate& size) {
}
} // 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 @@ inline DataRate operator*(const DataSize size, const Frequency frequency) {
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;
}

View File

@ -32,12 +32,12 @@ class DataSize final : public rtc_units_impl::RelativeUnit<DataSize> {
}
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>();
}

View File

@ -32,21 +32,21 @@ class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
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 @@ class Frequency final : public rtc_units_impl::RelativeUnit<Frequency> {
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 @@ inline Frequency operator/(int64_t nominator, const TimeDelta& interval) {
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());

View File

@ -46,34 +46,34 @@ class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
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 @@ class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
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>;

View File

@ -44,30 +44,30 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
}
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 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
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 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
}
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 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
}
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 @@ class Timestamp final : public rtc_units_impl::UnitBase<Timestamp> {
}
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;
}

View File

@ -68,21 +68,21 @@ class UnitBase {
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 @@ class UnitBase {
}
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 @@ class UnitBase {
}
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 @@ class UnitBase {
}
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 @@ class UnitBase {
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 @@ class UnitBase {
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 @@ class RelativeUnit : public UnitBase<Unit_T> {
}
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 @@ class RelativeUnit : public UnitBase<Unit_T> {
}
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 @@ class RelativeUnit : public UnitBase<Unit_T> {
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 @@ class RelativeUnit : public UnitBase<Unit_T> {
};
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;
}

View File

@ -43,6 +43,10 @@ class TestUnit final : public rtc_units_impl::RelativeUnit<TestUnit> {
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 @@ TEST(UnitBaseTest, ConstExpr) {
static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, "");
static_assert(kTestUnitValue.ToValueOr(0) == kValue, "");
static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000,
"");
}
TEST(UnitBaseTest, GetBackSameValues) {

View File

@ -30,7 +30,6 @@ ABSL_FLAG(std::string,
namespace webrtc {
namespace test {
namespace {
const Timestamp kSimulatedStartTime = Timestamp::seconds(100000);
std::unique_ptr<FileLogWriterFactory> GetScenarioLogManager(
std::string file_name) {