1*d9f75844SAndroid Build Coastguard Worker /* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2018 The WebRTC project authors. All Rights Reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker #ifndef RTC_BASE_UNITS_UNIT_BASE_H_ 11*d9f75844SAndroid Build Coastguard Worker #define RTC_BASE_UNITS_UNIT_BASE_H_ 12*d9f75844SAndroid Build Coastguard Worker 13*d9f75844SAndroid Build Coastguard Worker #include <stdint.h> 14*d9f75844SAndroid Build Coastguard Worker 15*d9f75844SAndroid Build Coastguard Worker #include <algorithm> 16*d9f75844SAndroid Build Coastguard Worker #include <cmath> 17*d9f75844SAndroid Build Coastguard Worker #include <limits> 18*d9f75844SAndroid Build Coastguard Worker #include <type_traits> 19*d9f75844SAndroid Build Coastguard Worker 20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h" 21*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h" 22*d9f75844SAndroid Build Coastguard Worker 23*d9f75844SAndroid Build Coastguard Worker namespace webrtc { 24*d9f75844SAndroid Build Coastguard Worker namespace rtc_units_impl { 25*d9f75844SAndroid Build Coastguard Worker 26*d9f75844SAndroid Build Coastguard Worker // UnitBase is a base class for implementing custom value types with a specific 27*d9f75844SAndroid Build Coastguard Worker // unit. It provides type safety and commonly useful operations. The underlying 28*d9f75844SAndroid Build Coastguard Worker // storage is always an int64_t, it's up to the unit implementation to choose 29*d9f75844SAndroid Build Coastguard Worker // what scale it represents. 30*d9f75844SAndroid Build Coastguard Worker // 31*d9f75844SAndroid Build Coastguard Worker // It's used like: 32*d9f75844SAndroid Build Coastguard Worker // class MyUnit: public UnitBase<MyUnit> {...}; 33*d9f75844SAndroid Build Coastguard Worker // 34*d9f75844SAndroid Build Coastguard Worker // Unit_T is the subclass representing the specific unit. 35*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 36*d9f75844SAndroid Build Coastguard Worker class UnitBase { 37*d9f75844SAndroid Build Coastguard Worker public: 38*d9f75844SAndroid Build Coastguard Worker UnitBase() = delete; Zero()39*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T Zero() { return Unit_T(0); } PlusInfinity()40*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T PlusInfinity() { return Unit_T(PlusInfinityVal()); } MinusInfinity()41*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T MinusInfinity() { return Unit_T(MinusInfinityVal()); } 42*d9f75844SAndroid Build Coastguard Worker IsZero()43*d9f75844SAndroid Build Coastguard Worker constexpr bool IsZero() const { return value_ == 0; } IsFinite()44*d9f75844SAndroid Build Coastguard Worker constexpr bool IsFinite() const { return !IsInfinite(); } IsInfinite()45*d9f75844SAndroid Build Coastguard Worker constexpr bool IsInfinite() const { 46*d9f75844SAndroid Build Coastguard Worker return value_ == PlusInfinityVal() || value_ == MinusInfinityVal(); 47*d9f75844SAndroid Build Coastguard Worker } IsPlusInfinity()48*d9f75844SAndroid Build Coastguard Worker constexpr bool IsPlusInfinity() const { return value_ == PlusInfinityVal(); } IsMinusInfinity()49*d9f75844SAndroid Build Coastguard Worker constexpr bool IsMinusInfinity() const { 50*d9f75844SAndroid Build Coastguard Worker return value_ == MinusInfinityVal(); 51*d9f75844SAndroid Build Coastguard Worker } 52*d9f75844SAndroid Build Coastguard Worker 53*d9f75844SAndroid Build Coastguard Worker constexpr bool operator==(const UnitBase<Unit_T>& other) const { 54*d9f75844SAndroid Build Coastguard Worker return value_ == other.value_; 55*d9f75844SAndroid Build Coastguard Worker } 56*d9f75844SAndroid Build Coastguard Worker constexpr bool operator!=(const UnitBase<Unit_T>& other) const { 57*d9f75844SAndroid Build Coastguard Worker return value_ != other.value_; 58*d9f75844SAndroid Build Coastguard Worker } 59*d9f75844SAndroid Build Coastguard Worker constexpr bool operator<=(const UnitBase<Unit_T>& other) const { 60*d9f75844SAndroid Build Coastguard Worker return value_ <= other.value_; 61*d9f75844SAndroid Build Coastguard Worker } 62*d9f75844SAndroid Build Coastguard Worker constexpr bool operator>=(const UnitBase<Unit_T>& other) const { 63*d9f75844SAndroid Build Coastguard Worker return value_ >= other.value_; 64*d9f75844SAndroid Build Coastguard Worker } 65*d9f75844SAndroid Build Coastguard Worker constexpr bool operator>(const UnitBase<Unit_T>& other) const { 66*d9f75844SAndroid Build Coastguard Worker return value_ > other.value_; 67*d9f75844SAndroid Build Coastguard Worker } 68*d9f75844SAndroid Build Coastguard Worker constexpr bool operator<(const UnitBase<Unit_T>& other) const { 69*d9f75844SAndroid Build Coastguard Worker return value_ < other.value_; 70*d9f75844SAndroid Build Coastguard Worker } RoundTo(const Unit_T & resolution)71*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T RoundTo(const Unit_T& resolution) const { 72*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsFinite()); 73*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(resolution.IsFinite()); 74*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(resolution.value_, 0); 75*d9f75844SAndroid Build Coastguard Worker return Unit_T((value_ + resolution.value_ / 2) / resolution.value_) * 76*d9f75844SAndroid Build Coastguard Worker resolution.value_; 77*d9f75844SAndroid Build Coastguard Worker } RoundUpTo(const Unit_T & resolution)78*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T RoundUpTo(const Unit_T& resolution) const { 79*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsFinite()); 80*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(resolution.IsFinite()); 81*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(resolution.value_, 0); 82*d9f75844SAndroid Build Coastguard Worker return Unit_T((value_ + resolution.value_ - 1) / resolution.value_) * 83*d9f75844SAndroid Build Coastguard Worker resolution.value_; 84*d9f75844SAndroid Build Coastguard Worker } RoundDownTo(const Unit_T & resolution)85*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T RoundDownTo(const Unit_T& resolution) const { 86*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsFinite()); 87*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(resolution.IsFinite()); 88*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(resolution.value_, 0); 89*d9f75844SAndroid Build Coastguard Worker return Unit_T(value_ / resolution.value_) * resolution.value_; 90*d9f75844SAndroid Build Coastguard Worker } 91*d9f75844SAndroid Build Coastguard Worker 92*d9f75844SAndroid Build Coastguard Worker protected: 93*d9f75844SAndroid Build Coastguard Worker template < 94*d9f75844SAndroid Build Coastguard Worker typename T, 95*d9f75844SAndroid Build Coastguard Worker typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> FromValue(T value)96*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T FromValue(T value) { 97*d9f75844SAndroid Build Coastguard Worker if (Unit_T::one_sided) 98*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(value, 0); 99*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(value, MinusInfinityVal()); 100*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_LT(value, PlusInfinityVal()); 101*d9f75844SAndroid Build Coastguard Worker return Unit_T(rtc::dchecked_cast<int64_t>(value)); 102*d9f75844SAndroid Build Coastguard Worker } 103*d9f75844SAndroid Build Coastguard Worker template <typename T, 104*d9f75844SAndroid Build Coastguard Worker typename std::enable_if<std::is_floating_point<T>::value>::type* = 105*d9f75844SAndroid Build Coastguard Worker nullptr> FromValue(T value)106*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T FromValue(T value) { 107*d9f75844SAndroid Build Coastguard Worker if (value == std::numeric_limits<T>::infinity()) { 108*d9f75844SAndroid Build Coastguard Worker return PlusInfinity(); 109*d9f75844SAndroid Build Coastguard Worker } else if (value == -std::numeric_limits<T>::infinity()) { 110*d9f75844SAndroid Build Coastguard Worker return MinusInfinity(); 111*d9f75844SAndroid Build Coastguard Worker } else { 112*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!std::isnan(value)); 113*d9f75844SAndroid Build Coastguard Worker return FromValue(rtc::dchecked_cast<int64_t>(value)); 114*d9f75844SAndroid Build Coastguard Worker } 115*d9f75844SAndroid Build Coastguard Worker } 116*d9f75844SAndroid Build Coastguard Worker 117*d9f75844SAndroid Build Coastguard Worker template < 118*d9f75844SAndroid Build Coastguard Worker typename T, 119*d9f75844SAndroid Build Coastguard Worker typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> FromFraction(int64_t denominator,T value)120*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T FromFraction(int64_t denominator, T value) { 121*d9f75844SAndroid Build Coastguard Worker if (Unit_T::one_sided) 122*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(value, 0); 123*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GT(value, MinusInfinityVal() / denominator); 124*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_LT(value, PlusInfinityVal() / denominator); 125*d9f75844SAndroid Build Coastguard Worker return Unit_T(rtc::dchecked_cast<int64_t>(value * denominator)); 126*d9f75844SAndroid Build Coastguard Worker } 127*d9f75844SAndroid Build Coastguard Worker template <typename T, 128*d9f75844SAndroid Build Coastguard Worker typename std::enable_if<std::is_floating_point<T>::value>::type* = 129*d9f75844SAndroid Build Coastguard Worker nullptr> FromFraction(int64_t denominator,T value)130*d9f75844SAndroid Build Coastguard Worker static constexpr Unit_T FromFraction(int64_t denominator, T value) { 131*d9f75844SAndroid Build Coastguard Worker return FromValue(value * denominator); 132*d9f75844SAndroid Build Coastguard Worker } 133*d9f75844SAndroid Build Coastguard Worker 134*d9f75844SAndroid Build Coastguard Worker template <typename T = int64_t> 135*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_integral<T>::value, T>::type ToValue()136*d9f75844SAndroid Build Coastguard Worker ToValue() const { 137*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsFinite()); 138*d9f75844SAndroid Build Coastguard Worker return rtc::dchecked_cast<T>(value_); 139*d9f75844SAndroid Build Coastguard Worker } 140*d9f75844SAndroid Build Coastguard Worker template <typename T> 141*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type ToValue()142*d9f75844SAndroid Build Coastguard Worker ToValue() const { 143*d9f75844SAndroid Build Coastguard Worker return IsPlusInfinity() 144*d9f75844SAndroid Build Coastguard Worker ? std::numeric_limits<T>::infinity() 145*d9f75844SAndroid Build Coastguard Worker : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() 146*d9f75844SAndroid Build Coastguard Worker : value_; 147*d9f75844SAndroid Build Coastguard Worker } 148*d9f75844SAndroid Build Coastguard Worker template <typename T> ToValueOr(T fallback_value)149*d9f75844SAndroid Build Coastguard Worker constexpr T ToValueOr(T fallback_value) const { 150*d9f75844SAndroid Build Coastguard Worker return IsFinite() ? value_ : fallback_value; 151*d9f75844SAndroid Build Coastguard Worker } 152*d9f75844SAndroid Build Coastguard Worker 153*d9f75844SAndroid Build Coastguard Worker template <int64_t Denominator, typename T = int64_t> 154*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_integral<T>::value, T>::type ToFraction()155*d9f75844SAndroid Build Coastguard Worker ToFraction() const { 156*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsFinite()); 157*d9f75844SAndroid Build Coastguard Worker if (Unit_T::one_sided) { 158*d9f75844SAndroid Build Coastguard Worker return rtc::dchecked_cast<T>( 159*d9f75844SAndroid Build Coastguard Worker DivRoundPositiveToNearest(value_, Denominator)); 160*d9f75844SAndroid Build Coastguard Worker } else { 161*d9f75844SAndroid Build Coastguard Worker return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator)); 162*d9f75844SAndroid Build Coastguard Worker } 163*d9f75844SAndroid Build Coastguard Worker } 164*d9f75844SAndroid Build Coastguard Worker template <int64_t Denominator, typename T> 165*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type ToFraction()166*d9f75844SAndroid Build Coastguard Worker ToFraction() const { 167*d9f75844SAndroid Build Coastguard Worker return ToValue<T>() * (1 / static_cast<T>(Denominator)); 168*d9f75844SAndroid Build Coastguard Worker } 169*d9f75844SAndroid Build Coastguard Worker 170*d9f75844SAndroid Build Coastguard Worker template <int64_t Denominator> ToFractionOr(int64_t fallback_value)171*d9f75844SAndroid Build Coastguard Worker constexpr int64_t ToFractionOr(int64_t fallback_value) const { 172*d9f75844SAndroid Build Coastguard Worker return IsFinite() ? Unit_T::one_sided 173*d9f75844SAndroid Build Coastguard Worker ? DivRoundPositiveToNearest(value_, Denominator) 174*d9f75844SAndroid Build Coastguard Worker : DivRoundToNearest(value_, Denominator) 175*d9f75844SAndroid Build Coastguard Worker : fallback_value; 176*d9f75844SAndroid Build Coastguard Worker } 177*d9f75844SAndroid Build Coastguard Worker 178*d9f75844SAndroid Build Coastguard Worker template <int64_t Factor, typename T = int64_t> 179*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_integral<T>::value, T>::type ToMultiple()180*d9f75844SAndroid Build Coastguard Worker ToMultiple() const { 181*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(ToValue(), std::numeric_limits<T>::min() / Factor); 182*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_LE(ToValue(), std::numeric_limits<T>::max() / Factor); 183*d9f75844SAndroid Build Coastguard Worker return rtc::dchecked_cast<T>(ToValue() * Factor); 184*d9f75844SAndroid Build Coastguard Worker } 185*d9f75844SAndroid Build Coastguard Worker template <int64_t Factor, typename T> 186*d9f75844SAndroid Build Coastguard Worker constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type ToMultiple()187*d9f75844SAndroid Build Coastguard Worker ToMultiple() const { 188*d9f75844SAndroid Build Coastguard Worker return ToValue<T>() * Factor; 189*d9f75844SAndroid Build Coastguard Worker } 190*d9f75844SAndroid Build Coastguard Worker UnitBase(int64_t value)191*d9f75844SAndroid Build Coastguard Worker explicit constexpr UnitBase(int64_t value) : value_(value) {} 192*d9f75844SAndroid Build Coastguard Worker 193*d9f75844SAndroid Build Coastguard Worker private: 194*d9f75844SAndroid Build Coastguard Worker template <class RelativeUnit_T> 195*d9f75844SAndroid Build Coastguard Worker friend class RelativeUnit; 196*d9f75844SAndroid Build Coastguard Worker PlusInfinityVal()197*d9f75844SAndroid Build Coastguard Worker static inline constexpr int64_t PlusInfinityVal() { 198*d9f75844SAndroid Build Coastguard Worker return std::numeric_limits<int64_t>::max(); 199*d9f75844SAndroid Build Coastguard Worker } MinusInfinityVal()200*d9f75844SAndroid Build Coastguard Worker static inline constexpr int64_t MinusInfinityVal() { 201*d9f75844SAndroid Build Coastguard Worker return std::numeric_limits<int64_t>::min(); 202*d9f75844SAndroid Build Coastguard Worker } 203*d9f75844SAndroid Build Coastguard Worker AsSubClassRef()204*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T& AsSubClassRef() { return static_cast<Unit_T&>(*this); } AsSubClassRef()205*d9f75844SAndroid Build Coastguard Worker constexpr const Unit_T& AsSubClassRef() const { 206*d9f75844SAndroid Build Coastguard Worker return static_cast<const Unit_T&>(*this); 207*d9f75844SAndroid Build Coastguard Worker } 208*d9f75844SAndroid Build Coastguard Worker // Assumes that n >= 0 and d > 0. DivRoundPositiveToNearest(int64_t n,int64_t d)209*d9f75844SAndroid Build Coastguard Worker static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) { 210*d9f75844SAndroid Build Coastguard Worker return (n + d / 2) / d; 211*d9f75844SAndroid Build Coastguard Worker } 212*d9f75844SAndroid Build Coastguard Worker // Assumes that d > 0. DivRoundToNearest(int64_t n,int64_t d)213*d9f75844SAndroid Build Coastguard Worker static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) { 214*d9f75844SAndroid Build Coastguard Worker return (n + (n >= 0 ? d / 2 : -d / 2)) / d; 215*d9f75844SAndroid Build Coastguard Worker } 216*d9f75844SAndroid Build Coastguard Worker 217*d9f75844SAndroid Build Coastguard Worker int64_t value_; 218*d9f75844SAndroid Build Coastguard Worker }; 219*d9f75844SAndroid Build Coastguard Worker 220*d9f75844SAndroid Build Coastguard Worker // Extends UnitBase to provide operations for relative units, that is, units 221*d9f75844SAndroid Build Coastguard Worker // that have a meaningful relation between values such that a += b is a 222*d9f75844SAndroid Build Coastguard Worker // sensible thing to do. For a,b <- same unit. 223*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 224*d9f75844SAndroid Build Coastguard Worker class RelativeUnit : public UnitBase<Unit_T> { 225*d9f75844SAndroid Build Coastguard Worker public: Clamped(Unit_T min_value,Unit_T max_value)226*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const { 227*d9f75844SAndroid Build Coastguard Worker return std::max(min_value, 228*d9f75844SAndroid Build Coastguard Worker std::min(UnitBase<Unit_T>::AsSubClassRef(), max_value)); 229*d9f75844SAndroid Build Coastguard Worker } Clamp(Unit_T min_value,Unit_T max_value)230*d9f75844SAndroid Build Coastguard Worker constexpr void Clamp(Unit_T min_value, Unit_T max_value) { 231*d9f75844SAndroid Build Coastguard Worker *this = Clamped(min_value, max_value); 232*d9f75844SAndroid Build Coastguard Worker } 233*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator+(const Unit_T other) const { 234*d9f75844SAndroid Build Coastguard Worker if (this->IsPlusInfinity() || other.IsPlusInfinity()) { 235*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!this->IsMinusInfinity()); 236*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!other.IsMinusInfinity()); 237*d9f75844SAndroid Build Coastguard Worker return this->PlusInfinity(); 238*d9f75844SAndroid Build Coastguard Worker } else if (this->IsMinusInfinity() || other.IsMinusInfinity()) { 239*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!this->IsPlusInfinity()); 240*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!other.IsPlusInfinity()); 241*d9f75844SAndroid Build Coastguard Worker return this->MinusInfinity(); 242*d9f75844SAndroid Build Coastguard Worker } 243*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue()); 244*d9f75844SAndroid Build Coastguard Worker } 245*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator-(const Unit_T other) const { 246*d9f75844SAndroid Build Coastguard Worker if (this->IsPlusInfinity() || other.IsMinusInfinity()) { 247*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!this->IsMinusInfinity()); 248*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!other.IsPlusInfinity()); 249*d9f75844SAndroid Build Coastguard Worker return this->PlusInfinity(); 250*d9f75844SAndroid Build Coastguard Worker } else if (this->IsMinusInfinity() || other.IsPlusInfinity()) { 251*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!this->IsPlusInfinity()); 252*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!other.IsMinusInfinity()); 253*d9f75844SAndroid Build Coastguard Worker return this->MinusInfinity(); 254*d9f75844SAndroid Build Coastguard Worker } 255*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue()); 256*d9f75844SAndroid Build Coastguard Worker } 257*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T& operator+=(const Unit_T other) { 258*d9f75844SAndroid Build Coastguard Worker *this = *this + other; 259*d9f75844SAndroid Build Coastguard Worker return this->AsSubClassRef(); 260*d9f75844SAndroid Build Coastguard Worker } 261*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T& operator-=(const Unit_T other) { 262*d9f75844SAndroid Build Coastguard Worker *this = *this - other; 263*d9f75844SAndroid Build Coastguard Worker return this->AsSubClassRef(); 264*d9f75844SAndroid Build Coastguard Worker } 265*d9f75844SAndroid Build Coastguard Worker constexpr double operator/(const Unit_T other) const { 266*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::template ToValue<double>() / 267*d9f75844SAndroid Build Coastguard Worker other.template ToValue<double>(); 268*d9f75844SAndroid Build Coastguard Worker } 269*d9f75844SAndroid Build Coastguard Worker template <typename T, 270*d9f75844SAndroid Build Coastguard Worker typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr> 271*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator/(T scalar) const { 272*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() / scalar)); 273*d9f75844SAndroid Build Coastguard Worker } 274*d9f75844SAndroid Build Coastguard Worker template <typename T, 275*d9f75844SAndroid Build Coastguard Worker typename std::enable_if_t<std::is_integral_v<T>>* = nullptr> 276*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator/(T scalar) const { 277*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() / scalar); 278*d9f75844SAndroid Build Coastguard Worker } 279*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator*(double scalar) const { 280*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(std::llround(this->ToValue() * scalar)); 281*d9f75844SAndroid Build Coastguard Worker } 282*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator*(int64_t scalar) const { 283*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); 284*d9f75844SAndroid Build Coastguard Worker } 285*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator*(int32_t scalar) const { 286*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); 287*d9f75844SAndroid Build Coastguard Worker } 288*d9f75844SAndroid Build Coastguard Worker constexpr Unit_T operator*(size_t scalar) const { 289*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar); 290*d9f75844SAndroid Build Coastguard Worker } 291*d9f75844SAndroid Build Coastguard Worker 292*d9f75844SAndroid Build Coastguard Worker protected: 293*d9f75844SAndroid Build Coastguard Worker using UnitBase<Unit_T>::UnitBase; 294*d9f75844SAndroid Build Coastguard Worker }; 295*d9f75844SAndroid Build Coastguard Worker 296*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 297*d9f75844SAndroid Build Coastguard Worker inline constexpr Unit_T operator*(double scalar, RelativeUnit<Unit_T> other) { 298*d9f75844SAndroid Build Coastguard Worker return other * scalar; 299*d9f75844SAndroid Build Coastguard Worker } 300*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 301*d9f75844SAndroid Build Coastguard Worker inline constexpr Unit_T operator*(int64_t scalar, RelativeUnit<Unit_T> other) { 302*d9f75844SAndroid Build Coastguard Worker return other * scalar; 303*d9f75844SAndroid Build Coastguard Worker } 304*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 305*d9f75844SAndroid Build Coastguard Worker inline constexpr Unit_T operator*(int32_t scalar, RelativeUnit<Unit_T> other) { 306*d9f75844SAndroid Build Coastguard Worker return other * scalar; 307*d9f75844SAndroid Build Coastguard Worker } 308*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 309*d9f75844SAndroid Build Coastguard Worker inline constexpr Unit_T operator*(size_t scalar, RelativeUnit<Unit_T> other) { 310*d9f75844SAndroid Build Coastguard Worker return other * scalar; 311*d9f75844SAndroid Build Coastguard Worker } 312*d9f75844SAndroid Build Coastguard Worker 313*d9f75844SAndroid Build Coastguard Worker template <class Unit_T> 314*d9f75844SAndroid Build Coastguard Worker inline constexpr Unit_T operator-(RelativeUnit<Unit_T> other) { 315*d9f75844SAndroid Build Coastguard Worker if (other.IsPlusInfinity()) 316*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::MinusInfinity(); 317*d9f75844SAndroid Build Coastguard Worker if (other.IsMinusInfinity()) 318*d9f75844SAndroid Build Coastguard Worker return UnitBase<Unit_T>::PlusInfinity(); 319*d9f75844SAndroid Build Coastguard Worker return -1 * other; 320*d9f75844SAndroid Build Coastguard Worker } 321*d9f75844SAndroid Build Coastguard Worker 322*d9f75844SAndroid Build Coastguard Worker } // namespace rtc_units_impl 323*d9f75844SAndroid Build Coastguard Worker 324*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc 325*d9f75844SAndroid Build Coastguard Worker 326*d9f75844SAndroid Build Coastguard Worker #endif // RTC_BASE_UNITS_UNIT_BASE_H_ 327