diff options
Diffstat (limited to 'third_party/libwebrtc/rtc_base/units/unit_base.h')
-rw-r--r-- | third_party/libwebrtc/rtc_base/units/unit_base.h | 326 |
1 files changed, 326 insertions, 0 deletions
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..e0a926fb8d --- /dev/null +++ b/third_party/libwebrtc/rtc_base/units/unit_base.h @@ -0,0 +1,326 @@ +/* + * 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/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()); + if (Unit_T::one_sided) { + return rtc::dchecked_cast<T>( + DivRoundPositiveToNearest(value_, Denominator)); + } else { + return rtc::dchecked_cast<T>(DivRoundToNearest(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() ? Unit_T::one_sided + ? DivRoundPositiveToNearest(value_, Denominator) + : DivRoundToNearest(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); + } + // Assumes that n >= 0 and d > 0. + static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) { + return (n + d / 2) / d; + } + // Assumes that d > 0. + static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) { + return (n + (n >= 0 ? d / 2 : -d / 2)) / d; + } + + 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_ |