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

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

Issue 1475233002: Remove base::enable_if (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years 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/safe_math.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ 5 #ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_ 6 #define BASE_NUMERICS_SAFE_MATH_IMPL_H_
7 7
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <cmath> 10 #include <cmath>
11 #include <cstdlib> 11 #include <cstdlib>
12 #include <limits> 12 #include <limits>
13 #include <type_traits>
13 14
14 #include "base/numerics/safe_conversions.h" 15 #include "base/numerics/safe_conversions.h"
15 #include "base/template_util.h" 16 #include "base/template_util.h"
16 17
17 namespace base { 18 namespace base {
18 namespace internal { 19 namespace internal {
19 20
20 // Everything from here up to the floating point operations is portable C++, 21 // Everything from here up to the floating point operations is portable C++,
21 // but it may not be fast. This code could be split based on 22 // but it may not be fast. This code could be split based on
22 // platform/architecture and replaced with potentially faster implementations. 23 // platform/architecture and replaced with potentially faster implementations.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 struct IntegerForSizeAndSign<8, false> { 57 struct IntegerForSizeAndSign<8, false> {
57 typedef uint64_t type; 58 typedef uint64_t type;
58 }; 59 };
59 60
60 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to 61 // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
61 // support 128-bit math, then the ArithmeticPromotion template below will need 62 // support 128-bit math, then the ArithmeticPromotion template below will need
62 // to be updated (or more likely replaced with a decltype expression). 63 // to be updated (or more likely replaced with a decltype expression).
63 64
64 template <typename Integer> 65 template <typename Integer>
65 struct UnsignedIntegerForSize { 66 struct UnsignedIntegerForSize {
66 typedef typename enable_if< 67 typedef typename std::enable_if<
67 std::numeric_limits<Integer>::is_integer, 68 std::numeric_limits<Integer>::is_integer,
68 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; 69 typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
69 }; 70 };
70 71
71 template <typename Integer> 72 template <typename Integer>
72 struct SignedIntegerForSize { 73 struct SignedIntegerForSize {
73 typedef typename enable_if< 74 typedef typename std::enable_if<
74 std::numeric_limits<Integer>::is_integer, 75 std::numeric_limits<Integer>::is_integer,
75 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; 76 typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
76 }; 77 };
77 78
78 template <typename Integer> 79 template <typename Integer>
79 struct TwiceWiderInteger { 80 struct TwiceWiderInteger {
80 typedef typename enable_if< 81 typedef typename std::enable_if<
81 std::numeric_limits<Integer>::is_integer, 82 std::numeric_limits<Integer>::is_integer,
82 typename IntegerForSizeAndSign< 83 typename IntegerForSizeAndSign<
83 sizeof(Integer) * 2, 84 sizeof(Integer) * 2,
84 std::numeric_limits<Integer>::is_signed>::type>::type type; 85 std::numeric_limits<Integer>::is_signed>::type>::type type;
85 }; 86 };
86 87
87 template <typename Integer> 88 template <typename Integer>
88 struct PositionOfSignBit { 89 struct PositionOfSignBit {
89 static const typename enable_if<std::numeric_limits<Integer>::is_integer, 90 static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
90 size_t>::type value = 8 * sizeof(Integer) - 1; 91 size_t>::type value =
92 8 * sizeof(Integer) - 1;
91 }; 93 };
92 94
93 // This is used for UnsignedAbs, where we need to support floating-point 95 // This is used for UnsignedAbs, where we need to support floating-point
94 // template instantiations even though we don't actually support the operations. 96 // template instantiations even though we don't actually support the operations.
95 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, 97 // However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
96 // so the float versions will not compile. 98 // so the float versions will not compile.
97 template <typename Numeric, 99 template <typename Numeric,
98 bool IsInteger = std::numeric_limits<Numeric>::is_integer, 100 bool IsInteger = std::numeric_limits<Numeric>::is_integer,
99 bool IsFloat = std::numeric_limits<Numeric>::is_iec559> 101 bool IsFloat = std::numeric_limits<Numeric>::is_iec559>
100 struct UnsignedOrFloatForSize; 102 struct UnsignedOrFloatForSize;
(...skipping 21 matching lines...) Expand all
122 template <typename T> 124 template <typename T>
123 T BinaryComplement(T x) { 125 T BinaryComplement(T x) {
124 return ~x; 126 return ~x;
125 } 127 }
126 128
127 // Here are the actual portable checked integer math implementations. 129 // Here are the actual portable checked integer math implementations.
128 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean 130 // TODO(jschuh): Break this code out from the enable_if pattern and find a clean
129 // way to coalesce things into the CheckedNumericState specializations below. 131 // way to coalesce things into the CheckedNumericState specializations below.
130 132
131 template <typename T> 133 template <typename T>
132 typename enable_if<std::numeric_limits<T>::is_integer, T>::type 134 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
133 CheckedAdd(T x, T y, RangeConstraint* validity) { 135 CheckedAdd(T x, T y, RangeConstraint* validity) {
134 // Since the value of x+y is undefined if we have a signed type, we compute 136 // Since the value of x+y is undefined if we have a signed type, we compute
135 // it using the unsigned type of the same size. 137 // it using the unsigned type of the same size.
136 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; 138 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
137 UnsignedDst ux = static_cast<UnsignedDst>(x); 139 UnsignedDst ux = static_cast<UnsignedDst>(x);
138 UnsignedDst uy = static_cast<UnsignedDst>(y); 140 UnsignedDst uy = static_cast<UnsignedDst>(y);
139 UnsignedDst uresult = ux + uy; 141 UnsignedDst uresult = ux + uy;
140 // Addition is valid if the sign of (x + y) is equal to either that of x or 142 // Addition is valid if the sign of (x + y) is equal to either that of x or
141 // that of y. 143 // that of y.
142 if (std::numeric_limits<T>::is_signed) { 144 if (std::numeric_limits<T>::is_signed) {
143 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy)))) 145 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
144 *validity = RANGE_VALID; 146 *validity = RANGE_VALID;
145 else // Direction of wrap is inverse of result sign. 147 else // Direction of wrap is inverse of result sign.
146 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; 148 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
147 149
148 } else { // Unsigned is either valid or overflow. 150 } else { // Unsigned is either valid or overflow.
149 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; 151 *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
150 } 152 }
151 return static_cast<T>(uresult); 153 return static_cast<T>(uresult);
152 } 154 }
153 155
154 template <typename T> 156 template <typename T>
155 typename enable_if<std::numeric_limits<T>::is_integer, T>::type 157 typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
156 CheckedSub(T x, T y, RangeConstraint* validity) { 158 CheckedSub(T x, T y, RangeConstraint* validity) {
157 // Since the value of x+y is undefined if we have a signed type, we compute 159 // Since the value of x+y is undefined if we have a signed type, we compute
158 // it using the unsigned type of the same size. 160 // it using the unsigned type of the same size.
159 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; 161 typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
160 UnsignedDst ux = static_cast<UnsignedDst>(x); 162 UnsignedDst ux = static_cast<UnsignedDst>(x);
161 UnsignedDst uy = static_cast<UnsignedDst>(y); 163 UnsignedDst uy = static_cast<UnsignedDst>(y);
162 UnsignedDst uresult = ux - uy; 164 UnsignedDst uresult = ux - uy;
163 // Subtraction is valid if either x and y have same sign, or (x-y) and x have 165 // Subtraction is valid if either x and y have same sign, or (x-y) and x have
164 // the same sign. 166 // the same sign.
165 if (std::numeric_limits<T>::is_signed) { 167 if (std::numeric_limits<T>::is_signed) {
166 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy)))) 168 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
167 *validity = RANGE_VALID; 169 *validity = RANGE_VALID;
168 else // Direction of wrap is inverse of result sign. 170 else // Direction of wrap is inverse of result sign.
169 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; 171 *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
170 172
171 } else { // Unsigned is either valid or underflow. 173 } else { // Unsigned is either valid or underflow.
172 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; 174 *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
173 } 175 }
174 return static_cast<T>(uresult); 176 return static_cast<T>(uresult);
175 } 177 }
176 178
177 // Integer multiplication is a bit complicated. In the fast case we just 179 // Integer multiplication is a bit complicated. In the fast case we just
178 // we just promote to a twice wider type, and range check the result. In the 180 // we just promote to a twice wider type, and range check the result. In the
179 // slow case we need to manually check that the result won't be truncated by 181 // slow case we need to manually check that the result won't be truncated by
180 // checking with division against the appropriate bound. 182 // checking with division against the appropriate bound.
181 template <typename T> 183 template <typename T>
182 typename enable_if< 184 typename std::enable_if<std::numeric_limits<T>::is_integer &&
183 std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), 185 sizeof(T) * 2 <= sizeof(uintmax_t),
184 T>::type 186 T>::type
185 CheckedMul(T x, T y, RangeConstraint* validity) { 187 CheckedMul(T x, T y, RangeConstraint* validity) {
186 typedef typename TwiceWiderInteger<T>::type IntermediateType; 188 typedef typename TwiceWiderInteger<T>::type IntermediateType;
187 IntermediateType tmp = 189 IntermediateType tmp =
188 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); 190 static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
189 *validity = DstRangeRelationToSrcRange<T>(tmp); 191 *validity = DstRangeRelationToSrcRange<T>(tmp);
190 return static_cast<T>(tmp); 192 return static_cast<T>(tmp);
191 } 193 }
192 194
193 template <typename T> 195 template <typename T>
194 typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits< 196 typename std::enable_if<std::numeric_limits<T>::is_integer &&
195 T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)), 197 std::numeric_limits<T>::is_signed &&
196 T>::type 198 (sizeof(T) * 2 > sizeof(uintmax_t)),
199 T>::type
197 CheckedMul(T x, T y, RangeConstraint* validity) { 200 CheckedMul(T x, T y, RangeConstraint* validity) {
198 // If either side is zero then the result will be zero. 201 // If either side is zero then the result will be zero.
199 if (!x || !y) { 202 if (!x || !y) {
200 return RANGE_VALID; 203 return RANGE_VALID;
201 204
202 } else if (x > 0) { 205 } else if (x > 0) {
203 if (y > 0) 206 if (y > 0)
204 *validity = 207 *validity =
205 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; 208 x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
206 else 209 else
207 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID 210 *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
208 : RANGE_UNDERFLOW; 211 : RANGE_UNDERFLOW;
209 212
210 } else { 213 } else {
211 if (y > 0) 214 if (y > 0)
212 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID 215 *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
213 : RANGE_UNDERFLOW; 216 : RANGE_UNDERFLOW;
214 else 217 else
215 *validity = 218 *validity =
216 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; 219 y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
217 } 220 }
218 221
219 return x * y; 222 return x * y;
220 } 223 }
221 224
222 template <typename T> 225 template <typename T>
223 typename enable_if<std::numeric_limits<T>::is_integer && 226 typename std::enable_if<std::numeric_limits<T>::is_integer &&
224 !std::numeric_limits<T>::is_signed && 227 !std::numeric_limits<T>::is_signed &&
225 (sizeof(T) * 2 > sizeof(uintmax_t)), 228 (sizeof(T) * 2 > sizeof(uintmax_t)),
226 T>::type 229 T>::type
227 CheckedMul(T x, T y, RangeConstraint* validity) { 230 CheckedMul(T x, T y, RangeConstraint* validity) {
228 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) 231 *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
229 ? RANGE_VALID 232 ? RANGE_VALID
230 : RANGE_OVERFLOW; 233 : RANGE_OVERFLOW;
231 return x * y; 234 return x * y;
232 } 235 }
233 236
234 // Division just requires a check for an invalid negation on signed min/-1. 237 // Division just requires a check for an invalid negation on signed min/-1.
235 template <typename T> 238 template <typename T>
236 T CheckedDiv( 239 T CheckedDiv(T x,
237 T x, 240 T y,
238 T y, 241 RangeConstraint* validity,
239 RangeConstraint* validity, 242 typename std::enable_if<std::numeric_limits<T>::is_integer,
240 typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) { 243 int>::type = 0) {
241 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && 244 if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
242 y == static_cast<T>(-1)) { 245 y == static_cast<T>(-1)) {
243 *validity = RANGE_OVERFLOW; 246 *validity = RANGE_OVERFLOW;
244 return std::numeric_limits<T>::min(); 247 return std::numeric_limits<T>::min();
245 } 248 }
246 249
247 *validity = RANGE_VALID; 250 *validity = RANGE_VALID;
248 return x / y; 251 return x / y;
249 } 252 }
250 253
251 template <typename T> 254 template <typename T>
252 typename enable_if< 255 typename std::enable_if<std::numeric_limits<T>::is_integer &&
253 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, 256 std::numeric_limits<T>::is_signed,
254 T>::type 257 T>::type
255 CheckedMod(T x, T y, RangeConstraint* validity) { 258 CheckedMod(T x, T y, RangeConstraint* validity) {
256 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; 259 *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
257 return x % y; 260 return x % y;
258 } 261 }
259 262
260 template <typename T> 263 template <typename T>
261 typename enable_if< 264 typename std::enable_if<std::numeric_limits<T>::is_integer &&
262 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, 265 !std::numeric_limits<T>::is_signed,
263 T>::type 266 T>::type
264 CheckedMod(T x, T y, RangeConstraint* validity) { 267 CheckedMod(T x, T y, RangeConstraint* validity) {
265 *validity = RANGE_VALID; 268 *validity = RANGE_VALID;
266 return x % y; 269 return x % y;
267 } 270 }
268 271
269 template <typename T> 272 template <typename T>
270 typename enable_if< 273 typename std::enable_if<std::numeric_limits<T>::is_integer &&
271 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, 274 std::numeric_limits<T>::is_signed,
272 T>::type 275 T>::type
273 CheckedNeg(T value, RangeConstraint* validity) { 276 CheckedNeg(T value, RangeConstraint* validity) {
274 *validity = 277 *validity =
275 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 278 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
276 // The negation of signed min is min, so catch that one. 279 // The negation of signed min is min, so catch that one.
277 return -value; 280 return -value;
278 } 281 }
279 282
280 template <typename T> 283 template <typename T>
281 typename enable_if< 284 typename std::enable_if<std::numeric_limits<T>::is_integer &&
282 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, 285 !std::numeric_limits<T>::is_signed,
283 T>::type 286 T>::type
284 CheckedNeg(T value, RangeConstraint* validity) { 287 CheckedNeg(T value, RangeConstraint* validity) {
285 // The only legal unsigned negation is zero. 288 // The only legal unsigned negation is zero.
286 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; 289 *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
287 return static_cast<T>( 290 return static_cast<T>(
288 -static_cast<typename SignedIntegerForSize<T>::type>(value)); 291 -static_cast<typename SignedIntegerForSize<T>::type>(value));
289 } 292 }
290 293
291 template <typename T> 294 template <typename T>
292 typename enable_if< 295 typename std::enable_if<std::numeric_limits<T>::is_integer &&
293 std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed, 296 std::numeric_limits<T>::is_signed,
294 T>::type 297 T>::type
295 CheckedAbs(T value, RangeConstraint* validity) { 298 CheckedAbs(T value, RangeConstraint* validity) {
296 *validity = 299 *validity =
297 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; 300 value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
298 return static_cast<T>(std::abs(value)); 301 return static_cast<T>(std::abs(value));
299 } 302 }
300 303
301 template <typename T> 304 template <typename T>
302 typename enable_if< 305 typename std::enable_if<std::numeric_limits<T>::is_integer &&
303 std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, 306 !std::numeric_limits<T>::is_signed,
304 T>::type 307 T>::type
305 CheckedAbs(T value, RangeConstraint* validity) { 308 CheckedAbs(T value, RangeConstraint* validity) {
306 // T is unsigned, so |value| must already be positive. 309 // T is unsigned, so |value| must already be positive.
307 *validity = RANGE_VALID; 310 *validity = RANGE_VALID;
308 return value; 311 return value;
309 } 312 }
310 313
311 template <typename T> 314 template <typename T>
312 typename enable_if<std::numeric_limits<T>::is_integer && 315 typename std::enable_if<std::numeric_limits<T>::is_integer &&
313 std::numeric_limits<T>::is_signed, 316 std::numeric_limits<T>::is_signed,
314 typename UnsignedIntegerForSize<T>::type>::type 317 typename UnsignedIntegerForSize<T>::type>::type
315 CheckedUnsignedAbs(T value) { 318 CheckedUnsignedAbs(T value) {
316 typedef typename UnsignedIntegerForSize<T>::type UnsignedT; 319 typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
317 return value == std::numeric_limits<T>::min() 320 return value == std::numeric_limits<T>::min()
318 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 321 ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
319 : static_cast<UnsignedT>(std::abs(value)); 322 : static_cast<UnsignedT>(std::abs(value));
320 } 323 }
321 324
322 template <typename T> 325 template <typename T>
323 typename enable_if<std::numeric_limits<T>::is_integer && 326 typename std::enable_if<std::numeric_limits<T>::is_integer &&
324 !std::numeric_limits<T>::is_signed, 327 !std::numeric_limits<T>::is_signed,
325 T>::type 328 T>::type
326 CheckedUnsignedAbs(T value) { 329 CheckedUnsignedAbs(T value) {
327 // T is unsigned, so |value| must already be positive. 330 // T is unsigned, so |value| must already be positive.
328 return value; 331 return value;
329 } 332 }
330 333
331 // These are the floating point stubs that the compiler needs to see. Only the 334 // These are the floating point stubs that the compiler needs to see. Only the
332 // negation operation is ever called. 335 // negation operation is ever called.
333 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ 336 #define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
334 template <typename T> \ 337 template <typename T> \
335 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \ 338 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
336 Checked##NAME(T, T, RangeConstraint*) { \ 339 Checked##NAME(T, T, RangeConstraint*) { \
337 NOTREACHED(); \ 340 NOTREACHED(); \
338 return 0; \ 341 return 0; \
339 } 342 }
340 343
341 BASE_FLOAT_ARITHMETIC_STUBS(Add) 344 BASE_FLOAT_ARITHMETIC_STUBS(Add)
342 BASE_FLOAT_ARITHMETIC_STUBS(Sub) 345 BASE_FLOAT_ARITHMETIC_STUBS(Sub)
343 BASE_FLOAT_ARITHMETIC_STUBS(Mul) 346 BASE_FLOAT_ARITHMETIC_STUBS(Mul)
344 BASE_FLOAT_ARITHMETIC_STUBS(Div) 347 BASE_FLOAT_ARITHMETIC_STUBS(Div)
345 BASE_FLOAT_ARITHMETIC_STUBS(Mod) 348 BASE_FLOAT_ARITHMETIC_STUBS(Mod)
346 349
347 #undef BASE_FLOAT_ARITHMETIC_STUBS 350 #undef BASE_FLOAT_ARITHMETIC_STUBS
348 351
349 template <typename T> 352 template <typename T>
350 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg( 353 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
351 T value, 354 T value,
352 RangeConstraint*) { 355 RangeConstraint*) {
353 return -value; 356 return -value;
354 } 357 }
355 358
356 template <typename T> 359 template <typename T>
357 typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs( 360 typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
358 T value, 361 T value,
359 RangeConstraint*) { 362 RangeConstraint*) {
360 return std::abs(value); 363 return std::abs(value);
361 } 364 }
362 365
363 // Floats carry around their validity state with them, but integers do not. So, 366 // Floats carry around their validity state with them, but integers do not. So,
364 // we wrap the underlying value in a specialization in order to hide that detail 367 // we wrap the underlying value in a specialization in order to hide that detail
365 // and expose an interface via accessors. 368 // and expose an interface via accessors.
366 enum NumericRepresentation { 369 enum NumericRepresentation {
367 NUMERIC_INTEGER, 370 NUMERIC_INTEGER,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 // Copy constructor. 410 // Copy constructor.
408 template <typename Src> 411 template <typename Src>
409 CheckedNumericState(const CheckedNumericState<Src>& rhs) 412 CheckedNumericState(const CheckedNumericState<Src>& rhs)
410 : value_(static_cast<T>(rhs.value())), 413 : value_(static_cast<T>(rhs.value())),
411 validity_(GetRangeConstraint( 414 validity_(GetRangeConstraint(
412 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {} 415 rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
413 416
414 template <typename Src> 417 template <typename Src>
415 explicit CheckedNumericState( 418 explicit CheckedNumericState(
416 Src value, 419 Src value,
417 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 420 typename std::enable_if<std::numeric_limits<Src>::is_specialized,
418 0) 421 int>::type = 0)
419 : value_(static_cast<T>(value)), 422 : value_(static_cast<T>(value)),
420 validity_(DstRangeRelationToSrcRange<T>(value)) {} 423 validity_(DstRangeRelationToSrcRange<T>(value)) {}
421 424
422 RangeConstraint validity() const { return validity_; } 425 RangeConstraint validity() const { return validity_; }
423 T value() const { return value_; } 426 T value() const { return value_; }
424 }; 427 };
425 428
426 // Floating points maintain their own validity, but need translation wrappers. 429 // Floating points maintain their own validity, but need translation wrappers.
427 template <typename T> 430 template <typename T>
428 class CheckedNumericState<T, NUMERIC_FLOATING> { 431 class CheckedNumericState<T, NUMERIC_FLOATING> {
429 private: 432 private:
430 T value_; 433 T value_;
431 434
432 public: 435 public:
433 template <typename Src, NumericRepresentation type> 436 template <typename Src, NumericRepresentation type>
434 friend class CheckedNumericState; 437 friend class CheckedNumericState;
435 438
436 CheckedNumericState() : value_(0.0) {} 439 CheckedNumericState() : value_(0.0) {}
437 440
438 template <typename Src> 441 template <typename Src>
439 CheckedNumericState( 442 CheckedNumericState(
440 Src value, 443 Src value,
441 RangeConstraint validity, 444 RangeConstraint validity,
442 typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) { 445 typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
446 0) {
443 switch (DstRangeRelationToSrcRange<T>(value)) { 447 switch (DstRangeRelationToSrcRange<T>(value)) {
444 case RANGE_VALID: 448 case RANGE_VALID:
445 value_ = static_cast<T>(value); 449 value_ = static_cast<T>(value);
446 break; 450 break;
447 451
448 case RANGE_UNDERFLOW: 452 case RANGE_UNDERFLOW:
449 value_ = -std::numeric_limits<T>::infinity(); 453 value_ = -std::numeric_limits<T>::infinity();
450 break; 454 break;
451 455
452 case RANGE_OVERFLOW: 456 case RANGE_OVERFLOW:
453 value_ = std::numeric_limits<T>::infinity(); 457 value_ = std::numeric_limits<T>::infinity();
454 break; 458 break;
455 459
456 case RANGE_INVALID: 460 case RANGE_INVALID:
457 value_ = std::numeric_limits<T>::quiet_NaN(); 461 value_ = std::numeric_limits<T>::quiet_NaN();
458 break; 462 break;
459 463
460 default: 464 default:
461 NOTREACHED(); 465 NOTREACHED();
462 } 466 }
463 } 467 }
464 468
465 template <typename Src> 469 template <typename Src>
466 explicit CheckedNumericState( 470 explicit CheckedNumericState(
467 Src value, 471 Src value,
468 typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 472 typename std::enable_if<std::numeric_limits<Src>::is_specialized,
469 0) 473 int>::type = 0)
470 : value_(static_cast<T>(value)) {} 474 : value_(static_cast<T>(value)) {}
471 475
472 // Copy constructor. 476 // Copy constructor.
473 template <typename Src> 477 template <typename Src>
474 CheckedNumericState(const CheckedNumericState<Src>& rhs) 478 CheckedNumericState(const CheckedNumericState<Src>& rhs)
475 : value_(static_cast<T>(rhs.value())) {} 479 : value_(static_cast<T>(rhs.value())) {}
476 480
477 RangeConstraint validity() const { 481 RangeConstraint validity() const {
478 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), 482 return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
479 value_ >= -std::numeric_limits<T>::max()); 483 value_ >= -std::numeric_limits<T>::max());
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 sizeof(T) >= (2 * sizeof(Lhs)) && 535 sizeof(T) >= (2 * sizeof(Lhs)) &&
532 StaticDstRangeRelationToSrcRange<T, Rhs>::value != 536 StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
533 NUMERIC_RANGE_CONTAINED && 537 NUMERIC_RANGE_CONTAINED &&
534 sizeof(T) >= (2 * sizeof(Rhs)); 538 sizeof(T) >= (2 * sizeof(Rhs));
535 }; 539 };
536 540
537 } // namespace internal 541 } // namespace internal
538 } // namespace base 542 } // namespace base
539 543
540 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ 544 #endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_
OLDNEW
« no previous file with comments | « base/numerics/safe_math.h ('k') | base/numerics/safe_numerics_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698