diff --git a/api/units/data_rate.h b/api/units/data_rate.h index 1122d5e891..47a143c889 100644 --- a/api/units/data_rate.h +++ b/api/units/data_rate.h @@ -44,6 +44,18 @@ class DataRate { static constexpr DataRate Infinity() { return DataRate(data_rate_impl::kPlusInfinityVal); } + template + static constexpr DataRate BitsPerSec() { + static_assert(bps >= 0, ""); + static_assert(bps < data_rate_impl::kPlusInfinityVal, ""); + return DataRate(bps); + } + template + 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 @@ class DataRate { } template typename std::enable_if::value, T>::type kbps() const { - return rtc::dchecked_cast((bps() + 500) / 1000); + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast(UnsafeKilobitsPerSec()); } template - typename std::enable_if::value, T>::type bps() - const { - if (IsInfinite()) { - return std::numeric_limits::infinity(); - } else { - return bits_per_sec_; - } + typename std::enable_if::value, + T>::type constexpr bps() const { + return IsInfinite() ? std::numeric_limits::infinity() : bits_per_sec_; } template - typename std::enable_if::value, T>::type kbps() - const { + typename std::enable_if::value, + T>::type constexpr kbps() const { return bps() * 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() / other.bps(); } - 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 @@ class DataRate { // 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 b0cc0138dd..9c91fd6247 100644 --- a/api/units/data_rate_unittest.cc +++ b/api/units/data_rate_unittest.cc @@ -15,10 +15,19 @@ namespace webrtc { 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(); + constexpr DataRate kDataRateKbps = DataRate::KilobitsPerSec(); + static_assert(kDataRateBps.bps() == 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 6fe1259e68..00ab2eccf7 100644 --- a/api/units/data_size.h +++ b/api/units/data_size.h @@ -33,6 +33,12 @@ class DataSize { static constexpr DataSize Infinity() { return DataSize(data_size_impl::kPlusInfinityVal); } + template + 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 @@ class DataSize { } template - typename std::enable_if::value, T>::type bytes() - const { - if (IsInfinite()) { - return std::numeric_limits::infinity(); - } else { - return bytes_; - } + constexpr typename std::enable_if::value, T>::type + bytes() const { + return IsInfinite() ? std::numeric_limits::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 @@ class DataSize { bytes_ += other.bytes(); return *this; } - double operator/(const DataSize& other) const { + constexpr double 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 { + 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 e8e16362c5..fe7f591dc0 100644 --- a/api/units/data_size_unittest.cc +++ b/api/units/data_size_unittest.cc @@ -15,10 +15,18 @@ namespace webrtc { 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(); + 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 1a636bd09d..1155eb526b 100644 --- a/api/units/time_delta.h +++ b/api/units/time_delta.h @@ -42,6 +42,24 @@ class TimeDelta { static constexpr TimeDelta MinusInfinity() { return TimeDelta(timedelta_impl::kMinusInfinityVal); } + template + static constexpr TimeDelta Seconds() { + static_assert(seconds > timedelta_impl::kMinusInfinityVal / 1000000, ""); + static_assert(seconds < timedelta_impl::kPlusInfinityVal / 1000000, ""); + return TimeDelta(seconds * 1000000); + } + template + static constexpr TimeDelta Millis() { + static_assert(ms > timedelta_impl::kMinusInfinityVal / 1000, ""); + static_assert(ms < timedelta_impl::kPlusInfinityVal / 1000, ""); + return TimeDelta(ms * 1000); + } + template + 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 @@ class TimeDelta { template typename std::enable_if::value, T>::type seconds() const { - return rtc::dchecked_cast((us() + (us() >= 0 ? 500000 : -500000)) / - 1000000); + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast(UnsafeSeconds()); } template typename std::enable_if::value, T>::type ms() const { - return rtc::dchecked_cast((us() + (us() >= 0 ? 500 : -500)) / 1000); + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast(UnsafeMillis()); } template typename std::enable_if::value, T>::type us() const { @@ -118,32 +137,39 @@ class TimeDelta { } template - typename std::enable_if::value, T>::type seconds() - const { + constexpr typename std::enable_if::value, T>::type + seconds() const { return us() * 1e-6; } template - typename std::enable_if::value, T>::type ms() - const { + constexpr typename std::enable_if::value, T>::type + ms() const { return us() * 1e-3; } template - typename std::enable_if::value, T>::type us() - const { - if (IsPlusInfinity()) { - return std::numeric_limits::infinity(); - } else if (IsMinusInfinity()) { - return -std::numeric_limits::infinity(); - } else { - return microseconds_; - } + constexpr typename std::enable_if::value, T>::type + us() const { + return IsPlusInfinity() + ? std::numeric_limits::infinity() + : IsMinusInfinity() ? -std::numeric_limits::infinity() + : microseconds_; } template - typename std::enable_if::value, T>::type ns() - const { + constexpr typename std::enable_if::value, T>::type + ns() const { return us() * 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 @@ class TimeDelta { microseconds_ += other.us(); return *this; } - double operator/(const TimeDelta& other) const { + constexpr double operator/(const TimeDelta& other) const { return us() / other.us(); } - 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 int32_t& scalar, const TimeDelta& delta) { 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 a858f78482..9eddee73ad 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(); + constexpr TimeDelta kTimeDeltaMs = TimeDelta::Millis(); + constexpr TimeDelta kTimeDeltaUs = TimeDelta::Micros(); + + 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 6f4dff88bc..1b5e84ff60 100644 --- a/api/units/timestamp.h +++ b/api/units/timestamp.h @@ -35,6 +35,24 @@ class Timestamp { static constexpr Timestamp Infinity() { return Timestamp(timestamp_impl::kPlusInfinityVal); } + template + static constexpr Timestamp Seconds() { + static_assert(seconds >= 0, ""); + static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, ""); + return Timestamp(seconds * 1000000); + } + template + static constexpr Timestamp Millis() { + static_assert(ms >= 0, ""); + static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, ""); + return Timestamp(ms * 1000); + } + template + static constexpr Timestamp Micros() { + static_assert(us >= 0, ""); + static_assert(us < timestamp_impl::kPlusInfinityVal, ""); + return Timestamp(us); + } template < typename T, @@ -92,11 +110,13 @@ class Timestamp { template typename std::enable_if::value, T>::type seconds() const { - return rtc::dchecked_cast((us() + 500000) / 1000000); + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast(UnsafeSeconds()); } template typename std::enable_if::value, T>::type ms() const { - return rtc::dchecked_cast((us() + 500) / 1000); + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast(UnsafeMillis()); } template typename std::enable_if::value, T>::type us() const { @@ -105,23 +125,29 @@ class Timestamp { } template - typename std::enable_if::value, T>::type seconds() - const { + constexpr typename std::enable_if::value, T>::type + seconds() const { return us() * 1e-6; } template - typename std::enable_if::value, T>::type ms() - const { + constexpr typename std::enable_if::value, T>::type + ms() const { return us() * 1e-3; } template - typename std::enable_if::value, T>::type us() - const { - if (IsInfinite()) { - return std::numeric_limits::infinity(); - } else { - return microseconds_; - } + constexpr typename std::enable_if::value, T>::type + us() const { + return IsInfinite() ? std::numeric_limits::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 @@ class Timestamp { 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 7dfe6695d2..db894cca44 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(); + constexpr Timestamp kTimestampMs = Timestamp::Millis(); + constexpr Timestamp kTimestampUs = Timestamp::Micros(); + + 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) {