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

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

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: more docs and modulus 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
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 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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698