Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: base/numerics/clamped_math.h

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: final Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/numerics/checked_math_impl.h ('k') | base/numerics/clamped_math_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 // The negation of two's complement int min is int min, so that's the
83 // only overflow case we have to check for.
84 std::is_signed<T>::value
85 ? ((std::is_floating_point<T>::value ||
86 NegateWrapper(value_) != std::numeric_limits<T>::lowest())
87 ? NegateWrapper(value_)
88 : std::numeric_limits<T>::max())
89 : T(0)); // Clamped unsigned negation is always zero.
90 }
91
92 constexpr ClampedNumeric operator~() const {
93 return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
94 }
95
96 constexpr ClampedNumeric Abs() const {
97 return ClampedNumeric<T>(
98 // The negation of two's complement int min is int min, so that's the
99 // only overflow case we have to check for.
100 (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
101 AbsWrapper(value_) != std::numeric_limits<T>::lowest())
102 ? AbsWrapper(value_)
103 : std::numeric_limits<T>::max());
104 }
105
106 template <typename U>
107 constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(
108 const U rhs) const {
109 using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
110 return ClampedNumeric<result_type>(
111 ClampedMaxOp<T, U>(value_, Wrapper<U>::value(rhs)));
112 }
113
114 template <typename U>
115 constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(
116 const U rhs) const {
117 using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
118 return ClampedNumeric<result_type>(
119 ClampedMinOp<T, U>(value_, Wrapper<U>::value(rhs)));
120 }
121
122 // This function is available only for integral types. It returns an unsigned
123 // integer of the same width as the source type, containing the absolute value
124 // of the source, and properly handling signed min.
125 constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>
126 UnsignedAbs() const {
127 return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(
128 SafeUnsignedAbs(value_));
129 }
130
131 ClampedNumeric& operator++() {
132 *this += 1;
133 return *this;
134 }
135
136 ClampedNumeric operator++(int) {
137 ClampedNumeric value = *this;
138 *this += 1;
139 return value;
140 }
141
142 ClampedNumeric& operator--() {
143 *this -= 1;
144 return *this;
145 }
146
147 ClampedNumeric operator--(int) {
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,
156 typename L,
157 typename R>
158 static ClampedNumeric MathOp(const L lhs, const R rhs) {
159 using Math = typename MathWrapper<M, L, R>::math;
160 return ClampedNumeric<T>(
161 Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
162 }
163
164 // Assignment arithmetic operations.
165 template <template <typename, typename, typename> class M, typename R>
166 ClampedNumeric& MathOp(const R rhs) {
167 using Math = typename MathWrapper<M, T, R>::math;
168 *this =
169 ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
170 return *this;
171 }
172
173 template <typename Dst>
174 constexpr operator Dst() const {
175 return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(
176 value_);
177 }
178
179 private:
180 T value_;
181
182 // These wrappers allow us to handle state the same way for both
183 // ClampedNumeric and POD arithmetic types.
184 template <typename Src>
185 struct Wrapper {
186 static constexpr Src value(Src value) {
187 return static_cast<typename UnderlyingType<Src>::type>(value);
188 }
189 };
190 };
191
192 // Convience wrapper to return a new ClampedNumeric from the provided arithmetic
193 // or ClampedNumericType.
194 template <typename T>
195 constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
196 const T value) {
197 return value;
198 }
199
200 // Overload the ostream output operator to make logging work nicely.
201 template <typename T>
202 std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) {
203 os << static_cast<T>(value);
204 return os;
205 }
206
207 // These implement the variadic wrapper for the math operations.
208 template <template <typename, typename, typename> class M,
209 typename L,
210 typename R>
211 ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(const L lhs,
212 const R rhs) {
213 using Math = typename MathWrapper<M, L, R>::math;
214 return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
215 rhs);
216 }
217
218 // General purpose wrapper template for arithmetic operations.
219 template <template <typename, typename, typename> class M,
220 typename L,
221 typename R,
222 typename... Args>
223 ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
224 ClampMathOp(const L lhs, const R rhs, const Args... args) {
225 return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
226 }
227
228 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
229 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
230 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
231 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
232 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
233 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
234 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
235 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
236 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
237 BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
238 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
239 BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
240 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <);
241 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=);
242 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >);
243 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=);
244 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==);
245 BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=);
246
247 } // namespace internal
248
249 using internal::ClampedNumeric;
250 using internal::MakeClampedNum;
251 using internal::ClampMax;
252 using internal::ClampMin;
253 using internal::ClampAdd;
254 using internal::ClampSub;
255 using internal::ClampMul;
256 using internal::ClampDiv;
257 using internal::ClampMod;
258 using internal::ClampLsh;
259 using internal::ClampRsh;
260 using internal::ClampAnd;
261 using internal::ClampOr;
262 using internal::ClampXor;
263
264 } // namespace base
265
266 #endif // BASE_NUMERICS_CLAMPED_MATH_H_
OLDNEW
« no previous file with comments | « base/numerics/checked_math_impl.h ('k') | base/numerics/clamped_math_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698