OLD | NEW |
---|---|
(Empty) | |
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 "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<T>::value, | |
21 "ClampedNumeric<T>: T must be a numeric type."); | |
22 | |
23 public: | |
24 using type = T; | |
25 | |
26 constexpr ClampedNumeric() : value_(0) {} | |
27 | |
28 // Copy constructor. | |
29 template <typename Src> | |
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 // This is not an explicit constructor because we implicitly upgrade regular | |
37 // numerics to ClampedNumerics to make them easier to use. | |
38 template <typename Src> | |
39 constexpr ClampedNumeric(Src value) // NOLINT(runtime/explicit) | |
40 : value_(saturated_cast<T>(value)) { | |
41 static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); | |
42 } | |
43 | |
44 // This is not an explicit constructor because we want a seamless conversion | |
45 // from StrictNumeric types. | |
46 template <typename Src> | |
47 constexpr ClampedNumeric( | |
48 StrictNumeric<Src> value) // NOLINT(runtime/explicit) | |
49 : value_(saturated_cast<T>(static_cast<Src>(value))) {} | |
50 | |
51 // Returns a checked numeric of the specified type, cast from the current | |
52 // ClampedNumeric. If the current state is invalid or the destination cannot | |
dcheng
2017/06/28 07:25:06
"current state is invalid" => how does that happen
jschuh
2017/06/28 12:32:37
Oops. Copy pasta.
| |
53 // represent the result then the returned ClampedNumeric will be invalid. | |
54 template <typename Dst> | |
55 constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const { | |
56 return *this; | |
57 } | |
58 | |
59 // Prototypes for the supported arithmetic operator overloads. | |
60 template <typename Src> | |
61 ClampedNumeric& operator+=(const Src rhs); | |
62 template <typename Src> | |
63 ClampedNumeric& operator-=(const Src rhs); | |
64 template <typename Src> | |
65 ClampedNumeric& operator*=(const Src rhs); | |
66 template <typename Src> | |
67 ClampedNumeric& operator/=(const Src rhs); | |
68 template <typename Src> | |
69 ClampedNumeric& operator%=(const Src rhs); | |
70 template <typename Src> | |
71 ClampedNumeric& operator<<=(const Src rhs); | |
72 template <typename Src> | |
73 ClampedNumeric& operator>>=(const Src rhs); | |
74 template <typename Src> | |
75 ClampedNumeric& operator&=(const Src rhs); | |
76 template <typename Src> | |
77 ClampedNumeric& operator|=(const Src rhs); | |
78 template <typename Src> | |
79 ClampedNumeric& operator^=(const Src rhs); | |
80 | |
81 constexpr ClampedNumeric operator-() const { | |
82 return ClampedNumeric<T>( | |
83 std::is_signed<T>::value | |
84 ? ((std::is_floating_point<T>::value || | |
85 NegateWrapper(value_) != std::numeric_limits<T>::lowest()) | |
86 ? NegateWrapper(value_) | |
87 : std::numeric_limits<T>::max()) | |
88 : T(0)); // Clamped unsigned negation is always zero. | |
89 } | |
90 | |
91 constexpr ClampedNumeric operator~() const { | |
92 return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_)); | |
93 } | |
94 | |
95 constexpr ClampedNumeric Abs() const { | |
96 return ClampedNumeric<T>( | |
97 (!std::is_signed<T>::value || std::is_floating_point<T>::value || | |
98 AbsWrapper(value_) != std::numeric_limits<T>::lowest()) | |
99 ? AbsWrapper(value_) | |
100 : std::numeric_limits<T>::max()); | |
101 } | |
102 | |
103 template <typename U> | |
104 constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max( | |
105 const U rhs) const { | |
106 using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type; | |
107 return ClampedNumeric<result_type>( | |
108 ClampedMaxOp<T, U>(value_, Wrapper<U>::value(rhs))); | |
109 } | |
110 | |
111 template <typename U> | |
112 constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min( | |
113 const U rhs) const { | |
114 using result_type = typename MathWrapper<ClampedMinOp, T, U>::type; | |
115 return ClampedNumeric<result_type>( | |
116 ClampedMinOp<T, U>(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. | |
122 constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type> | |
123 UnsignedAbs() const { | |
124 return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>( | |
125 SafeUnsignedAbs(value_)); | |
126 } | |
127 | |
128 ClampedNumeric& operator++() { | |
129 *this += 1; | |
130 return *this; | |
131 } | |
132 | |
133 ClampedNumeric operator++(int) { | |
134 ClampedNumeric value = *this; | |
135 *this += 1; | |
136 return value; | |
137 } | |
138 | |
139 ClampedNumeric& operator--() { | |
140 *this -= 1; | |
141 return *this; | |
142 } | |
143 | |
144 ClampedNumeric operator--(int) { | |
145 ClampedNumeric value = *this; | |
146 *this -= 1; | |
147 return value; | |
148 } | |
149 | |
150 // These perform the actual math operations on the ClampedNumerics. | |
151 // Binary arithmetic operations. | |
152 template <template <typename, typename, typename> class M, | |
dcheng
2017/06/28 07:25:06
TBH, I found these templates pretty hard to read d
jschuh
2017/06/28 12:32:37
It's the Clamped*Op struct. But yeah, I just used
dcheng
2017/06/30 07:39:30
Yeah I think that might be better. I would be OK d
| |
153 typename L, | |
154 typename R> | |
155 static ClampedNumeric MathOp(const L lhs, const R rhs) { | |
156 using Math = typename MathWrapper<M, L, R>::math; | |
157 return ClampedNumeric<T>( | |
158 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs))); | |
159 } | |
160 | |
161 // Assignment arithmetic operations. | |
162 template <template <typename, typename, typename> class M, typename R> | |
163 ClampedNumeric& MathOp(const R rhs) { | |
164 using Math = typename MathWrapper<M, T, R>::math; | |
165 *this = | |
166 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs))); | |
167 return *this; | |
168 } | |
169 | |
170 template <typename Dst> | |
171 constexpr operator Dst() const { | |
172 return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>( | |
173 value_); | |
174 } | |
175 | |
176 private: | |
177 T value_; | |
178 | |
179 // These wrappers allow us to handle state the same way for both | |
180 // ClampedNumeric and POD arithmetic types. | |
181 template <typename Src> | |
182 struct Wrapper { | |
183 static constexpr Src value(Src value) { | |
184 return static_cast<typename UnderlyingType<Src>::type>(value); | |
185 } | |
186 }; | |
187 }; | |
188 | |
189 // Convience wrapper to return a new ClampedNumeric from the provided arithmetic | |
190 // or ClampedNumericType. | |
191 template <typename T> | |
192 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum( | |
193 const T value) { | |
194 return value; | |
195 } | |
196 | |
197 // Overload the ostream output operator to make logging work nicely. | |
198 template <typename T> | |
199 std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) { | |
200 os << static_cast<T>(value); | |
201 return os; | |
202 } | |
203 | |
204 // These implement the variadic wrapper for the math operations. | |
205 template <template <typename, typename, typename> class M, | |
206 typename L, | |
207 typename R> | |
208 ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs, | |
209 const R rhs) { | |
210 using Math = typename MathWrapper<M, L, R>::math; | |
211 return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs, | |
212 rhs); | |
213 } | |
214 | |
215 // General purpose wrapper template for arithmetic operations. | |
216 template <template <typename, typename, typename> class M, | |
217 typename L, | |
218 typename R, | |
219 typename... Args> | |
220 ClampedNumeric<typename ResultType<M, L, R, Args...>::type> | |
221 ClampMathOp(const L lhs, const R rhs, const Args... args) { | |
222 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...); | |
dcheng
2017/06/28 07:25:06
Frightening =)
jschuh
2017/06/28 12:32:37
But I figured out how to make variadic templates!
| |
223 } | |
224 | |
225 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=) | |
226 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=) | |
227 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=) | |
228 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=) | |
229 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=) | |
230 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=) | |
231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=) | |
232 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=) | |
233 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=) | |
234 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=) | |
235 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max) | |
236 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min) | |
237 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <); | |
238 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=); | |
239 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >); | |
240 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=); | |
241 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==); | |
242 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=); | |
243 | |
244 } // namespace internal | |
245 | |
246 using internal::ClampedNumeric; | |
247 using internal::MakeClampedNum; | |
248 using internal::ClampMax; | |
249 using internal::ClampMin; | |
250 using internal::ClampAdd; | |
251 using internal::ClampSub; | |
252 using internal::ClampMul; | |
253 using internal::ClampDiv; | |
254 using internal::ClampMod; | |
255 using internal::ClampLsh; | |
256 using internal::ClampRsh; | |
257 using internal::ClampAnd; | |
258 using internal::ClampOr; | |
259 using internal::ClampXor; | |
260 | |
261 } // namespace base | |
262 | |
263 #endif // BASE_NUMERICS_CLAMPED_MATH_H_ | |
OLD | NEW |