xref: /aosp_15_r20/external/angle/src/common/base/anglebase/numerics/clamped_math.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 "anglebase/numerics/clamped_math_impl.h"
14 
15 namespace angle
16 {
17 namespace base
18 {
19 namespace internal
20 {
21 
22 template <typename T>
23 class ClampedNumeric
24 {
25     static_assert(std::is_arithmetic<T>::value, "ClampedNumeric<T>: T must be a numeric type.");
26 
27   public:
28     using type = T;
29 
ClampedNumeric()30     constexpr ClampedNumeric() : value_(0) {}
31 
32     // Copy constructor.
33     template <typename Src>
ClampedNumeric(const ClampedNumeric<Src> & rhs)34     constexpr ClampedNumeric(const ClampedNumeric<Src> &rhs) : value_(saturated_cast<T>(rhs.value_))
35     {}
36 
37     template <typename Src>
38     friend class ClampedNumeric;
39 
40     // This is not an explicit constructor because we implicitly upgrade regular
41     // numerics to ClampedNumerics to make them easier to use.
42     template <typename Src>
ClampedNumeric(Src value)43     constexpr ClampedNumeric(Src value)  // NOLINT(runtime/explicit)
44         : value_(saturated_cast<T>(value))
45     {
46         static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
47     }
48 
49     // This is not an explicit constructor because we want a seamless conversion
50     // from StrictNumeric types.
51     template <typename Src>
ClampedNumeric(StrictNumeric<Src> value)52     constexpr ClampedNumeric(StrictNumeric<Src> value)  // NOLINT(runtime/explicit)
53         : value_(saturated_cast<T>(static_cast<Src>(value)))
54     {}
55 
56     // Returns a ClampedNumeric of the specified type, cast from the current
57     // ClampedNumeric, and saturated to the destination type.
58     template <typename Dst>
Cast()59     constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const
60     {
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     {
88         // The negation of two's complement int min is int min, so that's the
89         // only overflow case where we will saturate.
90         return ClampedNumeric<T>(SaturatedNegWrapper(value_));
91     }
92 
93     constexpr ClampedNumeric operator~() const
94     {
95         return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
96     }
97 
Abs()98     constexpr ClampedNumeric Abs() const
99     {
100         // The negation of two's complement int min is int min, so that's the
101         // only overflow case where we will saturate.
102         return ClampedNumeric<T>(SaturatedAbsWrapper(value_));
103     }
104 
105     template <typename U>
Max(const U rhs)106     constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(const U rhs) const
107     {
108         using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
109         return ClampedNumeric<result_type>(ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
110     }
111 
112     template <typename U>
Min(const U rhs)113     constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(const U rhs) const
114     {
115         using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
116         return ClampedNumeric<result_type>(ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
117     }
118 
119     // This function is available only for integral types. It returns an unsigned
120     // integer of the same width as the source type, containing the absolute value
121     // of the source, and properly handling signed min.
UnsignedAbs()122     constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const
123     {
124         return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(SafeUnsignedAbs(value_));
125     }
126 
127     constexpr ClampedNumeric &operator++()
128     {
129         *this += 1;
130         return *this;
131     }
132 
133     constexpr ClampedNumeric operator++(int)
134     {
135         ClampedNumeric value = *this;
136         *this += 1;
137         return value;
138     }
139 
140     constexpr ClampedNumeric &operator--()
141     {
142         *this -= 1;
143         return *this;
144     }
145 
146     constexpr ClampedNumeric operator--(int)
147     {
148         ClampedNumeric value = *this;
149         *this -= 1;
150         return value;
151     }
152 
153     // These perform the actual math operations on the ClampedNumerics.
154     // Binary arithmetic operations.
155     template <template <typename, typename, typename> class M, typename L, typename R>
MathOp(const L lhs,const R rhs)156     static constexpr ClampedNumeric MathOp(const L lhs, const R rhs)
157     {
158         using Math = typename MathWrapper<M, L, R>::math;
159         return ClampedNumeric<T>(
160             Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
161     }
162 
163     // Assignment arithmetic operations.
164     template <template <typename, typename, typename> class M, typename R>
MathOp(const R rhs)165     constexpr ClampedNumeric &MathOp(const R rhs)
166     {
167         using Math = typename MathWrapper<M, T, R>::math;
168         *this      = ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
169         return *this;
170     }
171 
172     template <typename Dst>
Dst()173     constexpr operator Dst() const
174     {
175         return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(value_);
176     }
177 
178     // This method extracts the raw integer value without saturating it to the
179     // destination type as the conversion operator does. This is useful when
180     // e.g. assigning to an auto type or passing as a deduced template parameter.
RawValue()181     constexpr T RawValue() const { return value_; }
182 
183   private:
184     T value_;
185 
186     // These wrappers allow us to handle state the same way for both
187     // ClampedNumeric and POD arithmetic types.
188     template <typename Src>
189     struct Wrapper
190     {
valueWrapper191         static constexpr Src value(Src value)
192         {
193             return static_cast<typename UnderlyingType<Src>::type>(value);
194         }
195     };
196 };
197 
198 // Convience wrapper to return a new ClampedNumeric from the provided arithmetic
199 // or ClampedNumericType.
200 template <typename T>
MakeClampedNum(const T value)201 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(const T value)
202 {
203     return value;
204 }
205 
206 #if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
207 // Overload the ostream output operator to make logging work nicely.
208 template <typename T>
209 std::ostream &operator<<(std::ostream &os, const ClampedNumeric<T> &value)
210 {
211     os << static_cast<T>(value);
212     return os;
213 }
214 #endif
215 
216 // These implement the variadic wrapper for the math operations.
217 template <template <typename, typename, typename> class M, typename L, typename R>
ClampMathOp(const L lhs,const R rhs)218 constexpr ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs, const R rhs)
219 {
220     using Math = typename MathWrapper<M, L, R>::math;
221     return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs, rhs);
222 }
223 
224 // General purpose wrapper template for arithmetic operations.
225 template <template <typename, typename, typename> class M, typename L, typename R, typename... Args>
ClampMathOp(const L lhs,const R rhs,const Args...args)226 constexpr auto ClampMathOp(const L lhs, const R rhs, const Args... args)
227 {
228     return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
229 }
230 
231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
232 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
233 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
234 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
235 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
236 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
237 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
238 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
239 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
240 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
241 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
242 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
243 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <)
244 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=)
245 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >)
246 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=)
247 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==)
248 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=)
249 
250 }  // namespace internal
251 
252 using internal::ClampAdd;
253 using internal::ClampAnd;
254 using internal::ClampDiv;
255 using internal::ClampedNumeric;
256 using internal::ClampLsh;
257 using internal::ClampMax;
258 using internal::ClampMin;
259 using internal::ClampMod;
260 using internal::ClampMul;
261 using internal::ClampOr;
262 using internal::ClampRsh;
263 using internal::ClampSub;
264 using internal::ClampXor;
265 using internal::MakeClampedNum;
266 
267 }  // namespace base
268 }  // namespace angle
269 
270 #endif  // BASE_NUMERICS_CLAMPED_MATH_H_
271