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

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

Issue 2945433003: Add ClampedNumeric templates (Closed)
Patch Set: post-review fixes 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 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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698