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

Side by Side Diff: base/numerics/clamped_math_impl.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_IMPL_H_
6 #define BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <climits>
12 #include <cmath>
13 #include <cstdlib>
14 #include <limits>
15 #include <type_traits>
16
17 #include "base/numerics/checked_math.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/numerics/safe_math_shared_impl.h"
20
21 namespace base {
22 namespace internal {
23
24 // This provides a small optimization that generates more compact code when one
25 // of the components in an operation is a compile-time constant.
26 template <typename T>
27 constexpr bool IsValueConstantAndNegative(const T v) {
28 #if defined(__clang__) || defined(__GNUC__)
29 return __builtin_constant_p(v) ? IsValueNegative(v) : false;
30 #else
31 return false;
32 #endif
33 }
34
35 template <typename T, typename U, class Enable = void>
36 struct ClampedAddOp {};
37
38 template <typename T, typename U>
39 struct ClampedAddOp<T,
40 U,
41 typename std::enable_if<std::is_integral<T>::value &&
42 std::is_integral<U>::value>::type> {
43 using result_type = typename MaxExponentPromotion<T, U>::type;
44 template <typename V = result_type>
45 static V Do(T x, U y) {
46 V result;
47 return CheckedAddOp<T, U>::Do(x, y, &result)
48 ? result
49 : (as_unsigned(std::numeric_limits<V>::max()) +
50 (IsValueConstantAndNegative(x) || IsValueNegative(y)));
51 }
52 };
53
54 template <typename T, typename U, class Enable = void>
55 struct ClampedSubOp {};
56
57 template <typename T, typename U>
58 struct ClampedSubOp<T,
59 U,
60 typename std::enable_if<std::is_integral<T>::value &&
61 std::is_integral<U>::value>::type> {
62 using result_type = typename MaxExponentPromotion<T, U>::type;
63 template <typename V = result_type>
64 static V Do(T x, U y) {
65 V result;
66 return CheckedSubOp<T, U>::Do(x, y, &result)
67 ? result
68 : (as_unsigned(std::numeric_limits<V>::max()) +
69 (IsValueConstantAndNegative(x) || !IsValueNegative(y)));
70 }
71 };
72
73 template <typename T, typename U, class Enable = void>
74 struct ClampedMulOp {};
75
76 template <typename T, typename U>
77 struct ClampedMulOp<T,
78 U,
79 typename std::enable_if<std::is_integral<T>::value &&
80 std::is_integral<U>::value>::type> {
81 using result_type = typename MaxExponentPromotion<T, U>::type;
82 template <typename V = result_type>
83 static V Do(T x, U y) {
84 V result;
85 return CheckedMulOp<T, U>::Do(x, y, &result)
86 ? result
87 : as_unsigned(std::numeric_limits<V>::max()) +
88 (IsValueNegative(x) ^ IsValueNegative(y));
89 }
90 };
91
92 template <typename T, typename U, class Enable = void>
93 struct ClampedDivOp {};
94
95 template <typename T, typename U>
96 struct ClampedDivOp<T,
97 U,
98 typename std::enable_if<std::is_integral<T>::value &&
99 std::is_integral<U>::value>::type> {
100 using result_type = typename MaxExponentPromotion<T, U>::type;
101 template <typename V = result_type>
102 static V Do(T x, U y) {
103 V result;
104 return CheckedDivOp<T, U>::Do(x, y, &result)
105 ? result
106 : as_unsigned(std::numeric_limits<V>::max()) +
107 (IsValueNegative(x) ^ IsValueNegative(y));
108 }
109 };
110
111 template <typename T, typename U, class Enable = void>
112 struct ClampedModOp {};
113
114 template <typename T, typename U>
115 struct ClampedModOp<T,
116 U,
117 typename std::enable_if<std::is_integral<T>::value &&
118 std::is_integral<U>::value>::type> {
119 using result_type = typename MaxExponentPromotion<T, U>::type;
120 template <typename V = result_type>
121 static V Do(T x, U y) {
122 V result;
123 return CheckedModOp<T, U>::Do(x, y, &result) ? result : x;
124 }
125 };
126
127 template <typename T, typename U, class Enable = void>
128 struct ClampedLshOp {};
129
130 // Left shift. Non-zero values saturate in the direction of the sign. A zero
131 // shifted by any value always results in zero.
132 // Note: This class template supports left shifting negative values.
133 template <typename T, typename U>
134 struct ClampedLshOp<T,
135 U,
136 typename std::enable_if<std::is_integral<T>::value &&
137 std::is_integral<U>::value>::type> {
138 using result_type = T;
139 template <typename V = result_type>
140 static V Do(T x, U shift) {
141 static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
142 V result = x;
143 return CheckedLshOp<T, U>::Do(x, shift, &result)
144 ? result
145 : as_unsigned(std::numeric_limits<V>::max()) +
146 IsValueNegative(x);
147 }
148 };
149
150 template <typename T, typename U, class Enable = void>
151 struct ClampedRshOp {};
152
153 // Right shift. Negative values saturate to -1. Positive or 0 saturates to 0.
154 template <typename T, typename U>
155 struct ClampedRshOp<T,
156 U,
157 typename std::enable_if<std::is_integral<T>::value &&
158 std::is_integral<U>::value>::type> {
159 using result_type = T;
160 template <typename V = result_type>
161 static V Do(T x, U shift) {
162 static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
163 V result = x;
164 return CheckedRshOp<T, U>::Do(x, shift, &result)
165 ? result
166 : as_unsigned(V(0)) - IsValueNegative(x);
167 }
168 };
169
170 template <typename T, typename U, class Enable = void>
171 struct ClampedAndOp {};
172
173 template <typename T, typename U>
174 struct ClampedAndOp<T,
175 U,
176 typename std::enable_if<std::is_integral<T>::value &&
177 std::is_integral<U>::value>::type> {
178 using result_type = typename std::make_unsigned<
179 typename MaxExponentPromotion<T, U>::type>::type;
180 template <typename V>
181 static constexpr V Do(T x, U y) {
182 return static_cast<result_type>(x) & static_cast<result_type>(y);
183 }
184 };
185
186 template <typename T, typename U, class Enable = void>
187 struct ClampedOrOp {};
188
189 // For simplicity we promote to unsigned integers.
190 template <typename T, typename U>
191 struct ClampedOrOp<T,
192 U,
193 typename std::enable_if<std::is_integral<T>::value &&
194 std::is_integral<U>::value>::type> {
195 using result_type = typename std::make_unsigned<
196 typename MaxExponentPromotion<T, U>::type>::type;
197 template <typename V>
198 static constexpr V Do(T x, U y) {
199 return static_cast<result_type>(x) | static_cast<result_type>(y);
200 }
201 };
202
203 template <typename T, typename U, class Enable = void>
204 struct ClampedXorOp {};
205
206 // For simplicity we support only unsigned integers.
207 template <typename T, typename U>
208 struct ClampedXorOp<T,
209 U,
210 typename std::enable_if<std::is_integral<T>::value &&
211 std::is_integral<U>::value>::type> {
212 using result_type = typename std::make_unsigned<
213 typename MaxExponentPromotion<T, U>::type>::type;
214 template <typename V>
215 static constexpr V Do(T x, U y) {
216 return static_cast<result_type>(x) ^ static_cast<result_type>(y);
217 }
218 };
219
220 template <typename T, typename U, class Enable = void>
221 struct ClampedMaxOp {};
222
223 template <typename T, typename U>
224 struct ClampedMaxOp<
225 T,
226 U,
227 typename std::enable_if<std::is_arithmetic<T>::value &&
228 std::is_arithmetic<U>::value>::type> {
229 using result_type = typename MaxExponentPromotion<T, U>::type;
230 template <typename V = result_type>
231 static constexpr V Do(T x, U y) {
232 return IsGreater<T, U>::Test(x, y) ? saturated_cast<V>(x)
233 : saturated_cast<V>(y);
234 }
235 };
236
237 template <typename T, typename U, class Enable = void>
238 struct ClampedMinOp {};
239
240 template <typename T, typename U>
241 struct ClampedMinOp<
242 T,
243 U,
244 typename std::enable_if<std::is_arithmetic<T>::value &&
245 std::is_arithmetic<U>::value>::type> {
246 using result_type = typename LowestValuePromotion<T, U>::type;
247 template <typename V = result_type>
248 static constexpr V Do(T x, U y) {
249 return IsLess<T, U>::Test(x, y) ? saturated_cast<V>(x)
250 : saturated_cast<V>(y);
251 }
252 };
253
254 // This is just boilerplate that wraps the standard floating point arithmetic.
255 // A macro isn't the nicest solution, but it beats rewriting these repeatedly.
256 #define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
257 template <typename T, typename U> \
258 struct Clamped##NAME##Op< \
259 T, U, \
260 typename std::enable_if<std::is_floating_point<T>::value || \
261 std::is_floating_point<U>::value>::type> { \
262 using result_type = typename MaxExponentPromotion<T, U>::type; \
263 template <typename V = result_type> \
264 static constexpr V Do(T x, U y) { \
265 return saturated_cast<V>(x OP y); \
266 } \
267 };
268
269 BASE_FLOAT_ARITHMETIC_OPS(Add, +)
270 BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
271 BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
272 BASE_FLOAT_ARITHMETIC_OPS(Div, /)
273
274 #undef BASE_FLOAT_ARITHMETIC_OPS
275
276 } // namespace internal
277 } // namespace base
278
279 #endif // BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698