Add conversions to and from double for units.
Bug: webrtc:8415 Change-Id: I6b1f7afb163daa327e45c51f1a3fb7cafbb1444e Reviewed-on: https://webrtc-review.googlesource.com/78183 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23451}
This commit is contained in:

committed by
Commit Bot

parent
f859e55d9b
commit
942b360d82
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/time_delta.h"
|
||||
@ -43,28 +44,78 @@ class DataRate {
|
||||
static DataRate Infinity() {
|
||||
return DataRate(data_rate_impl::kPlusInfinityVal);
|
||||
}
|
||||
static DataRate bits_per_second(int64_t bits_per_sec) {
|
||||
RTC_DCHECK_GE(bits_per_sec, 0);
|
||||
return DataRate(bits_per_sec);
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static DataRate bps(T bits_per_second) {
|
||||
RTC_DCHECK_GE(bits_per_second, 0);
|
||||
RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
|
||||
return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
|
||||
}
|
||||
static DataRate bps(int64_t bits_per_sec) {
|
||||
return DataRate::bits_per_second(bits_per_sec);
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static DataRate kbps(T kilobits_per_sec) {
|
||||
RTC_DCHECK_GE(kilobits_per_sec, 0);
|
||||
RTC_DCHECK_LT(kilobits_per_sec, data_rate_impl::kPlusInfinityVal / 1000);
|
||||
return DataRate::bps(rtc::dchecked_cast<int64_t>(kilobits_per_sec) * 1000);
|
||||
}
|
||||
static DataRate kbps(int64_t kilobits_per_sec) {
|
||||
return DataRate::bits_per_second(kilobits_per_sec * 1000);
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static DataRate bps(T bits_per_second) {
|
||||
if (bits_per_second == std::numeric_limits<T>::infinity()) {
|
||||
return Infinity();
|
||||
} else {
|
||||
RTC_DCHECK(!std::isnan(bits_per_second));
|
||||
RTC_DCHECK_GE(bits_per_second, 0);
|
||||
RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal);
|
||||
return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second));
|
||||
}
|
||||
int64_t bits_per_second() const {
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static DataRate kbps(T kilobits_per_sec) {
|
||||
return DataRate::bps(kilobits_per_sec * 1e3);
|
||||
}
|
||||
|
||||
template <typename T = int64_t>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type bps() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return rtc::dchecked_cast<T>(bits_per_sec_);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
int64_t bps() const { return bits_per_second(); }
|
||||
int64_t kbps() const { return (bps() + 500) / 1000; }
|
||||
}
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type kbps()
|
||||
const {
|
||||
return bps<T>() * 1e-3;
|
||||
}
|
||||
|
||||
bool IsZero() const { return bits_per_sec_ == 0; }
|
||||
bool IsInfinite() const {
|
||||
return bits_per_sec_ == data_rate_impl::kPlusInfinityVal;
|
||||
}
|
||||
bool IsFinite() const { return !IsInfinite(); }
|
||||
|
||||
double operator/(const DataRate& other) const {
|
||||
return bps<double>() / other.bps<double>();
|
||||
}
|
||||
bool operator==(const DataRate& other) const {
|
||||
return bits_per_sec_ == other.bits_per_sec_;
|
||||
}
|
||||
@ -92,34 +143,32 @@ class DataRate {
|
||||
};
|
||||
|
||||
inline DataRate operator*(const DataRate& rate, const double& scalar) {
|
||||
return DataRate::bits_per_second(std::round(rate.bits_per_second() * scalar));
|
||||
return DataRate::bps(std::round(rate.bps() * scalar));
|
||||
}
|
||||
inline DataRate operator*(const double& scalar, const DataRate& rate) {
|
||||
return rate * scalar;
|
||||
}
|
||||
inline DataRate operator*(const DataRate& rate, const int64_t& scalar) {
|
||||
return DataRate::bits_per_second(rate.bits_per_second() * scalar);
|
||||
return DataRate::bps(rate.bps() * scalar);
|
||||
}
|
||||
inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
|
||||
return rate * scalar;
|
||||
}
|
||||
inline DataRate operator*(const DataRate& rate, const int32_t& scalar) {
|
||||
return DataRate::bits_per_second(rate.bits_per_second() * scalar);
|
||||
return DataRate::bps(rate.bps() * scalar);
|
||||
}
|
||||
inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
|
||||
return rate * scalar;
|
||||
}
|
||||
|
||||
inline DataRate operator/(const DataSize& size, const TimeDelta& duration) {
|
||||
return DataRate::bits_per_second(data_rate_impl::Microbits(size) /
|
||||
duration.us());
|
||||
return DataRate::bps(data_rate_impl::Microbits(size) / duration.us());
|
||||
}
|
||||
inline TimeDelta operator/(const DataSize& size, const DataRate& rate) {
|
||||
return TimeDelta::us(data_rate_impl::Microbits(size) /
|
||||
rate.bits_per_second());
|
||||
return TimeDelta::us(data_rate_impl::Microbits(size) / rate.bps());
|
||||
}
|
||||
inline DataSize operator*(const DataRate& rate, const TimeDelta& duration) {
|
||||
int64_t microbits = rate.bits_per_second() * duration.us();
|
||||
int64_t microbits = rate.bps() * duration.us();
|
||||
return DataSize::bytes((microbits + 4000000) / 8000000);
|
||||
}
|
||||
inline DataSize operator*(const TimeDelta& duration, const DataRate& rate) {
|
||||
|
@ -15,7 +15,6 @@ namespace webrtc {
|
||||
namespace test {
|
||||
TEST(DataRateTest, GetBackSameValues) {
|
||||
const int64_t kValue = 123 * 8;
|
||||
EXPECT_EQ(DataRate::bits_per_second(kValue).bits_per_second(), kValue);
|
||||
EXPECT_EQ(DataRate::bps(kValue).bps(), kValue);
|
||||
EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue);
|
||||
}
|
||||
@ -28,22 +27,22 @@ TEST(DataRateTest, GetDifferentPrefix) {
|
||||
TEST(DataRateTest, IdentityChecks) {
|
||||
const int64_t kValue = 3000;
|
||||
EXPECT_TRUE(DataRate::Zero().IsZero());
|
||||
EXPECT_FALSE(DataRate::bits_per_second(kValue).IsZero());
|
||||
EXPECT_FALSE(DataRate::bps(kValue).IsZero());
|
||||
|
||||
EXPECT_TRUE(DataRate::Infinity().IsInfinite());
|
||||
EXPECT_FALSE(DataRate::Zero().IsInfinite());
|
||||
EXPECT_FALSE(DataRate::bits_per_second(kValue).IsInfinite());
|
||||
EXPECT_FALSE(DataRate::bps(kValue).IsInfinite());
|
||||
|
||||
EXPECT_FALSE(DataRate::Infinity().IsFinite());
|
||||
EXPECT_TRUE(DataRate::bits_per_second(kValue).IsFinite());
|
||||
EXPECT_TRUE(DataRate::bps(kValue).IsFinite());
|
||||
EXPECT_TRUE(DataRate::Zero().IsFinite());
|
||||
}
|
||||
|
||||
TEST(DataRateTest, ComparisonOperators) {
|
||||
const int64_t kSmall = 450;
|
||||
const int64_t kLarge = 451;
|
||||
const DataRate small = DataRate::bits_per_second(kSmall);
|
||||
const DataRate large = DataRate::bits_per_second(kLarge);
|
||||
const DataRate small = DataRate::bps(kSmall);
|
||||
const DataRate large = DataRate::bps(kLarge);
|
||||
|
||||
EXPECT_EQ(DataRate::Zero(), DataRate::bps(0));
|
||||
EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity());
|
||||
@ -59,15 +58,36 @@ TEST(DataRateTest, ComparisonOperators) {
|
||||
EXPECT_GT(DataRate::Infinity(), large);
|
||||
}
|
||||
|
||||
TEST(DataRateTest, ConvertsToAndFromDouble) {
|
||||
const int64_t kValue = 128;
|
||||
const double kDoubleValue = static_cast<double>(kValue);
|
||||
const double kDoubleKbps = kValue * 1e-3;
|
||||
const double kFloatKbps = static_cast<float>(kDoubleKbps);
|
||||
|
||||
EXPECT_EQ(DataRate::bps(kValue).bps<double>(), kDoubleValue);
|
||||
EXPECT_EQ(DataRate::bps(kValue).kbps<double>(), kDoubleKbps);
|
||||
EXPECT_EQ(DataRate::bps(kValue).kbps<float>(), kFloatKbps);
|
||||
EXPECT_EQ(DataRate::bps(kDoubleValue).bps(), kValue);
|
||||
EXPECT_EQ(DataRate::kbps(kDoubleKbps).bps(), kValue);
|
||||
|
||||
const double kInfinity = std::numeric_limits<double>::infinity();
|
||||
EXPECT_EQ(DataRate::Infinity().bps<double>(), kInfinity);
|
||||
EXPECT_TRUE(DataRate::bps(kInfinity).IsInfinite());
|
||||
EXPECT_TRUE(DataRate::kbps(kInfinity).IsInfinite());
|
||||
}
|
||||
|
||||
TEST(DataRateTest, MathOperations) {
|
||||
const int64_t kValueA = 450;
|
||||
const int64_t kValueB = 267;
|
||||
const DataRate size_a = DataRate::bits_per_second(kValueA);
|
||||
const DataRate rate_a = DataRate::bps(kValueA);
|
||||
const DataRate rate_b = DataRate::bps(kValueB);
|
||||
const int32_t kInt32Value = 123;
|
||||
const double kFloatValue = 123.0;
|
||||
EXPECT_EQ((size_a * kValueB).bits_per_second(), kValueA * kValueB);
|
||||
EXPECT_EQ((size_a * kInt32Value).bits_per_second(), kValueA * kInt32Value);
|
||||
EXPECT_EQ((size_a * kFloatValue).bits_per_second(), kValueA * kFloatValue);
|
||||
EXPECT_EQ((rate_a * kValueB).bps(), kValueA * kValueB);
|
||||
EXPECT_EQ((rate_a * kInt32Value).bps(), kValueA * kInt32Value);
|
||||
EXPECT_EQ((rate_a * kFloatValue).bps(), kValueA * kFloatValue);
|
||||
|
||||
EXPECT_EQ(rate_a / rate_b, static_cast<double>(kValueA) / kValueB);
|
||||
}
|
||||
|
||||
TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
|
||||
@ -75,11 +95,11 @@ TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
|
||||
const int64_t kBitsPerSecond = 440;
|
||||
const int64_t kBytes = 44000;
|
||||
const TimeDelta delta_a = TimeDelta::seconds(kSeconds);
|
||||
const DataRate rate_b = DataRate::bits_per_second(kBitsPerSecond);
|
||||
const DataRate rate_b = DataRate::bps(kBitsPerSecond);
|
||||
const DataSize size_c = DataSize::bytes(kBytes);
|
||||
EXPECT_EQ((delta_a * rate_b).bytes(), kSeconds * kBitsPerSecond / 8);
|
||||
EXPECT_EQ((rate_b * delta_a).bytes(), kSeconds * kBitsPerSecond / 8);
|
||||
EXPECT_EQ((size_c / delta_a).bits_per_second(), kBytes * 8 / kSeconds);
|
||||
EXPECT_EQ((size_c / delta_a).bps(), kBytes * 8 / kSeconds);
|
||||
EXPECT_EQ((size_c / rate_b).seconds(), kBytes * 8 / kBitsPerSecond);
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,10 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace data_size_impl {
|
||||
@ -31,15 +33,46 @@ class DataSize {
|
||||
static DataSize Infinity() {
|
||||
return DataSize(data_size_impl::kPlusInfinityVal);
|
||||
}
|
||||
static DataSize bytes(int64_t bytes) {
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static DataSize bytes(T bytes) {
|
||||
RTC_DCHECK_GE(bytes, 0);
|
||||
return DataSize(bytes);
|
||||
RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
|
||||
return DataSize(rtc::dchecked_cast<int64_t>(bytes));
|
||||
}
|
||||
int64_t bytes() const {
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static DataSize bytes(T bytes) {
|
||||
if (bytes == std::numeric_limits<T>::infinity()) {
|
||||
return Infinity();
|
||||
} else {
|
||||
RTC_DCHECK(!std::isnan(bytes));
|
||||
RTC_DCHECK_GE(bytes, 0);
|
||||
RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal);
|
||||
return DataSize(rtc::dchecked_cast<int64_t>(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T = int64_t>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type bytes() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return rtc::dchecked_cast<T>(bytes_);
|
||||
}
|
||||
|
||||
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_;
|
||||
}
|
||||
int64_t kilobytes() const { return (bytes() + 500) / 1000; }
|
||||
}
|
||||
|
||||
bool IsZero() const { return bytes_ == 0; }
|
||||
bool IsInfinite() const { return bytes_ == data_size_impl::kPlusInfinityVal; }
|
||||
bool IsFinite() const { return !IsInfinite(); }
|
||||
@ -57,6 +90,9 @@ class DataSize {
|
||||
bytes_ += other.bytes();
|
||||
return *this;
|
||||
}
|
||||
double operator/(const DataSize& other) const {
|
||||
return bytes<double>() / other.bytes<double>();
|
||||
}
|
||||
bool operator==(const DataSize& other) const {
|
||||
return bytes_ == other.bytes_;
|
||||
}
|
||||
@ -76,6 +112,7 @@ class DataSize {
|
||||
explicit DataSize(int64_t bytes) : bytes_(bytes) {}
|
||||
int64_t bytes_;
|
||||
};
|
||||
|
||||
inline DataSize operator*(const DataSize& size, const double& scalar) {
|
||||
return DataSize::bytes(std::round(size.bytes() * scalar));
|
||||
}
|
||||
|
@ -19,11 +19,6 @@ TEST(DataSizeTest, GetBackSameValues) {
|
||||
EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue);
|
||||
}
|
||||
|
||||
TEST(DataSizeTest, GetDifferentPrefix) {
|
||||
const int64_t kValue = 123 * 8000;
|
||||
EXPECT_EQ(DataSize::bytes(kValue).kilobytes(), kValue / 1000);
|
||||
}
|
||||
|
||||
TEST(DataSizeTest, IdentityChecks) {
|
||||
const int64_t kValue = 3000;
|
||||
EXPECT_TRUE(DataSize::Zero().IsZero());
|
||||
@ -58,6 +53,18 @@ TEST(DataSizeTest, ComparisonOperators) {
|
||||
EXPECT_GT(DataSize::Infinity(), large);
|
||||
}
|
||||
|
||||
TEST(DataSizeTest, ConvertsToAndFromDouble) {
|
||||
const int64_t kValue = 128;
|
||||
const double kDoubleValue = static_cast<double>(kValue);
|
||||
|
||||
EXPECT_EQ(DataSize::bytes(kValue).bytes<double>(), kDoubleValue);
|
||||
EXPECT_EQ(DataSize::bytes(kDoubleValue).bytes(), kValue);
|
||||
|
||||
const double kInfinity = std::numeric_limits<double>::infinity();
|
||||
EXPECT_EQ(DataSize::Infinity().bytes<double>(), kInfinity);
|
||||
EXPECT_TRUE(DataSize::bytes(kInfinity).IsInfinite());
|
||||
}
|
||||
|
||||
TEST(DataSizeTest, MathOperations) {
|
||||
const int64_t kValueA = 450;
|
||||
const int64_t kValueB = 267;
|
||||
@ -73,6 +80,7 @@ TEST(DataSizeTest, MathOperations) {
|
||||
EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue);
|
||||
|
||||
EXPECT_EQ((size_a / 10).bytes(), kValueA / 10);
|
||||
EXPECT_EQ(size_a / size_b, static_cast<double>(kValueA) / kValueB);
|
||||
|
||||
DataSize mutable_size = DataSize::bytes(kValueA);
|
||||
mutable_size += size_b;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace timedelta_impl {
|
||||
@ -41,33 +42,107 @@ class TimeDelta {
|
||||
static TimeDelta MinusInfinity() {
|
||||
return TimeDelta(timedelta_impl::kMinusInfinityVal);
|
||||
}
|
||||
static TimeDelta seconds(int64_t seconds) {
|
||||
return TimeDelta::us(seconds * 1000000);
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static TimeDelta seconds(T seconds) {
|
||||
RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000);
|
||||
RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000);
|
||||
return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
|
||||
}
|
||||
static TimeDelta ms(int64_t milliseconds) {
|
||||
return TimeDelta::us(milliseconds * 1000);
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static TimeDelta ms(T milliseconds) {
|
||||
RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000);
|
||||
RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000);
|
||||
return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
|
||||
}
|
||||
static TimeDelta us(int64_t microseconds) {
|
||||
// Infinities only allowed via use of explicit constants.
|
||||
RTC_DCHECK(microseconds > std::numeric_limits<int64_t>::min());
|
||||
RTC_DCHECK(microseconds < std::numeric_limits<int64_t>::max());
|
||||
return TimeDelta(microseconds);
|
||||
}
|
||||
int64_t seconds() const {
|
||||
return (us() + (us() >= 0 ? 500000 : -500000)) / 1000000;
|
||||
}
|
||||
int64_t ms() const { return (us() + (us() >= 0 ? 500 : -500)) / 1000; }
|
||||
int64_t us() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return microseconds_;
|
||||
}
|
||||
int64_t ns() const {
|
||||
RTC_DCHECK(us() > std::numeric_limits<int64_t>::min() / 1000);
|
||||
RTC_DCHECK(us() < std::numeric_limits<int64_t>::max() / 1000);
|
||||
return us() * 1000;
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static TimeDelta us(T microseconds) {
|
||||
RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
|
||||
RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
|
||||
return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
|
||||
}
|
||||
|
||||
double SecondsAsDouble() const;
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static TimeDelta seconds(T seconds) {
|
||||
return TimeDelta::us(seconds * 1e6);
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static TimeDelta ms(T milliseconds) {
|
||||
return TimeDelta::us(milliseconds * 1e3);
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static TimeDelta us(T microseconds) {
|
||||
if (microseconds == std::numeric_limits<T>::infinity()) {
|
||||
return PlusInfinity();
|
||||
} else if (microseconds == -std::numeric_limits<T>::infinity()) {
|
||||
return MinusInfinity();
|
||||
} else {
|
||||
RTC_DCHECK(!std::isnan(microseconds));
|
||||
RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal);
|
||||
RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal);
|
||||
return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return rtc::dchecked_cast<T>(microseconds_);
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type ns() const {
|
||||
RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000);
|
||||
RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000);
|
||||
return rtc::dchecked_cast<T>(us() * 1000);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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 {
|
||||
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_;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, T>::type ns()
|
||||
const {
|
||||
return us<T>() * 1e3;
|
||||
}
|
||||
|
||||
TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
|
||||
bool IsZero() const { return microseconds_ == 0; }
|
||||
@ -96,7 +171,9 @@ class TimeDelta {
|
||||
microseconds_ += other.us();
|
||||
return *this;
|
||||
}
|
||||
|
||||
double operator/(const TimeDelta& other) const {
|
||||
return us<double>() / other.us<double>();
|
||||
}
|
||||
bool operator==(const TimeDelta& other) const {
|
||||
return microseconds_ == other.microseconds_;
|
||||
}
|
||||
|
@ -80,6 +80,51 @@ TEST(TimeDeltaTest, ComparisonOperators) {
|
||||
EXPECT_LT(TimeDelta::MinusInfinity(), TimeDelta::Zero());
|
||||
}
|
||||
|
||||
TEST(TimeDeltaTest, CanBeInititializedFromLargeInt) {
|
||||
const int kMaxInt = std::numeric_limits<int>::max();
|
||||
EXPECT_EQ(TimeDelta::seconds(kMaxInt).us(),
|
||||
static_cast<int64_t>(kMaxInt) * 1000000);
|
||||
EXPECT_EQ(TimeDelta::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
|
||||
}
|
||||
|
||||
TEST(TimeDeltaTest, ConvertsToAndFromDouble) {
|
||||
const int64_t kMicros = 17017;
|
||||
const double kNanosDouble = kMicros * 1e3;
|
||||
const double kMicrosDouble = kMicros;
|
||||
const double kMillisDouble = kMicros * 1e-3;
|
||||
const double kSecondsDouble = kMillisDouble * 1e-3;
|
||||
|
||||
EXPECT_EQ(TimeDelta::us(kMicros).seconds<double>(), kSecondsDouble);
|
||||
EXPECT_EQ(TimeDelta::seconds(kSecondsDouble).us(), kMicros);
|
||||
|
||||
EXPECT_EQ(TimeDelta::us(kMicros).ms<double>(), kMillisDouble);
|
||||
EXPECT_EQ(TimeDelta::ms(kMillisDouble).us(), kMicros);
|
||||
|
||||
EXPECT_EQ(TimeDelta::us(kMicros).us<double>(), kMicrosDouble);
|
||||
EXPECT_EQ(TimeDelta::us(kMicrosDouble).us(), kMicros);
|
||||
|
||||
EXPECT_NEAR(TimeDelta::us(kMicros).ns<double>(), kNanosDouble, 1);
|
||||
|
||||
const double kPlusInfinity = std::numeric_limits<double>::infinity();
|
||||
const double kMinusInfinity = -kPlusInfinity;
|
||||
|
||||
EXPECT_EQ(TimeDelta::PlusInfinity().seconds<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(TimeDelta::MinusInfinity().seconds<double>(), kMinusInfinity);
|
||||
EXPECT_EQ(TimeDelta::PlusInfinity().ms<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(TimeDelta::MinusInfinity().ms<double>(), kMinusInfinity);
|
||||
EXPECT_EQ(TimeDelta::PlusInfinity().us<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(TimeDelta::MinusInfinity().us<double>(), kMinusInfinity);
|
||||
EXPECT_EQ(TimeDelta::PlusInfinity().ns<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(TimeDelta::MinusInfinity().ns<double>(), kMinusInfinity);
|
||||
|
||||
EXPECT_TRUE(TimeDelta::seconds(kPlusInfinity).IsPlusInfinity());
|
||||
EXPECT_TRUE(TimeDelta::seconds(kMinusInfinity).IsMinusInfinity());
|
||||
EXPECT_TRUE(TimeDelta::ms(kPlusInfinity).IsPlusInfinity());
|
||||
EXPECT_TRUE(TimeDelta::ms(kMinusInfinity).IsMinusInfinity());
|
||||
EXPECT_TRUE(TimeDelta::us(kPlusInfinity).IsPlusInfinity());
|
||||
EXPECT_TRUE(TimeDelta::us(kMinusInfinity).IsMinusInfinity());
|
||||
}
|
||||
|
||||
TEST(TimeDeltaTest, MathOperations) {
|
||||
const int64_t kValueA = 267;
|
||||
const int64_t kValueB = 450;
|
||||
@ -94,6 +139,9 @@ TEST(TimeDeltaTest, MathOperations) {
|
||||
EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value);
|
||||
EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue);
|
||||
|
||||
EXPECT_EQ((delta_b / 10).ms(), kValueB / 10);
|
||||
EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA);
|
||||
|
||||
EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
|
||||
EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
|
||||
}
|
||||
|
@ -13,14 +13,6 @@
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
|
||||
namespace webrtc {
|
||||
double Timestamp::SecondsAsDouble() const {
|
||||
if (IsInfinite()) {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
} else {
|
||||
return us() * 1e-6;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ToString(const Timestamp& value) {
|
||||
char buf[64];
|
||||
rtc::SimpleStringBuilder sb(buf);
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace timestamp_impl {
|
||||
@ -34,22 +35,94 @@ class Timestamp {
|
||||
static Timestamp Infinity() {
|
||||
return Timestamp(timestamp_impl::kPlusInfinityVal);
|
||||
}
|
||||
static Timestamp seconds(int64_t seconds) {
|
||||
return Timestamp::us(seconds * 1000000);
|
||||
}
|
||||
static Timestamp ms(int64_t millis) { return Timestamp::us(millis * 1000); }
|
||||
static Timestamp us(int64_t micros) {
|
||||
RTC_DCHECK_GE(micros, 0);
|
||||
return Timestamp(micros);
|
||||
}
|
||||
int64_t seconds() const { return (us() + 500000) / 1000000; }
|
||||
int64_t ms() const { return (us() + 500) / 1000; }
|
||||
int64_t us() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return microseconds_;
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static Timestamp seconds(T seconds) {
|
||||
RTC_DCHECK_GE(seconds, 0);
|
||||
RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000);
|
||||
return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000);
|
||||
}
|
||||
|
||||
double SecondsAsDouble() const;
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static Timestamp ms(T milliseconds) {
|
||||
RTC_DCHECK_GE(milliseconds, 0);
|
||||
RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000);
|
||||
return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000);
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
|
||||
static Timestamp us(T microseconds) {
|
||||
RTC_DCHECK_GE(microseconds, 0);
|
||||
RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
|
||||
return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static Timestamp seconds(T seconds) {
|
||||
return Timestamp::us(seconds * 1e6);
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static Timestamp ms(T milliseconds) {
|
||||
return Timestamp::us(milliseconds * 1e3);
|
||||
}
|
||||
template <typename T,
|
||||
typename std::enable_if<std::is_floating_point<T>::value>::type* =
|
||||
nullptr>
|
||||
static Timestamp us(T microseconds) {
|
||||
if (microseconds == std::numeric_limits<double>::infinity()) {
|
||||
return Infinity();
|
||||
} else {
|
||||
RTC_DCHECK(!std::isnan(microseconds));
|
||||
RTC_DCHECK_GE(microseconds, 0);
|
||||
RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal);
|
||||
return Timestamp(rtc::dchecked_cast<int64_t>(microseconds));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
template <typename T = int64_t>
|
||||
typename std::enable_if<std::is_integral<T>::value, T>::type us() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
return rtc::dchecked_cast<T>(microseconds_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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 {
|
||||
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_;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsInfinite() const {
|
||||
return microseconds_ == timestamp_impl::kPlusInfinityVal;
|
||||
|
@ -58,6 +58,39 @@ TEST(TimestampTest, ComparisonOperators) {
|
||||
EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
|
||||
}
|
||||
|
||||
TEST(TimestampTest, CanBeInititializedFromLargeInt) {
|
||||
const int kMaxInt = std::numeric_limits<int>::max();
|
||||
EXPECT_EQ(Timestamp::seconds(kMaxInt).us(),
|
||||
static_cast<int64_t>(kMaxInt) * 1000000);
|
||||
EXPECT_EQ(Timestamp::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000);
|
||||
}
|
||||
|
||||
TEST(TimestampTest, ConvertsToAndFromDouble) {
|
||||
const int64_t kMicros = 17017;
|
||||
const double kMicrosDouble = kMicros;
|
||||
const double kMillisDouble = kMicros * 1e-3;
|
||||
const double kSecondsDouble = kMillisDouble * 1e-3;
|
||||
|
||||
EXPECT_EQ(Timestamp::us(kMicros).seconds<double>(), kSecondsDouble);
|
||||
EXPECT_EQ(Timestamp::seconds(kSecondsDouble).us(), kMicros);
|
||||
|
||||
EXPECT_EQ(Timestamp::us(kMicros).ms<double>(), kMillisDouble);
|
||||
EXPECT_EQ(Timestamp::ms(kMillisDouble).us(), kMicros);
|
||||
|
||||
EXPECT_EQ(Timestamp::us(kMicros).us<double>(), kMicrosDouble);
|
||||
EXPECT_EQ(Timestamp::us(kMicrosDouble).us(), kMicros);
|
||||
|
||||
const double kPlusInfinity = std::numeric_limits<double>::infinity();
|
||||
|
||||
EXPECT_EQ(Timestamp::Infinity().seconds<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(Timestamp::Infinity().ms<double>(), kPlusInfinity);
|
||||
EXPECT_EQ(Timestamp::Infinity().us<double>(), kPlusInfinity);
|
||||
|
||||
EXPECT_TRUE(Timestamp::seconds(kPlusInfinity).IsInfinite());
|
||||
EXPECT_TRUE(Timestamp::ms(kPlusInfinity).IsInfinite());
|
||||
EXPECT_TRUE(Timestamp::us(kPlusInfinity).IsInfinite());
|
||||
}
|
||||
|
||||
TEST(UnitConversionTest, TimestampAndTimeDeltaMath) {
|
||||
const int64_t kValueA = 267;
|
||||
const int64_t kValueB = 450;
|
||||
|
Reference in New Issue
Block a user