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