xref: /aosp_15_r20/external/cronet/base/numerics/clamped_math.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_NUMERICS_CLAMPED_MATH_H_
6 #define BASE_NUMERICS_CLAMPED_MATH_H_
7 
8 #include <stddef.h>
9 
10 #include <limits>
11 #include <type_traits>
12 
13 #include "base/numerics/clamped_math_impl.h"
14 
15 namespace base {
16 namespace internal {
17 
18 template <typename T>
19 class ClampedNumeric {
20   static_assert(std::is_arithmetic_v<T>,
21                 "ClampedNumeric<T>: T must be a numeric type.");
22 
23  public:
24   using type = T;
25 
ClampedNumeric()26   constexpr ClampedNumeric() : value_(0) {}
27 
28   // Copy constructor.
29   template <typename Src>
ClampedNumeric(const ClampedNumeric<Src> & rhs)30   constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs)
31       : value_(saturated_cast<T>(rhs.value_)) {}
32 
33   template <typename Src>
34   friend class ClampedNumeric;
35 
36   // Strictly speaking, this is not necessary, but declaring this allows class
37   // template argument deduction to be used so that it is possible to simply
38   // write `ClampedNumeric(777)` instead of `ClampedNumeric<int>(777)`.
39   // NOLINTNEXTLINE(google-explicit-constructor)
ClampedNumeric(T value)40   constexpr ClampedNumeric(T value) : value_(value) {}
41 
42   // This is not an explicit constructor because we implicitly upgrade regular
43   // numerics to ClampedNumerics to make them easier to use.
44   template <typename Src>
45   // NOLINTNEXTLINE(google-explicit-constructor)
ClampedNumeric(Src value)46   constexpr ClampedNumeric(Src value) : value_(saturated_cast<T>(value)) {
47     static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
48   }
49 
50   // This is not an explicit constructor because we want a seamless conversion
51   // from StrictNumeric types.
52   template <typename Src>
53   // NOLINTNEXTLINE(google-explicit-constructor)
ClampedNumeric(StrictNumeric<Src> value)54   constexpr ClampedNumeric(StrictNumeric<Src> value)
55       : value_(saturated_cast<T>(static_cast<Src>(value))) {}
56 
57   // Returns a ClampedNumeric of the specified type, cast from the current
58   // ClampedNumeric, and saturated to the destination type.
59   template <typename Dst>
Cast()60   constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
61     return *this;
62   }
63 
64   // Prototypes for the supported arithmetic operator overloads.
65   template <typename Src>
66   constexpr ClampedNumeric& operator+=(const Src rhs);
67   template <typename Src>
68   constexpr ClampedNumeric& operator-=(const Src rhs);
69   template <typename Src>
70   constexpr ClampedNumeric& operator*=(const Src rhs);
71   template <typename Src>
72   constexpr ClampedNumeric& operator/=(const Src rhs);
73   template <typename Src>
74   constexpr ClampedNumeric& operator%=(const Src rhs);
75   template <typename Src>
76   constexpr ClampedNumeric& operator<<=(const Src rhs);
77   template <typename Src>
78   constexpr ClampedNumeric& operator>>=(const Src rhs);
79   template <typename Src>
80   constexpr ClampedNumeric& operator&=(const Src rhs);
81   template <typename Src>
82   constexpr ClampedNumeric& operator|=(const Src rhs);
83   template <typename Src>
84   constexpr ClampedNumeric& operator^=(const Src rhs);
85 
86   constexpr ClampedNumeric operator-() const {
87     // The negation of two's complement int min is int min, so that's the
88     // only overflow case where we will saturate.
89     return ClampedNumeric<T>(SaturatedNegWrapper(value_));
90   }
91 
92   constexpr ClampedNumeric operator~() const {
93     return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
94   }
95 
Abs()96   constexpr ClampedNumeric Abs() const {
97     // The negation of two's complement int min is int min, so that's the
98     // only overflow case where we will saturate.
99     return ClampedNumeric<T>(SaturatedAbsWrapper(value_));
100   }
101 
102   template <typename U>
Max(const U rhs)103   constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(
104       const U rhs) const {
105     using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
106     return ClampedNumeric<result_type>(
107         ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
108   }
109 
110   template <typename U>
Min(const U rhs)111   constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(
112       const U rhs) const {
113     using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
114     return ClampedNumeric<result_type>(
115         ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
116   }
117 
118   // This function is available only for integral types. It returns an unsigned
119   // integer of the same width as the source type, containing the absolute value
120   // of the source, and properly handling signed min.
121   constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>
UnsignedAbs()122   UnsignedAbs() const {
123     return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(
124         SafeUnsignedAbs(value_));
125   }
126 
127   constexpr ClampedNumeric& operator++() {
128     *this += 1;
129     return *this;
130   }
131 
132   constexpr ClampedNumeric operator++(int) {
133     ClampedNumeric value = *this;
134     *this += 1;
135     return value;
136   }
137 
138   constexpr ClampedNumeric& operator--() {
139     *this -= 1;
140     return *this;
141   }
142 
143   constexpr ClampedNumeric operator--(int) {
144     ClampedNumeric value = *this;
145     *this -= 1;
146     return value;
147   }
148 
149   // These perform the actual math operations on the ClampedNumerics.
150   // Binary arithmetic operations.
151   template <template <typename, typename> class M, typename L, typename R>
MathOp(const L lhs,const R rhs)152   static constexpr ClampedNumeric MathOp(const L lhs, const R rhs) {
153     using Math = typename MathWrapper<M, L, R>::math;
154     return ClampedNumeric<T>(
155         Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
156   }
157 
158   // Assignment arithmetic operations.
159   template <template <typename, typename> class M, typename R>
MathOp(const R rhs)160   constexpr ClampedNumeric& MathOp(const R rhs) {
161     using Math = typename MathWrapper<M, T, R>::math;
162     *this =
163         ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
164     return *this;
165   }
166 
167   template <typename Dst>
Dst()168   constexpr operator Dst() const {
169     return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(
170         value_);
171   }
172 
173   // This method extracts the raw integer value without saturating it to the
174   // destination type as the conversion operator does. This is useful when
175   // e.g. assigning to an auto type or passing as a deduced template parameter.
RawValue()176   constexpr T RawValue() const { return value_; }
177 
178  private:
179   T value_;
180 
181   // These wrappers allow us to handle state the same way for both
182   // ClampedNumeric and POD arithmetic types.
183   template <typename Src>
184   struct Wrapper {
valueWrapper185     static constexpr typename UnderlyingType<Src>::type value(Src value) {
186       return value;
187     }
188   };
189 };
190 
191 // Convenience wrapper to return a new ClampedNumeric from the provided
192 // arithmetic or ClampedNumericType.
193 template <typename T>
MakeClampedNum(const T value)194 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
195     const T value) {
196   return value;
197 }
198 
199 // These implement the variadic wrapper for the math operations.
200 template <template <typename, typename> class M, typename L, typename R>
ClampMathOp(const L lhs,const R rhs)201 constexpr ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(
202     const L lhs,
203     const R rhs) {
204   using Math = typename MathWrapper<M, L, R>::math;
205   return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
206                                                                         rhs);
207 }
208 
209 // General purpose wrapper template for arithmetic operations.
210 template <template <typename, typename> class M,
211           typename L,
212           typename R,
213           typename... Args>
ClampMathOp(const L lhs,const R rhs,const Args...args)214 constexpr auto ClampMathOp(const L lhs, const R rhs, const Args... args) {
215   return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
216 }
217 
218 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
219 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
220 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
221 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
222 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
223 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
224 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
225 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
226 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
227 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
228 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
229 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
230 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <)
231 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=)
232 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >)
233 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=)
234 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==)
235 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=)
236 
237 }  // namespace internal
238 
239 using internal::ClampAdd;
240 using internal::ClampAnd;
241 using internal::ClampDiv;
242 using internal::ClampedNumeric;
243 using internal::ClampLsh;
244 using internal::ClampMax;
245 using internal::ClampMin;
246 using internal::ClampMod;
247 using internal::ClampMul;
248 using internal::ClampOr;
249 using internal::ClampRsh;
250 using internal::ClampSub;
251 using internal::ClampXor;
252 using internal::MakeClampedNum;
253 
254 }  // namespace base
255 
256 #endif  // BASE_NUMERICS_CLAMPED_MATH_H_
257