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

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

Issue 141583008: Add support for safe math operations in base/numerics (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 6 years, 10 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 | Annotate | Revision Log
« 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')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #ifndef SAFE_MATH_IMPL_H_
6 #define SAFE_MATH_IMPL_H_
7
8 #include <stdint.h>
9
10 #include <limits>
11
12 #include "base/compiler_specific.h"
13 #include "base/macros.h"
14
15 namespace base {
16 namespace internal {
17
18 using std::numeric_limits;
19
20 // Everything from here up to the definition of CheckedNumericState is
21 // portable C++, but it may not be fast. This code could be split based on
22 // platform/architecture and replaced with potentially faster implementations.
23
24 template <size_t Size, bool IsSigned>
25 struct IntegerTypeForSizeAndSign {};
26
27 template <>
28 struct IntegerTypeForSizeAndSign<1, true> {
29 typedef int8_t Type;
30 };
31
32 template <>
33 struct IntegerTypeForSizeAndSign<1, false> {
34 typedef uint8_t Type;
35 };
36
37 template <>
38 struct IntegerTypeForSizeAndSign<2, true> {
39 typedef int16_t Type;
40 };
41
42 template <>
43 struct IntegerTypeForSizeAndSign<2, false> {
44 typedef uint16_t Type;
45 };
46
47 template <>
48 struct IntegerTypeForSizeAndSign<4, true> {
49 typedef int32_t Type;
50 };
51
52 template <>
53 struct IntegerTypeForSizeAndSign<4, false> {
54 typedef uint32_t Type;
55 };
56
57 template <>
58 struct IntegerTypeForSizeAndSign<8, true> {
59 typedef int64_t Type;
60 };
61
62 template <>
63 struct IntegerTypeForSizeAndSign<8, false> {
64 typedef uint64_t Type;
65 };
66
67 // This is effectively a compile assert to ensure we're supporting the full
68 // type range for this compiler (otherwise multiply may not compile).
69 typedef IntegerTypeForSizeAndSign<sizeof(intmax_t), true> MaxSupportedInteger;
70
71 template <typename IntegerType>
72 struct UnsignedType {
73 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), false>::Type
74 Type;
75 };
76
77 template <typename IntegerType>
78 struct SignedType {
79 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType), true>::Type
80 Type;
81 };
82
83 template <typename IntegerType>
84 struct TwiceWiderType {
85 typedef typename IntegerTypeForSizeAndSign<sizeof(IntegerType) * 2,
86 numeric_limits<IntegerType>::is_signed>::Type
87 Type;
88 };
89
90 template <typename IntegerType>
91 struct PositionOfSignBit {
92 static const size_t value = 8 * sizeof(IntegerType) - 1;
93 };
94
95
96 template <typename T>
97 bool HasSignBit(T x) {
98 // Cast to unsigned since right shift on signed is undefined.
99 return !!(static_cast<typename UnsignedType<T>::Type>(x) >>
100 PositionOfSignBit<T>::value);
101 }
102
103
104 // This wrapper undoes the standard integer promotions.
105 template <typename T>
106 T BinaryComplement(T x) {
107 return ~x;
108 }
109
110 template <typename T,
111 DstSignId DstSign = numeric_limits<T>::is_signed ?
112 DST_SIGNED : DST_UNSIGNED>
113 struct NegIntegerImpl;
114
115 template <typename T>
116 struct NegIntegerImpl<T, DST_SIGNED> {
117 static RangeCheckId run(T value, T* result) {
118 *result = -value;
119 // The negation of signed min is min, so catch that one.
120 return value != numeric_limits<T>::min() ? TYPE_VALID : TYPE_OVERFLOW;
121 }
122 };
123
124 template <typename T>
125 struct NegIntegerImpl<T, DST_UNSIGNED> {
126 static RangeCheckId run(T value, T* result) {
127 *result = static_cast<T>(
128 -static_cast<typename SignedType<T>::Type>(value));
129 // The only legal unsigned negation is zero.
130 return *result ? TYPE_UNDERFLOW : TYPE_VALID;
131 }
132 };
133
134 template <typename T>
135 RangeCheckId NegInteger(T value, T* result) {
136 return NegIntegerImpl<T>::run(value, result);
137 }
138
139
140 template <typename T>
141 RangeCheckId AddIntegers(T x, T y, T* result) {
142 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
143 // Since the value of x+y is undefined if we have a signed type, we compute
144 // it using the unsigned type of the same size.
145 typedef typename UnsignedType<T>::Type UnsignedDst;
146 UnsignedDst ux = static_cast<UnsignedDst>(x);
147 UnsignedDst uy = static_cast<UnsignedDst>(y);
148 UnsignedDst uresult = ux + uy;
149 *result = static_cast<T>(uresult);
150 // Addition is valid if the sign of (x + y) is equal to either that of x or
151 // that of y.
152 if (numeric_limits<T>::is_signed) {
153 if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
154 return TYPE_VALID;
155 // Direction of wrap is inverse of result sign.
156 return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW;
157 }
158 // Unsigned is either valid or overflow.
159 return BinaryComplement(x) >= y ? TYPE_VALID : TYPE_OVERFLOW;
160 }
161
162 template <typename T>
163 RangeCheckId SubIntegers(T x, T y, T* result) {
164 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
165 // Since the value of x+y is undefined if we have a signed type, we compute
166 // it using the unsigned type of the same size.
167 typedef typename UnsignedType<T>::Type UnsignedDst;
168 UnsignedDst ux = static_cast<UnsignedDst>(x);
169 UnsignedDst uy = static_cast<UnsignedDst>(y);
170 UnsignedDst uresult = ux - uy;
171 *result = static_cast<T>(uresult);
172 // Subtraction is valid if either x and y have same sign, or (x-y) and x have
173 // the same sign.
174 if (numeric_limits<T>::is_signed) {
175 if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
176 return TYPE_VALID;
177 // Direction of wrap is inverse of result sign.
178 return HasSignBit(uresult) ? TYPE_OVERFLOW : TYPE_UNDERFLOW;
179 }
180 // Unsigned is either valid or underflow.
181 return x >= y ? TYPE_VALID : TYPE_UNDERFLOW;
182 }
183
184 // Integer multiplication is a bit complicated. In the fast case we just
185 // we just promote to a twice wider type, and range check the result. In the
186 // slow case we need to manually check that the result won't be truncated by
187 // checking with division against the appropriate bound.
188 enum IntegerMathId {
189 FAST_MATH,
190 SLOW_MATH
191 };
192 template <typename T,
193 DstSignId DstSign = numeric_limits<T>::is_signed ?
194 DST_SIGNED : DST_UNSIGNED,
195 IntegerMathId MathType = sizeof(T)* 2 <= sizeof(uintmax_t) ?
196 FAST_MATH : SLOW_MATH>
197 struct MulIntegersImpl {};
198
199 template <typename T, DstSignId DstSign>
200 struct MulIntegersImpl<T, DstSign, FAST_MATH> {
201 static RangeCheckId run(T x, T y, T* result) {
202 typedef typename TwiceWiderType<T>::Type IntermediateType;
203 IntermediateType tmp = static_cast<IntermediateType>(x) *
204 static_cast<IntermediateType>(y);
205 *result = static_cast<T>(tmp);
206 return RangeCheck<T>(tmp);
207 }
208 };
209
210 template <typename T>
211 struct MulIntegersImpl<T, DST_SIGNED, SLOW_MATH> {
212 static RangeCheckId run(T x, T y, T* result) {
213 *result = x * y;
214
215 // if either side is zero then the result will be zero.
216 if (!(x || y))
217 return TYPE_VALID;
218
219 // Check each boundary based on the sign.
220 if (x > 0) {
221 if (y > 0)
222 return x <= numeric_limits<T>::max() / y ? TYPE_VALID : TYPE_OVERFLOW;
223 return y >= numeric_limits<T>::min() / x ? TYPE_VALID : TYPE_UNDERFLOW;
224 }
225
226 if (y > 0)
227 return x >= numeric_limits<T>::min() / y ? TYPE_VALID : TYPE_UNDERFLOW;
228 return y >= numeric_limits<T>::max() / x ? TYPE_VALID : TYPE_OVERFLOW;
229 }
230 };
231
232 template <typename T>
233 struct MulIntegersImpl<T, DST_UNSIGNED, SLOW_MATH> {
234 static RangeCheckId run(T x, T y, T* result) {
235 *result = x * y;
236 return (y == 0 || x <= numeric_limits<T>::max() / y) ?
237 TYPE_VALID : TYPE_OVERFLOW;
238 }
239 };
240
241 template <typename T>
242 RangeCheckId MulIntegers(T x, T y, T* result) {
243 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
244 return MulIntegersImpl<T>::run(x, y, result);
245 }
246
247
248 // Division is really easy. Just check for an invalid negation on signed min/-1.
249 template <typename T>
250 RangeCheckId DivIntegers(T x, T y, T* result) {
251 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
252 *result = x / y;
253 return (!numeric_limits<T>::is_signed || x != numeric_limits<T>::min()
254 || y != -1) ? TYPE_VALID : TYPE_OVERFLOW;
255 }
256
257 // Modulus is easy, but we split it into signed and unsigned to avoid warnings.
258 template <typename T,
259 DstSignId DstSign = numeric_limits<T>::is_signed ?
260 DST_SIGNED : DST_UNSIGNED>
261 struct ModIntegersImpl {};
262
263 template <typename T>
264 struct ModIntegersImpl<T, DST_SIGNED> {
265 static RangeCheckId run(T x, T y, T* result) {
266 *result = x % y;
267 return y > 0 ? TYPE_VALID : TYPE_INVALID;
268 }
269 };
270
271 template <typename T>
272 struct ModIntegersImpl<T, DST_UNSIGNED> {
273 static RangeCheckId run(T x, T y, T* result) {
274 *result = x % y;
275 return TYPE_VALID;
276 }
277 };
278
279 template <typename T>
280 RangeCheckId ModIntegers(T x, T y, T* result) {
281 COMPILE_ASSERT(numeric_limits<T>::is_integer, arguments_must_be_integers);
282 return ModIntegersImpl<T>::run(x, y, result);
283 }
284
285
286 // Floats carry around their validity state with them, but integers do not. So,
287 // we wrap the underlying value in a specialization in order to hide that detail
288 // and expose an interface via accessors.
289 enum NumericTypeId {
290 NUMERIC_INTEGER,
291 NUMERIC_FLOATING,
292 NUMERIC_UNKNOWN
293 };
294
295 template <typename NumericType>
296 struct GetNumericTypeId {
297 static const NumericTypeId value = numeric_limits<NumericType>::is_integer ?
298 NUMERIC_INTEGER : (numeric_limits<NumericType>::is_iec559 ?
299 NUMERIC_FLOATING : NUMERIC_UNKNOWN);
300 };
301
302 template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value>
303 class CheckedNumericState {};
304
305 // Integrals require quite a bit of additional housekeeping to manage state.
306 template <typename T>
307 class CheckedNumericState<T, NUMERIC_INTEGER> {
308 private:
309 T value_;
310 RangeCheckId validity_;
311
312 public:
313 template <typename Src, NumericTypeId Type>
314 friend class CheckedNumericState;
315
316 CheckedNumericState() : value_(0), validity_(TYPE_VALID) {}
317
318 template <typename Src>
319 CheckedNumericState(Src value, RangeCheckId validity) :
320 value_(value), validity_(static_cast<RangeCheckId>(
321 validity | RangeCheck<T>(value))) {
322 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
323 argument_must_be_numeric);
324 }
325
326 template <typename Src>
327 explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) :
328 value_(static_cast<T>(rhs.value_)), validity_(
329 static_cast<RangeCheckId>(rhs.validity() |
330 RangeCheck<T>(rhs.value_))) {
331 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
332 argument_must_be_numeric);
333 }
334
335 template <typename Src>
336 explicit CheckedNumericState(Src value) :
337 value_(static_cast<T>(value)), validity_(RangeCheck<T>(value)) {
338 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
339 argument_must_be_numeric);
340 }
Ryan Sleevi 2014/02/05 02:45:06 So, templated CTORS = generally a bad/tricky thing
341
342 RangeCheckId validity() const { return validity_; }
343 T value() const { return value_; }
344 };
345
346 // Floating points maintain their own validity, but need translation wrappers.
347 template <typename T>
348 class CheckedNumericState<T, NUMERIC_FLOATING> {
349 private:
350 T value_;
351
352 public:
353 template <typename Src, NumericTypeId Type>
354 friend class CheckedNumericState;
355
356 CheckedNumericState() : value_(0.0) {}
357
358 template <typename Src>
359 CheckedNumericState(Src value, RangeCheckId validity) {
360 // A non-integer specialization can get generated in non-optimized builds,
361 // but it should be impossible to trigger the code path.
362 DCHECK(numeric_limits<Src>::is_integer);
363
364 switch (RangeCheck<T>(value)) {
365 case TYPE_VALID:
366 value_ = static_cast<T>(value_);
367 break;
368
369 case TYPE_UNDERFLOW:
370 value_ = -numeric_limits<T>::infinity();
371 break;
372
373 case TYPE_OVERFLOW:
374 value_ = numeric_limits<T>::infinity();
375 break;
376
377 case TYPE_INVALID:
378 value_ = numeric_limits<T>::quiet_NaN();
379 break;
380
381 default:
382 NOTREACHED();
383 }
384 }
385
386 template <typename Src>
387 explicit CheckedNumericState(Src value) : value_(static_cast<T>(value)) {
388 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
389 argument_must_be_numeric);
390 }
391
392 template <typename Src>
393 explicit CheckedNumericState(const CheckedNumericState<Src>& rhs) :
394 value_(static_cast<T>(rhs.value_)) {
395 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
396 argument_must_be_numeric);
397 }
398
399 RangeCheckId validity() const {
400 return BASE_NUMERIC_RANGE_CHECK_RESULT(
401 value_ < numeric_limits<T>::max(),
402 value_ > -numeric_limits<T>::max());
403 }
404 T value() const { return value_; }
405 };
406
407 // In addition to wrapping the state, we also need to wrap all the arithmetic
408 // operations because we use a fast path for floating points, but a slower,
409 // checked path for integers.
410 template <typename T, NumericTypeId Type = GetNumericTypeId<T>::value>
411 class CheckedIntegerArithmetic {};
412
413 // Wrap the checked integer operations injected as a dependency.
414 template <typename T>
415 class CheckedIntegerArithmetic<T, NUMERIC_INTEGER> {
416 public:
417 static RangeCheckId Neg(T value, T* result) {
418 return NegInteger(value, result);
419 }
420 static RangeCheckId Add(T x, T y, T* result) {
421 return AddIntegers(x, y, result);
422 }
423 static RangeCheckId Sub(T x, T y, T* result) {
424 return SubIntegers(x, y, result);
425 }
426 static RangeCheckId Mul(T x, T y, T* result) {
427 return MulIntegers(x, y, result);
428 }
429 static RangeCheckId Div(T x, T y, T* result) {
430 return DivIntegers(x, y, result);
431 }
432 static RangeCheckId Mod(T x, T y, T* result) {
433 return ModIntegers(x, y, result);
434 }
435 };
436
437 // We never use these for floats, but the compiler needs to see an
438 // implementation.
439 template <typename T>
440 class CheckedIntegerArithmetic<T, NUMERIC_FLOATING> {
441 private:
442 static RangeCheckId not_implemented() {
443 NOTREACHED();
444 return TYPE_INVALID;
445 }
446
447 public:
448 static RangeCheckId Add(T, T, T*) { return not_implemented(); }
449 static RangeCheckId Sub(T, T, T*) { return not_implemented(); }
450 static RangeCheckId Mul(T, T, T*) { return not_implemented(); }
451 static RangeCheckId Div(T, T, T*) { return not_implemented(); }
452 static RangeCheckId Mod(T, T, T*) { return not_implemented(); }
453 static RangeCheckId Neg(T, T*) { return not_implemented(); }
454 };
455
456
457 // This template class implements all the logic and operators for safe numeric
458 // arithmetic and conversions.
459 template <typename T>
460 class CheckedNumeric {
461 private:
462 CheckedNumericState<T> state_;
463
464 public:
465 template <typename Src>
466 friend class CheckedNumeric;
467
468 CheckedNumeric() {}
469
470 template <typename Src>
471 CheckedNumeric(const CheckedNumeric<Src>& rhs) : state_(rhs.state_) {}
472
473 template <typename Src>
474 CheckedNumeric(Src value, RangeCheckId validity) : state_(value, validity) {}
475
476 template <typename Src>
477 CheckedNumeric(Src value) : state_(value) {}
478
479 RangeCheckId validity() const { return state_.validity(); }
480 bool IsValid() const { return validity() == TYPE_VALID; }
481 bool IsOverflow() const { return validity() == TYPE_OVERFLOW; }
482 bool IsUnderflow() const { return validity() == TYPE_UNDERFLOW; }
483 bool IsInvalid() const { return validity() == TYPE_INVALID; }
484
485 T ValueUnsafe() const { return state_.value(); }
486
487 template <typename FloatingType>
488 FloatingType ValueFloating() const {
489 if (std::numeric_limits<T>::is_iec559)
490 return ValueUnsafe();
491 return CheckedNumeric<FloatingType>(ValueUnsafe()).ValueUnsafe();
492 }
493
494 T ValueOrDie() const {
495 CHECK(IsValid());
496 return state_.value();
497 }
498
499 T ValueOrDefault(T default_value) const {
500 return IsValid() ? state_.value() : default_value;
501 }
502
503 // Friend all the operator overloads
504 template <typename Src>
505 CheckedNumeric& operator +=(Src rhs);
506
507 template <typename Src>
508 CheckedNumeric& operator -=(Src rhs);
509
510 template <typename Src>
511 CheckedNumeric& operator *=(Src rhs);
512
513 template <typename Src>
514 CheckedNumeric& operator /=(Src rhs);
515
516 template <typename Src>
517 CheckedNumeric& operator %=(Src rhs);
518
519 CheckedNumeric operator -() const {
520 // Negation is always valid for floating point
521 if (numeric_limits<T>::is_iec559)
522 return -state_.value();
523
524 T value;
525 RangeCheckId validity = static_cast<RangeCheckId>(
526 state_.validity() |
527 CheckedIntegerArithmetic<T>::Neg(state_.value(), &value));
528 return CheckedNumeric<T>(value, validity);
529 }
530
531 CheckedNumeric& operator++() {
532 *this += 1;
533 return *this;
534 }
535
536 CheckedNumeric operator++(int) {
537 CheckedNumeric tmp = *this;
538 *this += 1;
539 return tmp;
540 }
541
542 CheckedNumeric& operator--() {
543 *this -= 1;
544 return *this;
545 }
546
547 CheckedNumeric operator--(int) {
548 CheckedNumeric tmp = *this;
549 *this -= 1;
550 return tmp;
551 }
552
553 // These static functions behave like a convenience operator for casting to
554 // the desired numeric base type or CheckedNumeric type. As an optimization,
555 // a reference is returned when Src is the same type as T.
556 template <typename Src>
557 CheckedNumeric<T> static cast(Src u) {
558 COMPILE_ASSERT(numeric_limits<Src>::is_specialized,
559 argument_must_be_numeric);
560 return u;
561 }
562
563 template <typename Src>
564 CheckedNumeric<T> static cast(const CheckedNumeric<Src>& u) {
565 return u;
566 }
567
568 CheckedNumeric<T> static cast(const CheckedNumeric<T>& u) {
569 return u;
570 }
571 };
572
573 enum ArithmeticPromotionId {
574 LEFT_PROMOTION,
575 RIGHT_PROMOTION,
576 DEFAULT_PROMOTION
577 };
578
579 template <typename Lhs, typename Rhs,
580 ArithmeticPromotionId Promotion =
581 (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) ?
582 (MaxExponent<Lhs>::value > MaxExponent<int>::value ?
583 LEFT_PROMOTION : DEFAULT_PROMOTION) :
584 (MaxExponent<Rhs>::value > MaxExponent<int>::value ?
585 RIGHT_PROMOTION : DEFAULT_PROMOTION)>
586 struct ArithmeticPromotion {};
587
588 template <typename Lhs, typename Rhs>
589 struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
590 typedef Lhs Type;
591 };
592
593 template <typename Lhs, typename Rhs>
594 struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
595 typedef Rhs Type;
596 };
597
598 template <typename Lhs, typename Rhs>
599 struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
600 typedef int Type;
601 };
602
603 // Statically check if operations on the provided types can wrap, so we can skip
604 // the checked operations if they're not needed. An integer is safe if the
605 // destination type preserves sign and is wider.
606 template <typename T, typename Lhs, typename Rhs>
607 struct IsIntegerArithmeticSafe {
608 static const bool value = !numeric_limits<T>::is_iec559 &&
609 StaticRangeCheck<T, Lhs>::value == CONTAINS_RANGE &&
610 sizeof(T) >= (2 * sizeof(Lhs)) &&
611 StaticRangeCheck<T, Rhs>::value != CONTAINS_RANGE &&
612 sizeof(T) >= (2 * sizeof(Rhs));
613 };
614
615 // This is the boilerplate for the standard arithmetic operator overloads. A
616 // macro isn't the prettiest solution, but it beats rewriting these five times.
617 // Some details worth noting:
618 // * We employ the standard aritmetic promotions.
619 // * We skip the range checking operations for floating points.
620 // * We skip the range checking operations for integers with sufficient range.
621 #define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME,OP,COMPOUND_OP) \
622 /* Binary arithmetic operator for CheckedNumerics of the same type. */ \
623 template <typename T> \
624 CheckedNumeric<typename ArithmeticPromotion<T, T>::Type> \
625 operator OP(const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) { \
626 typedef typename ArithmeticPromotion<T, T>::Type Promotion; \
627 /* Floating point always takes the fast path */ \
628 if (numeric_limits<T>::is_iec559) \
629 return CheckedNumeric<T>(lhs.template ValueFloating<T>() OP \
630 rhs.template ValueFloating<T>()); \
631 if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \
632 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
633 static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \
634 T result = 0; \
635 RangeCheckId validity = \
636 CheckedIntegerArithmetic<Promotion>::NAME(lhs.ValueUnsafe(), \
637 rhs.ValueUnsafe(), \
638 &result); \
639 return CheckedNumeric<Promotion>(result, static_cast<RangeCheckId>( \
640 validity | lhs.validity() | rhs.validity())); \
641 } \
642 /* Binary arithmetic operator for CheckedNumeric of different type. */ \
643 template <typename T, typename Src> \
644 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
645 operator OP(const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) { \
646 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
647 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
648 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
649 static_cast<RangeCheckId>(rhs.validity() | lhs.validity())); \
650 return CheckedNumeric<Promotion>::cast(lhs) OP \
651 CheckedNumeric<Promotion>::cast(rhs); \
652 } \
653 /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
654 template <typename T, typename Src> \
655 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
656 operator OP(const CheckedNumeric<T> &lhs, Src rhs) { \
657 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
658 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
659 return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP \
660 rhs, lhs.validity()); \
661 return CheckedNumeric<Promotion>::cast(lhs) OP \
662 CheckedNumeric<Promotion>::cast(rhs); \
663 } \
664 /* Assignment arithmetic operator implementation from CheckedNumeric above. */ \
665 template <typename T> \
666 template <typename Src> \
667 CheckedNumeric<T>& \
668 CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \
669 *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
670 return *this; \
671 } \
672 /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
673 template <typename T, typename Src> \
674 CheckedNumeric<typename ArithmeticPromotion<T, Src>::Type> \
675 operator OP(Src lhs, const CheckedNumeric<T> &rhs) { \
676 typedef typename ArithmeticPromotion<T, Src>::Type Promotion; \
677 if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
678 return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \
679 rhs.validity()); \
680 return CheckedNumeric<Promotion>::cast(lhs) OP \
681 CheckedNumeric<Promotion>::cast(rhs); \
682 }
683
684 BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=)
685 BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=)
686 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=)
687 BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=)
688 BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=)
689
690 #undef BASE_NUMERIC_ARITHMETIC_OPERATORS
691
692 } // namespace internal
693 } // namespace base
694
695 #endif // SAFE_MATH_IMPL_H_
696
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