xref: /aosp_15_r20/external/webrtc/rtc_base/units/unit_base.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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