diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/units')
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/BUILD.gn | 34 | ||||
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/OWNERS | 1 | ||||
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/unit_base.h | 311 | ||||
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build | 209 | ||||
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc | 251 |
5 files changed, 806 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/units/BUILD.gn b/third_party/libwebrtc/rtc_base/units/BUILD.gn new file mode 100644 index 0000000000..bbb87a009a --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. +# +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file in the root of the source +# tree. An additional intellectual property rights grant can be found +# in the file PATENTS. All contributing project authors may +# be found in the AUTHORS file in the root of the source tree. + +import("../../webrtc.gni") + +rtc_source_set("unit_base") { + visibility = [ + ":*", + "../../api/units:*", + ] + sources = [ "unit_base.h" ] + + deps = [ + "../../rtc_base:checks", + "../../rtc_base:divide_round", + "../../rtc_base:safe_conversions", + ] +} + +if (rtc_include_tests) { + rtc_library("units_unittests") { + testonly = true + sources = [ "unit_base_unittest.cc" ] + deps = [ + ":unit_base", + "../../test:test_support", + ] + } +} diff --git a/third_party/libwebrtc/rtc_base/units/OWNERS b/third_party/libwebrtc/rtc_base/units/OWNERS new file mode 100644 index 0000000000..53e076b20b --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/OWNERS @@ -0,0 +1 @@ +srte@webrtc.org diff --git a/third_party/libwebrtc/rtc_base/units/unit_base.h b/third_party/libwebrtc/rtc_base/units/unit_base.h new file mode 100644 index 0000000000..a6bdbf547d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base.h @@ -0,0 +1,311 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef RTC_BASE_UNITS_UNIT_BASE_H_ +#define RTC_BASE_UNITS_UNIT_BASE_H_ + +#include <stdint.h> + +#include <algorithm> +#include <cmath> +#include <limits> +#include <type_traits> + +#include "rtc_base/checks.h" +#include "rtc_base/numerics/divide_round.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { +namespace rtc_units_impl { + +// UnitBase is a base class for implementing custom value types with a specific +// unit. It provides type safety and commonly useful operations. The underlying +// storage is always an int64_t, it's up to the unit implementation to choose +// what scale it represents. +// +// It's used like: +// class MyUnit: public UnitBase<MyUnit> {...}; +// +// Unit_T is the subclass representing the specific unit. +template <class Unit_T> +class UnitBase { + public: + UnitBase() = delete; + static constexpr Unit_T Zero() { return Unit_T(0); } + static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); } + static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); } + + constexpr bool IsZero() const { return value_ == 0; } + constexpr bool IsFinite() const { return !IsInfinite(); } + constexpr bool IsInfinite() const { + return value_ == PlusInfinityVal() || value_ == MinusInfinityVal(); + } + constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); } + constexpr bool IsMinusInfinity() const { + return value_ == MinusInfinityVal(); + } + + constexpr bool operator==(const UnitBase<Unit_T>& other) const { + return value_ == other.value_; + } + constexpr bool operator!=(const UnitBase<Unit_T>& other) const { + return value_ != other.value_; + } + constexpr bool operator<=(const UnitBase<Unit_T>& other) const { + return value_ <= other.value_; + } + constexpr bool operator>=(const UnitBase<Unit_T>& other) const { + return value_ >= other.value_; + } + constexpr bool operator>(const UnitBase<Unit_T>& other) const { + return value_ > other.value_; + } + constexpr bool operator<(const UnitBase<Unit_T>& other) const { + return value_ < other.value_; + } + 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_; + } + 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_; + } + constexpr Unit_T RoundDownTo(const Unit_T& resolution) const { + RTC_DCHECK(IsFinite()); + RTC_DCHECK(resolution.IsFinite()); + RTC_DCHECK_GT(resolution.value_, 0); + return Unit_T(value_ / resolution.value_) * resolution.value_; + } + + protected: + template < + typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> + static constexpr Unit_T FromValue(T value) { + if (Unit_T::one_sided) + RTC_DCHECK_GE(value, 0); + RTC_DCHECK_GT(value, MinusInfinityVal()); + RTC_DCHECK_LT(value, PlusInfinityVal()); + return Unit_T(rtc::dchecked_cast<int64_t>(value)); + } + template <typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = + nullptr> + static constexpr Unit_T FromValue(T value) { + if (value == std::numeric_limits<T>::infinity()) { + return PlusInfinity(); + } else if (value == -std::numeric_limits<T>::infinity()) { + return MinusInfinity(); + } else { + RTC_DCHECK(!std::isnan(value)); + return FromValue(rtc::dchecked_cast<int64_t>(value)); + } + } + + template < + typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> + static constexpr Unit_T FromFraction(int64_t denominator, T value) { + if (Unit_T::one_sided) + RTC_DCHECK_GE(value, 0); + RTC_DCHECK_GT(value, MinusInfinityVal() / denominator); + RTC_DCHECK_LT(value, PlusInfinityVal() / denominator); + return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator)); + } + template <typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = + nullptr> + static constexpr Unit_T FromFraction(int64_t denominator, T value) { + return FromValue(value * denominator); + } + + template <typename T = int64_t> + constexpr typename std::enable_if<std::is_integral<T>::value, T>::type + ToValue() const { + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast<T>(value_); + } + template <typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToValue() const { + return IsPlusInfinity() ? std::numeric_limits<T>::infinity() + : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() + : value_; + } + template <typename T> + constexpr T ToValueOr(T fallback_value) const { + return IsFinite() ? value_ : fallback_value; + } + + template <int64_t Denominator, typename T = int64_t> + constexpr typename std::enable_if<std::is_integral<T>::value, T>::type + ToFraction() const { + RTC_DCHECK(IsFinite()); + return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator)); + } + template <int64_t Denominator, typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToFraction() const { + return ToValue<T>() * (1 / static_cast<T>(Denominator)); + } + + template <int64_t Denominator> + constexpr int64_t ToFractionOr(int64_t fallback_value) const { + return IsFinite() ? DivideRoundToNearest(value_, Denominator) + : fallback_value; + } + + template <int64_t Factor, typename T = int64_t> + 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); + } + template <int64_t Factor, typename T> + constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type + ToMultiple() const { + return ToValue<T>() * Factor; + } + + explicit constexpr UnitBase(int64_t value) : value_(value) {} + + private: + template <class RelativeUnit_T> + friend class RelativeUnit; + + static inline constexpr int64_t PlusInfinityVal() { + return std::numeric_limits<int64_t>::max(); + } + static inline constexpr int64_t MinusInfinityVal() { + return std::numeric_limits<int64_t>::min(); + } + + constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); } + constexpr const Unit_T& AsSubClassRef() const { + return static_cast<const Unit_T&>(*this); + } + + int64_t value_; +}; + +// Extends UnitBase to provide operations for relative units, that is, units +// that have a meaningful relation between values such that a += b is a +// sensible thing to do. For a,b <- same unit. +template <class Unit_T> +class RelativeUnit : public UnitBase<Unit_T> { + public: + 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)); + } + constexpr void Clamp(Unit_T min_value, Unit_T max_value) { + *this = Clamped(min_value, max_value); + } + constexpr Unit_T operator+(const Unit_T other) const { + if (this->IsPlusInfinity() || other.IsPlusInfinity()) { + RTC_DCHECK(!this->IsMinusInfinity()); + RTC_DCHECK(!other.IsMinusInfinity()); + return this->PlusInfinity(); + } else if (this->IsMinusInfinity() || other.IsMinusInfinity()) { + RTC_DCHECK(!this->IsPlusInfinity()); + RTC_DCHECK(!other.IsPlusInfinity()); + return this->MinusInfinity(); + } + return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue()); + } + constexpr Unit_T operator-(const Unit_T other) const { + if (this->IsPlusInfinity() || other.IsMinusInfinity()) { + RTC_DCHECK(!this->IsMinusInfinity()); + RTC_DCHECK(!other.IsPlusInfinity()); + return this->PlusInfinity(); + } else if (this->IsMinusInfinity() || other.IsPlusInfinity()) { + RTC_DCHECK(!this->IsPlusInfinity()); + RTC_DCHECK(!other.IsMinusInfinity()); + return this->MinusInfinity(); + } + return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue()); + } + constexpr Unit_T& operator+=(const Unit_T other) { + *this = *this + other; + return this->AsSubClassRef(); + } + constexpr Unit_T& operator-=(const Unit_T other) { + *this = *this - other; + return this->AsSubClassRef(); + } + constexpr double operator/(const Unit_T other) const { + return UnitBase<Unit_T>::template ToValue<double>() / + other.template ToValue<double>(); + } + template <typename T, + typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr> + constexpr Unit_T operator/(T scalar) const { + return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar)); + } + template <typename T, + typename std::enable_if_t<std::is_integral_v<T>>* = nullptr> + constexpr Unit_T operator/(T scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar); + } + constexpr Unit_T operator*(double scalar) const { + return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar)); + } + constexpr Unit_T operator*(int64_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + constexpr Unit_T operator*(int32_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + constexpr Unit_T operator*(size_t scalar) const { + return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); + } + + protected: + using UnitBase<Unit_T>::UnitBase; +}; + +template <class Unit_T> +inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} +template <class Unit_T> +inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) { + return other * scalar; +} + +template <class Unit_T> +inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) { + if (other.IsPlusInfinity()) + return UnitBase<Unit_T>::MinusInfinity(); + if (other.IsMinusInfinity()) + return UnitBase<Unit_T>::PlusInfinity(); + return -1 * other; +} + +} // namespace rtc_units_impl + +} // namespace webrtc + +#endif // RTC_BASE_UNITS_UNIT_BASE_H_ diff --git a/third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build b/third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build new file mode 100644 index 0000000000..bb68c4ea3c --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base_gn/moz.build @@ -0,0 +1,209 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + + + ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ### + ### DO NOT edit it by hand. ### + +COMPILE_FLAGS["OS_INCLUDES"] = [] +AllowCompilerWarnings() + +DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0" +DEFINES["WEBRTC_LIBRARY_IMPL"] = True +DEFINES["WEBRTC_MOZILLA_BUILD"] = True +DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0" +DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0" + +FINAL_LIBRARY = "webrtc" + + +LOCAL_INCLUDES += [ + "!/ipc/ipdl/_ipdlheaders", + "!/third_party/libwebrtc/gen", + "/ipc/chromium/src", + "/third_party/libwebrtc/", + "/third_party/libwebrtc/third_party/abseil-cpp/", + "/tools/profiler/public" +] + +if not CONFIG["MOZ_DEBUG"]: + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0" + DEFINES["NDEBUG"] = True + DEFINES["NVALGRIND"] = True + +if CONFIG["MOZ_DEBUG"] == "1": + + DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1" + +if CONFIG["OS_TARGET"] == "Android": + + DEFINES["ANDROID"] = True + DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1" + DEFINES["HAVE_SYS_UIO_H"] = True + DEFINES["WEBRTC_ANDROID"] = True + DEFINES["WEBRTC_ANDROID_OPENSLES"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_GNU_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + + OS_LIBS += [ + "log" + ] + +if CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["WEBRTC_MAC"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True + DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0" + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_AURA"] = "1" + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_NSS_CERTS"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_UDEV"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_LINUX"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["USE_GLIB"] = "1" + DEFINES["USE_OZONE"] = "1" + DEFINES["USE_X11"] = "1" + DEFINES["WEBRTC_BSD"] = True + DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True + DEFINES["WEBRTC_POSIX"] = True + DEFINES["_FILE_OFFSET_BITS"] = "64" + DEFINES["_LARGEFILE64_SOURCE"] = True + DEFINES["_LARGEFILE_SOURCE"] = True + DEFINES["__STDC_CONSTANT_MACROS"] = True + DEFINES["__STDC_FORMAT_MACROS"] = True + +if CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True + DEFINES["NOMINMAX"] = True + DEFINES["NTDDI_VERSION"] = "0x0A000000" + DEFINES["PSAPI_VERSION"] = "2" + DEFINES["RTC_ENABLE_WIN_WGC"] = True + DEFINES["UNICODE"] = True + DEFINES["USE_AURA"] = "1" + DEFINES["WEBRTC_WIN"] = True + DEFINES["WIN32"] = True + DEFINES["WIN32_LEAN_AND_MEAN"] = True + DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP" + DEFINES["WINVER"] = "0x0A00" + DEFINES["_ATL_NO_OPENGL"] = True + DEFINES["_CRT_RAND_S"] = True + DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True + DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True + DEFINES["_HAS_EXCEPTIONS"] = "0" + DEFINES["_HAS_NODISCARD"] = True + DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True + DEFINES["_SECURE_ATL"] = True + DEFINES["_UNICODE"] = True + DEFINES["_WIN32_WINNT"] = "0x0A00" + DEFINES["_WINDOWS"] = True + DEFINES["__STD_C"] = True + +if CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "arm": + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["TARGET_CPU"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["TARGET_CPU"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD": + + DEFINES["_DEBUG"] = True + +if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT": + + DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0" + +if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["USE_X11"] = "1" + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86": + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64": + + DEFINES["_GNU_SOURCE"] = True + +Library("unit_base_gn") diff --git a/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc b/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc new file mode 100644 index 0000000000..258d7d1268 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base_unittest.cc @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/units/unit_base.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace { +class TestUnit final : public rtc_units_impl::RelativeUnit<TestUnit> { + public: + TestUnit() = delete; + + using UnitBase::FromValue; + using UnitBase::ToValue; + using UnitBase::ToValueOr; + + template <typename T> + static constexpr TestUnit FromKilo(T kilo) { + return FromFraction(1000, kilo); + } + template <typename T = int64_t> + T ToKilo() const { + return UnitBase::ToFraction<1000, T>(); + } + constexpr int64_t ToKiloOr(int64_t fallback) const { + return UnitBase::ToFractionOr<1000>(fallback); + } + template <typename T> + constexpr T ToMilli() const { + return UnitBase::ToMultiple<1000, T>(); + } + + private: + friend class rtc_units_impl::UnitBase<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) { + constexpr int64_t kValue = -12345; + constexpr TestUnit kTestUnitZero = TestUnit::Zero(); + constexpr TestUnit kTestUnitPlusInf = TestUnit::PlusInfinity(); + constexpr TestUnit kTestUnitMinusInf = TestUnit::MinusInfinity(); + static_assert(kTestUnitZero.IsZero(), ""); + static_assert(kTestUnitPlusInf.IsPlusInfinity(), ""); + static_assert(kTestUnitMinusInf.IsMinusInfinity(), ""); + static_assert(kTestUnitPlusInf.ToKiloOr(-1) == -1, ""); + + static_assert(kTestUnitPlusInf > kTestUnitZero, ""); + + constexpr TestUnit kTestUnitKilo = TestUnit::FromKilo(kValue); + constexpr TestUnit kTestUnitValue = TestUnit::FromValue(kValue); + + static_assert(kTestUnitKilo.ToKiloOr(0) == kValue, ""); + static_assert(kTestUnitValue.ToValueOr(0) == kValue, ""); + static_assert(TestUnitAddKilo(kTestUnitValue, 2).ToValue() == kValue + 2000, + ""); + static_assert(TestUnit::FromValue(500) / 2 == TestUnit::FromValue(250)); +} + +TEST(UnitBaseTest, GetBackSameValues) { + const int64_t kValue = 499; + for (int sign = -1; sign <= 1; ++sign) { + int64_t value = kValue * sign; + EXPECT_EQ(TestUnit::FromKilo(value).ToKilo(), value); + EXPECT_EQ(TestUnit::FromValue(value).ToValue<int64_t>(), value); + } + EXPECT_EQ(TestUnit::Zero().ToValue<int64_t>(), 0); +} + +TEST(UnitBaseTest, GetDifferentPrefix) { + const int64_t kValue = 3000000; + EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo(), kValue / 1000); + EXPECT_EQ(TestUnit::FromKilo(kValue).ToValue<int64_t>(), kValue * 1000); +} + +TEST(UnitBaseTest, IdentityChecks) { + const int64_t kValue = 3000; + EXPECT_TRUE(TestUnit::Zero().IsZero()); + EXPECT_FALSE(TestUnit::FromKilo(kValue).IsZero()); + + EXPECT_TRUE(TestUnit::PlusInfinity().IsInfinite()); + EXPECT_TRUE(TestUnit::MinusInfinity().IsInfinite()); + EXPECT_FALSE(TestUnit::Zero().IsInfinite()); + EXPECT_FALSE(TestUnit::FromKilo(-kValue).IsInfinite()); + EXPECT_FALSE(TestUnit::FromKilo(kValue).IsInfinite()); + + EXPECT_FALSE(TestUnit::PlusInfinity().IsFinite()); + EXPECT_FALSE(TestUnit::MinusInfinity().IsFinite()); + EXPECT_TRUE(TestUnit::FromKilo(-kValue).IsFinite()); + EXPECT_TRUE(TestUnit::FromKilo(kValue).IsFinite()); + EXPECT_TRUE(TestUnit::Zero().IsFinite()); + + EXPECT_TRUE(TestUnit::PlusInfinity().IsPlusInfinity()); + EXPECT_FALSE(TestUnit::MinusInfinity().IsPlusInfinity()); + + EXPECT_TRUE(TestUnit::MinusInfinity().IsMinusInfinity()); + EXPECT_FALSE(TestUnit::PlusInfinity().IsMinusInfinity()); +} + +TEST(UnitBaseTest, ComparisonOperators) { + const int64_t kSmall = 450; + const int64_t kLarge = 451; + const TestUnit small = TestUnit::FromKilo(kSmall); + const TestUnit large = TestUnit::FromKilo(kLarge); + + EXPECT_EQ(TestUnit::Zero(), TestUnit::FromKilo(0)); + EXPECT_EQ(TestUnit::PlusInfinity(), TestUnit::PlusInfinity()); + EXPECT_EQ(small, TestUnit::FromKilo(kSmall)); + EXPECT_LE(small, TestUnit::FromKilo(kSmall)); + EXPECT_GE(small, TestUnit::FromKilo(kSmall)); + EXPECT_NE(small, TestUnit::FromKilo(kLarge)); + EXPECT_LE(small, TestUnit::FromKilo(kLarge)); + EXPECT_LT(small, TestUnit::FromKilo(kLarge)); + EXPECT_GE(large, TestUnit::FromKilo(kSmall)); + EXPECT_GT(large, TestUnit::FromKilo(kSmall)); + EXPECT_LT(TestUnit::Zero(), small); + EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); + EXPECT_GT(TestUnit::Zero(), TestUnit::FromKilo(-kSmall)); + + EXPECT_GT(TestUnit::PlusInfinity(), large); + EXPECT_LT(TestUnit::MinusInfinity(), TestUnit::Zero()); +} + +TEST(UnitBaseTest, Clamping) { + const TestUnit upper = TestUnit::FromKilo(800); + const TestUnit lower = TestUnit::FromKilo(100); + const TestUnit under = TestUnit::FromKilo(100); + const TestUnit inside = TestUnit::FromKilo(500); + const TestUnit over = TestUnit::FromKilo(1000); + EXPECT_EQ(under.Clamped(lower, upper), lower); + EXPECT_EQ(inside.Clamped(lower, upper), inside); + EXPECT_EQ(over.Clamped(lower, upper), upper); + + TestUnit mutable_delta = lower; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, lower); + mutable_delta = inside; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, inside); + mutable_delta = over; + mutable_delta.Clamp(lower, upper); + EXPECT_EQ(mutable_delta, upper); +} + +TEST(UnitBaseTest, CanBeInititializedFromLargeInt) { + const int kMaxInt = std::numeric_limits<int>::max(); + EXPECT_EQ(TestUnit::FromKilo(kMaxInt).ToValue<int64_t>(), + static_cast<int64_t>(kMaxInt) * 1000); +} + +TEST(UnitBaseTest, ConvertsToAndFromDouble) { + const int64_t kValue = 17017; + const double kMilliDouble = kValue * 1e3; + const double kValueDouble = kValue; + const double kKiloDouble = kValue * 1e-3; + + EXPECT_EQ(TestUnit::FromValue(kValue).ToKilo<double>(), kKiloDouble); + EXPECT_EQ(TestUnit::FromKilo(kKiloDouble).ToValue<int64_t>(), kValue); + + EXPECT_EQ(TestUnit::FromValue(kValue).ToValue<double>(), kValueDouble); + EXPECT_EQ(TestUnit::FromValue(kValueDouble).ToValue<int64_t>(), kValue); + + EXPECT_NEAR(TestUnit::FromValue(kValue).ToMilli<double>(), kMilliDouble, 1); + + const double kPlusInfinity = std::numeric_limits<double>::infinity(); + const double kMinusInfinity = -kPlusInfinity; + + EXPECT_EQ(TestUnit::PlusInfinity().ToKilo<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToKilo<double>(), kMinusInfinity); + EXPECT_EQ(TestUnit::PlusInfinity().ToValue<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToValue<double>(), kMinusInfinity); + EXPECT_EQ(TestUnit::PlusInfinity().ToMilli<double>(), kPlusInfinity); + EXPECT_EQ(TestUnit::MinusInfinity().ToMilli<double>(), kMinusInfinity); + + EXPECT_TRUE(TestUnit::FromKilo(kPlusInfinity).IsPlusInfinity()); + EXPECT_TRUE(TestUnit::FromKilo(kMinusInfinity).IsMinusInfinity()); + EXPECT_TRUE(TestUnit::FromValue(kPlusInfinity).IsPlusInfinity()); + EXPECT_TRUE(TestUnit::FromValue(kMinusInfinity).IsMinusInfinity()); +} + +TEST(UnitBaseTest, MathOperations) { + const int64_t kValueA = 267; + const int64_t kValueB = 450; + const TestUnit delta_a = TestUnit::FromKilo(kValueA); + const TestUnit delta_b = TestUnit::FromKilo(kValueB); + EXPECT_EQ((delta_a + delta_b).ToKilo(), kValueA + kValueB); + EXPECT_EQ((delta_a - delta_b).ToKilo(), kValueA - kValueB); + + const int32_t kInt32Value = 123; + const double kFloatValue = 123.0; + EXPECT_EQ((TestUnit::FromValue(kValueA) * kValueB).ToValue<int64_t>(), + kValueA * kValueB); + EXPECT_EQ((TestUnit::FromValue(kValueA) * kInt32Value).ToValue<int64_t>(), + kValueA * kInt32Value); + EXPECT_EQ((TestUnit::FromValue(kValueA) * kFloatValue).ToValue<int64_t>(), + kValueA * kFloatValue); + + EXPECT_EQ((delta_b / 10).ToKilo(), kValueB / 10); + EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA); + + TestUnit mutable_delta = TestUnit::FromKilo(kValueA); + mutable_delta += TestUnit::FromKilo(kValueB); + EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA + kValueB)); + mutable_delta -= TestUnit::FromKilo(kValueB); + EXPECT_EQ(mutable_delta, TestUnit::FromKilo(kValueA)); + + // Division by an int rounds towards zero to follow regular int division. + EXPECT_EQ(TestUnit::FromValue(789) / 10, TestUnit::FromValue(78)); + EXPECT_EQ(TestUnit::FromValue(-789) / 10, TestUnit::FromValue(-78)); +} + +TEST(UnitBaseTest, InfinityOperations) { + const int64_t kValue = 267; + const TestUnit finite = TestUnit::FromKilo(kValue); + EXPECT_TRUE((TestUnit::PlusInfinity() + finite).IsPlusInfinity()); + EXPECT_TRUE((TestUnit::PlusInfinity() - finite).IsPlusInfinity()); + EXPECT_TRUE((finite + TestUnit::PlusInfinity()).IsPlusInfinity()); + EXPECT_TRUE((finite - TestUnit::MinusInfinity()).IsPlusInfinity()); + + EXPECT_TRUE((TestUnit::MinusInfinity() + finite).IsMinusInfinity()); + EXPECT_TRUE((TestUnit::MinusInfinity() - finite).IsMinusInfinity()); + EXPECT_TRUE((finite + TestUnit::MinusInfinity()).IsMinusInfinity()); + EXPECT_TRUE((finite - TestUnit::PlusInfinity()).IsMinusInfinity()); +} + +TEST(UnitBaseTest, UnaryMinus) { + const int64_t kValue = 1337; + const TestUnit unit = TestUnit::FromValue(kValue); + EXPECT_EQ(-unit.ToValue(), -kValue); + + // Check infinity. + EXPECT_EQ(-TestUnit::PlusInfinity(), TestUnit::MinusInfinity()); + EXPECT_EQ(-TestUnit::MinusInfinity(), TestUnit::PlusInfinity()); +} + +} // namespace test +} // namespace webrtc |