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 ClampedNumeric of the specified type, cast from the current | |
52 // ClampedNumeric, and saturated to the destination type. | |
53 template <typename Dst> | |
54 constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const { | |
55 return *this; | |
56 } | |
57 | |
58 // Prototypes for the supported arithmetic operator overloads. | |
59 template <typename Src> | |
60 ClampedNumeric& operator+=(const Src rhs); | |
61 template <typename Src> | |
62 ClampedNumeric& operator-=(const Src rhs); | |
63 template <typename Src> | |
64 ClampedNumeric& operator*=(const Src rhs); | |
65 template <typename Src> | |
66 ClampedNumeric& operator/=(const Src rhs); | |
67 template <typename Src> | |
68 ClampedNumeric& operator%=(const Src rhs); | |
69 template <typename Src> | |
70 ClampedNumeric& operator<<=(const Src rhs); | |
71 template <typename Src> | |
72 ClampedNumeric& operator>>=(const Src rhs); | |
73 template <typename Src> | |
74 ClampedNumeric& operator&=(const Src rhs); | |
75 template <typename Src> | |
76 ClampedNumeric& operator|=(const Src rhs); | |
77 template <typename Src> | |
78 ClampedNumeric& operator^=(const Src rhs); | |
79 | |
80 constexpr ClampedNumeric operator-() const { | |
81 return ClampedNumeric<T>( | |
82 std::is_signed<T>::value | |
83 ? ((std::is_floating_point<T>::value || | |
84 NegateWrapper(value_) != std::numeric_limits<T>::lowest()) | |
dcheng
2017/06/30 07:39:30
I can't help but feel that NegateWrapper / InvertW
jschuh
2017/07/01 06:31:59
There already is a comment at the function definit
dcheng
2017/07/03 10:01:43
Right, the comments I was thinking of were more al
| |
85 ? NegateWrapper(value_) | |
86 : std::numeric_limits<T>::max()) | |
87 : T(0)); // Clamped unsigned negation is always zero. | |
88 } | |
89 | |
90 constexpr ClampedNumeric operator~() const { | |
91 return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_)); | |
92 } | |
93 | |
94 constexpr ClampedNumeric Abs() const { | |
95 return ClampedNumeric<T>( | |
96 (!std::is_signed<T>::value || std::is_floating_point<T>::value || | |
97 AbsWrapper(value_) != std::numeric_limits<T>::lowest()) | |
98 ? AbsWrapper(value_) | |
99 : std::numeric_limits<T>::max()); | |
100 } | |
101 | |
102 template <typename U> | |
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>(value_, Wrapper<U>::value(rhs))); | |
108 } | |
109 | |
110 template <typename U> | |
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>(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> | |
122 UnsignedAbs() const { | |
123 return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>( | |
124 SafeUnsignedAbs(value_)); | |
125 } | |
126 | |
127 ClampedNumeric& operator++() { | |
128 *this += 1; | |
129 return *this; | |
130 } | |
131 | |
132 ClampedNumeric operator++(int) { | |
133 ClampedNumeric value = *this; | |
134 *this += 1; | |
135 return value; | |
136 } | |
137 | |
138 ClampedNumeric& operator--() { | |
139 *this -= 1; | |
140 return *this; | |
141 } | |
142 | |
143 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, typename> class M, | |
152 typename L, | |
153 typename R> | |
154 static ClampedNumeric MathOp(const L lhs, const R rhs) { | |
155 using Math = typename MathWrapper<M, L, R>::math; | |
156 return ClampedNumeric<T>( | |
157 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs))); | |
158 } | |
159 | |
160 // Assignment arithmetic operations. | |
161 template <template <typename, typename, typename> class M, typename R> | |
162 ClampedNumeric& MathOp(const R rhs) { | |
163 using Math = typename MathWrapper<M, T, R>::math; | |
164 *this = | |
165 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs))); | |
166 return *this; | |
167 } | |
168 | |
169 template <typename Dst> | |
170 constexpr operator Dst() const { | |
171 return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>( | |
172 value_); | |
173 } | |
174 | |
175 private: | |
176 T value_; | |
177 | |
178 // These wrappers allow us to handle state the same way for both | |
179 // ClampedNumeric and POD arithmetic types. | |
180 template <typename Src> | |
181 struct Wrapper { | |
182 static constexpr Src value(Src value) { | |
183 return static_cast<typename UnderlyingType<Src>::type>(value); | |
184 } | |
185 }; | |
186 }; | |
187 | |
188 // Convience wrapper to return a new ClampedNumeric from the provided arithmetic | |
189 // or ClampedNumericType. | |
190 template <typename T> | |
191 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum( | |
192 const T value) { | |
193 return value; | |
194 } | |
195 | |
196 // Overload the ostream output operator to make logging work nicely. | |
197 template <typename T> | |
198 std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) { | |
199 os << static_cast<T>(value); | |
200 return os; | |
201 } | |
202 | |
203 // These implement the variadic wrapper for the math operations. | |
204 template <template <typename, typename, typename> class M, | |
205 typename L, | |
206 typename R> | |
207 ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs, | |
208 const R rhs) { | |
209 using Math = typename MathWrapper<M, L, R>::math; | |
210 return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs, | |
211 rhs); | |
212 } | |
213 | |
214 // General purpose wrapper template for arithmetic operations. | |
215 template <template <typename, typename, typename> class M, | |
216 typename L, | |
217 typename R, | |
218 typename... Args> | |
219 ClampedNumeric<typename ResultType<M, L, R, Args...>::type> | |
220 ClampMathOp(const L lhs, const R rhs, const Args... args) { | |
221 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...); | |
222 } | |
223 | |
224 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=) | |
225 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=) | |
226 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=) | |
227 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=) | |
228 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=) | |
229 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=) | |
230 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=) | |
231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=) | |
232 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=) | |
233 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=) | |
234 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max) | |
235 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min) | |
236 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <); | |
237 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=); | |
238 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >); | |
239 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=); | |
240 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==); | |
241 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=); | |
242 | |
243 } // namespace internal | |
244 | |
245 using internal::ClampedNumeric; | |
246 using internal::MakeClampedNum; | |
247 using internal::ClampMax; | |
248 using internal::ClampMin; | |
249 using internal::ClampAdd; | |
250 using internal::ClampSub; | |
251 using internal::ClampMul; | |
252 using internal::ClampDiv; | |
253 using internal::ClampMod; | |
254 using internal::ClampLsh; | |
255 using internal::ClampRsh; | |
256 using internal::ClampAnd; | |
257 using internal::ClampOr; | |
258 using internal::ClampXor; | |
259 | |
260 } // namespace base | |
261 | |
262 #endif // BASE_NUMERICS_CLAMPED_MATH_H_ | |
OLD | NEW |