1 #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
2 #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
4 // Copyright (c) 2012 Robert Ramey
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
10 // Implemenation of arithmetic on "extended" integers.
11 // Extended integers are defined in terms of C++ primitive integers as
12 // a) an interger range
13 // b) extra elements +inf, -inf, indeterminate
15 // Integer operations are closed on the set of extended integers
16 // but operations are not necessarily associative when they result in the
17 // extensions +inf, -inf, and indeterminate
19 // in this code, the type "checked_result<T>" where T is some
20 // integer type is an "extended" integer.
24 #include <boost/logic/tribool.hpp>
26 #include "checked_result.hpp"
27 #include "checked_integer.hpp"
29 //////////////////////////////////////////////////////////////////////////
30 // the following idea of "value_type" is used by several of the operations
31 // defined by checked_result arithmetic.
34 namespace safe_numerics {
37 constexpr inline void display(const boost::safe_numerics::checked_result<T> & c){
39 case safe_numerics_error::success:
41 case safe_numerics_error::positive_overflow_error: // result is above representational maximum
43 case safe_numerics_error::negative_overflow_error: // result is below representational minimum
45 case safe_numerics_error::domain_error: // one operand is out of valid range
47 case safe_numerics_error::range_error: // result cannot be produced for this operation
49 case safe_numerics_error::precision_overflow_error: // result lost precision
51 case safe_numerics_error::underflow_error: // result is too small to be represented
53 case safe_numerics_error::negative_value_shift: // negative value in shift operator
55 case safe_numerics_error::negative_shift: // shift a negative value
57 case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size
59 case safe_numerics_error::uninitialized_value: // creating of uninitialized value
64 //////////////////////////////////////////////////////////////////////////
65 // implement C++ operators for check_result<T>
67 struct sum_value_type {
68 // characterization of various values
77 constexpr flag to_flag(const checked_result<T> & t) const {
78 switch(static_cast<safe_numerics_error>(t)){
79 case safe_numerics_error::success:
81 case safe_numerics_error::negative_overflow_error:
82 // result is below representational minimum
84 case safe_numerics_error::positive_overflow_error:
85 // result is above representational maximum
86 return greater_than_max;
92 constexpr sum_value_type(const checked_result<T> & t) :
95 constexpr operator std::uint8_t () const {
96 return static_cast<std::uint8_t>(m_flag);
102 typename std::enable_if<
103 std::is_integral<T>::value,
106 constexpr inline operator+(
107 const checked_result<T> & t,
108 const checked_result<T> & u
110 using value_type = sum_value_type;
111 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
113 // note major pain. Clang constexpr multi-dimensional array is fine.
114 // but gcc doesn't permit a multi-dimensional array to be be constexpr.
115 // so we need to some ugly gymnastics to make our system work for all
117 const enum safe_numerics_error result[order * order] = {
121 safe_numerics_error::success, // known_value,
122 safe_numerics_error::negative_overflow_error, // less_than_min,
123 safe_numerics_error::positive_overflow_error, // greater_than_max,
124 safe_numerics_error::range_error, // indeterminate,
126 // t == less_than_min,
129 safe_numerics_error::negative_overflow_error, // known_value,
130 safe_numerics_error::negative_overflow_error, // less_than_min,
131 safe_numerics_error::range_error, // greater_than_max,
132 safe_numerics_error::range_error, // indeterminate,
134 // t == greater_than_max,
137 safe_numerics_error::positive_overflow_error, // known_value,
138 safe_numerics_error::range_error, // less_than_min,
139 safe_numerics_error::positive_overflow_error, // greater_than_max,
140 safe_numerics_error::range_error, // indeterminate,
142 // t == indeterminate,
145 safe_numerics_error::range_error, // known_value,
146 safe_numerics_error::range_error, // less_than_min,
147 safe_numerics_error::range_error, // greater_than_max,
148 safe_numerics_error::range_error, // indeterminate,
152 const value_type tx(t);
153 const value_type ux(u);
155 const safe_numerics_error e = result[tx * order + ux];
156 if(safe_numerics_error::success == e)
157 return checked::add<T>(t, u);
158 return checked_result<T>(e, "addition result");
163 typename std::enable_if<
164 std::is_integral<T>::value,
167 constexpr inline operator+(
168 const checked_result<T> & t
173 // integers subtraction
175 typename std::enable_if<
176 std::is_integral<T>::value,
179 constexpr inline operator-(
180 const checked_result<T> & t,
181 const checked_result<T> & u
183 using value_type = sum_value_type;
184 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
186 constexpr const enum safe_numerics_error result[order * order] = {
190 safe_numerics_error::success, // known_value,
191 safe_numerics_error::positive_overflow_error, // less_than_min,
192 safe_numerics_error::negative_overflow_error, // greater_than_max,
193 safe_numerics_error::range_error, // indeterminate,
195 // t == less_than_min,
198 safe_numerics_error::negative_overflow_error, // known_value,
199 safe_numerics_error::range_error, // less_than_min,
200 safe_numerics_error::negative_overflow_error, // greater_than_max,
201 safe_numerics_error::range_error, // indeterminate,
203 // t == greater_than_max,
206 safe_numerics_error::positive_overflow_error, // known_value,
207 safe_numerics_error::positive_overflow_error, // less_than_min,
208 safe_numerics_error::range_error, // greater_than_max,
209 safe_numerics_error::range_error, // indeterminate,
211 // t == indeterminate,
214 safe_numerics_error::range_error, // known_value,
215 safe_numerics_error::range_error, // less_than_min,
216 safe_numerics_error::range_error, // greater_than_max,
217 safe_numerics_error::range_error, // indeterminate,
221 const value_type tx(t);
222 const value_type ux(u);
224 const safe_numerics_error e = result[tx * order + ux];
225 if(safe_numerics_error::success == e)
226 return checked::subtract<T>(t, u);
227 return checked_result<T>(e, "subtraction result");
232 typename std::enable_if<
233 std::is_integral<T>::value,
236 constexpr inline operator-(
237 const checked_result<T> & t
240 return checked_result<T>(0) - t;
243 struct product_value_type {
244 // characterization of various values
252 // count of number of cases for values
254 // temporary values for special cases
260 constexpr flag to_flag(const checked_result<T> & t) const {
261 switch(static_cast<safe_numerics_error>(t)){
262 case safe_numerics_error::success:
263 return (t < checked_result<T>(0))
265 : (t > checked_result<T>(0))
268 case safe_numerics_error::negative_overflow_error:
269 // result is below representational minimum
270 return less_than_min;
271 case safe_numerics_error::positive_overflow_error:
272 // result is above representational maximum
273 return greater_than_max;
275 return indeterminate;
279 constexpr product_value_type(const checked_result<T> & t) :
282 constexpr operator std::uint8_t () const {
283 return static_cast<std::uint8_t>(m_flag);
287 // integers multiplication
289 typename std::enable_if<
290 std::is_integral<T>::value,
293 constexpr inline operator*(
294 const checked_result<T> & t,
295 const checked_result<T> & u
297 using value_type = product_value_type;
298 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
300 constexpr const enum value_type::flag result[order * order] = {
301 // t == less_than_min
304 value_type::greater_than_max, // less_than_min,
305 value_type::greater_than_max, // less_than_zero,
306 value_type::zero, // zero,
307 value_type::less_than_min, // greater_than_zero,
308 value_type::less_than_min, // greater than max,
309 value_type::indeterminate, // indeterminate,
311 // t == less_than_zero,
314 value_type::greater_than_max, // less_than_min,
315 value_type::greater_than_zero, // less_than_zero,
316 value_type::zero, // zero,
317 value_type::less_than_zero, // greater_than_zero,
318 value_type::less_than_min, // greater than max,
319 value_type::indeterminate, // indeterminate,
324 value_type::zero, // less_than_min,
325 value_type::zero, // less_than_zero,
326 value_type::zero, // zero,
327 value_type::zero, // greater_than_zero,
328 value_type::zero, // greater than max,
329 value_type::indeterminate, // indeterminate,
331 // t == greater_than_zero,
334 value_type::less_than_min, // less_than_min,
335 value_type::less_than_zero, // less_than_zero,
336 value_type::zero, // zero,
337 value_type::greater_than_zero, // greater_than_zero,
338 value_type::greater_than_max, // greater than max,
339 value_type::indeterminate, // indeterminate,
341 // t == greater_than_max
343 value_type::less_than_min, // less_than_min,
344 value_type::less_than_min, // less_than_zero,
345 value_type::zero, // zero,
346 value_type::greater_than_max, // greater_than_zero,
347 value_type::greater_than_max, // greater than max,
348 value_type::indeterminate, // indeterminate,
350 // t == indeterminate
352 value_type::indeterminate, // less_than_min,
353 value_type::indeterminate, // less_than_zero,
354 value_type::indeterminate, // zero,
355 value_type::indeterminate, // greater_than_zero,
356 value_type::indeterminate, // greater than max,
357 value_type::indeterminate, // indeterminate,
361 const value_type tx(t);
362 const value_type ux(u);
364 switch(result[tx * order + ux]){
365 case value_type::less_than_min:
366 return safe_numerics_error::negative_overflow_error;
367 case value_type::zero:
369 case value_type::greater_than_max:
370 return safe_numerics_error::positive_overflow_error;
371 case value_type::less_than_zero:
372 case value_type::greater_than_zero:
373 return checked::multiply<T>(t, u);
374 case value_type::indeterminate:
375 return safe_numerics_error::range_error;
379 return checked_result<T>(0); // to suppress msvc warning
384 typename std::enable_if<
385 std::is_integral<T>::value,
388 constexpr inline operator/(
389 const checked_result<T> & t,
390 const checked_result<T> & u
392 using value_type = product_value_type;
393 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
395 constexpr const enum value_type::flag result[order * order] = {
396 // t == less_than_min
399 value_type::indeterminate, // less_than_min,
400 value_type::greater_than_max, // less_than_zero,
401 value_type::less_than_min, // zero,
402 value_type::less_than_min, // greater_than_zero,
403 value_type::less_than_min, // greater than max,
404 value_type::indeterminate, // indeterminate,
406 // t == less_than_zero,
409 value_type::zero, // less_than_min,
410 value_type::greater_than_zero, // less_than_zero,
411 value_type::less_than_min, // zero,
412 value_type::less_than_zero, // greater_than_zero,
413 value_type::zero, // greater than max,
414 value_type::indeterminate, // indeterminate,
419 value_type::zero, // less_than_min,
420 value_type::zero, // less_than_zero,
421 value_type::indeterminate, // zero,
422 value_type::zero, // greater_than_zero,
423 value_type::zero, // greater than max,
424 value_type::indeterminate, // indeterminate,
426 // t == greater_than_zero,
429 value_type::zero, // less_than_min,
430 value_type::less_than_zero, // less_than_zero,
431 value_type::greater_than_max, // zero,
432 value_type::greater_than_zero, // greater_than_zero,
433 value_type::zero, // greater than max,
434 value_type::indeterminate, // indeterminate,
436 // t == greater_than_max
438 value_type::less_than_min, // less_than_min,
439 value_type::less_than_min, // less_than_zero,
440 value_type::greater_than_max, // zero,
441 value_type::greater_than_max, // greater_than_zero,
442 value_type::indeterminate, // greater than max,
443 value_type::indeterminate, // indeterminate,
445 // t == indeterminate
447 value_type::indeterminate, // less_than_min,
448 value_type::indeterminate, // less_than_zero,
449 value_type::indeterminate, // zero,
450 value_type::indeterminate, // greater_than_zero,
451 value_type::indeterminate, // greater than max,
452 value_type::indeterminate, // indeterminate,
456 const value_type tx(t);
457 const value_type ux(u);
459 switch(result[tx * order + ux]){
460 case value_type::less_than_min:
461 return safe_numerics_error::negative_overflow_error;
462 case value_type::zero:
464 case value_type::greater_than_max:
465 return safe_numerics_error::positive_overflow_error;
466 case value_type::less_than_zero:
467 case value_type::greater_than_zero:
468 return checked::divide<T>(t, u);
469 case value_type::indeterminate:
470 return safe_numerics_error::range_error;
474 return checked_result<T>(0); // to suppress msvc warning
479 typename std::enable_if<
480 std::is_integral<T>::value,
483 constexpr inline operator%(
484 const checked_result<T> & t,
485 const checked_result<T> & u
487 using value_type = product_value_type;
488 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
490 constexpr const enum value_type::flag result[order * order] = {
491 // t == less_than_min
494 value_type::indeterminate, // less_than_min,
495 value_type::z_value, // less_than_zero,
496 value_type::indeterminate, // zero,
497 value_type::z_value, // greater_than_zero,
498 value_type::indeterminate, // greater than max,
499 value_type::indeterminate, // indeterminate,
501 // t == less_than_zero,
504 value_type::t_value, // less_than_min,
505 value_type::greater_than_zero, // less_than_zero,
506 value_type::indeterminate, // zero,
507 value_type::less_than_zero, // greater_than_zero,
508 value_type::t_value, // greater than max,
509 value_type::indeterminate, // indeterminate,
514 value_type::zero, // less_than_min,
515 value_type::zero, // less_than_zero,
516 value_type::indeterminate, // zero,
517 value_type::zero, // greater_than_zero,
518 value_type::zero, // greater than max,
519 value_type::indeterminate, // indeterminate,
521 // t == greater_than_zero,
524 value_type::t_value, // less_than_min,
525 value_type::less_than_zero, // less_than_zero,
526 value_type::indeterminate, // zero,
527 value_type::greater_than_zero, // greater_than_zero,
528 value_type::t_value, // greater than max,
529 value_type::indeterminate, // indeterminate,
531 // t == greater_than_max
533 value_type::indeterminate, // less_than_min,
534 value_type::u_value, // less_than_zero,
535 value_type::indeterminate, // zero,
536 value_type::u_value, // greater_than_zero,
537 value_type::indeterminate, // greater than max,
538 value_type::indeterminate, // indeterminate,
540 // t == indeterminate
542 value_type::indeterminate, // less_than_min,
543 value_type::indeterminate, // less_than_zero,
544 value_type::indeterminate, // zero,
545 value_type::indeterminate, // greater_than_zero,
546 value_type::indeterminate, // greater than max,
547 value_type::indeterminate, // indeterminate,
551 const value_type tx(t);
552 const value_type ux(u);
554 switch(result[tx * order + ux]){
555 case value_type::zero:
557 case value_type::less_than_zero:
558 case value_type::greater_than_zero:
559 return checked::modulus<T>(t, u);
560 case value_type::indeterminate:
561 return safe_numerics_error::range_error;
562 case value_type::t_value:
564 case value_type::u_value:
565 return checked::subtract<T>(u, 1);
566 case value_type::z_value:
567 return checked::subtract<T>(1, u);
568 case value_type::greater_than_max:
569 case value_type::less_than_min:
573 // suppress msvc warning
574 return checked_result<T>(0);
577 // comparison operators
580 constexpr boost::logic::tribool operator<(
581 const checked_result<T> & t,
582 const checked_result<T> & u
584 using value_type = sum_value_type;
585 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
587 // the question arises about how to order values of type greater_than_min.
588 // that is: what should greater_than_min < greater_than_min return.
590 // a) return indeterminate because we're talking about the "true" values for
591 // which greater_than_min is a placholder.
593 // b) return false because the two values are "equal"
595 // for our purposes, a) seems the better interpretation.
597 enum class result_type : std::uint8_t {
603 constexpr const result_type resultx[order * order]{
607 result_type::runtime, // known_value,
608 result_type::false_value, // less_than_min,
609 result_type::true_value, // greater_than_max,
610 result_type::indeterminate, // indeterminate,
612 // t == less_than_min
615 result_type::true_value, // known_value,
616 result_type::indeterminate, // less_than_min, see above argument
617 result_type::true_value, // greater_than_max,
618 result_type::indeterminate, // indeterminate,
620 // t == greater_than_max
623 result_type::false_value, // known_value,
624 result_type::false_value, // less_than_min,
625 result_type::indeterminate, // greater_than_max, see above argument
626 result_type::indeterminate, // indeterminate,
628 // t == indeterminate
631 result_type::indeterminate, // known_value,
632 result_type::indeterminate, // less_than_min,
633 result_type::indeterminate, // greater_than_max,
634 result_type::indeterminate, // indeterminate,
638 const value_type tx(t);
639 const value_type ux(u);
641 switch(resultx[tx * order + ux]){
642 case result_type::runtime:
643 return static_cast<const T &>(t) < static_cast<const T &>(u);
644 case result_type::false_value:
646 case result_type::true_value:
648 case result_type::indeterminate:
649 return boost::logic::indeterminate;
657 constexpr boost::logic::tribool
659 const checked_result<T> & t,
660 const checked_result<T> & u
666 constexpr boost::logic::tribool
668 const checked_result<T> & t,
669 const checked_result<T> & u
675 constexpr boost::logic::tribool
677 const checked_result<T> & t,
678 const checked_result<T> & u
684 constexpr boost::logic::tribool
686 const checked_result<T> & t,
687 const checked_result<T> & u
689 using value_type = sum_value_type;
690 constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
692 enum class result_type : std::uint8_t {
699 constexpr const result_type result[order * order]{
703 result_type::runtime, // known_value,
704 result_type::false_value, // less_than_min,
705 result_type::false_value, // greater_than_max,
706 result_type::indeterminate, // indeterminate,
708 // t == less_than_min
711 result_type::false_value, // known_value,
712 result_type::indeterminate, // less_than_min,
713 result_type::false_value, // greater_than_max,
714 result_type::indeterminate, // indeterminate,
716 // t == greater_than_max
719 result_type::false_value, // known_value,
720 result_type::false_value, // less_than_min,
721 result_type::indeterminate, // greater_than_max,
722 result_type::indeterminate, // indeterminate,
724 // t == indeterminate
727 result_type::indeterminate, // known_value,
728 result_type::indeterminate, // less_than_min,
729 result_type::indeterminate, // greater_than_max,
730 result_type::indeterminate, // indeterminate,
734 const value_type tx(t);
735 const value_type ux(u);
737 switch(result[tx * order + ux]){
738 case result_type::runtime:
739 return static_cast<const T &>(t) == static_cast<const T &>(u);
740 case result_type::false_value:
742 case result_type::true_value:
744 case result_type::indeterminate:
745 return boost::logic::indeterminate;
749 // suppress msvc warning - not all control paths return a value
754 constexpr boost::logic::tribool
756 const checked_result<T> & t,
757 const checked_result<T> & u
763 typename std::enable_if<
764 std::is_integral<T>::value,
767 constexpr inline operator>>(
768 const checked_result<T> & t,
769 const checked_result<T> & u
773 typename std::enable_if<
774 std::is_integral<T>::value,
777 constexpr inline operator~(
778 const checked_result<T> & t
785 typename std::enable_if<
786 std::is_integral<T>::value,
789 constexpr inline operator<<(
790 const checked_result<T> & t,
791 const checked_result<T> & u
793 using value_type = product_value_type;
794 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
796 constexpr const std::uint8_t result[order * order] = {
797 // t == less_than_min
800 1, // -1, // less_than_min,
801 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
802 2, // safe_numerics_error::negative_overflow_error, // zero,
803 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
804 2, // safe_numerics_error::negative_overflow_error, // greater than max,
805 1, // safe_numerics_error::range_error, // indeterminate,
807 // t == less_than_zero,
810 3, // -1, // less_than_min,
811 4, // - (-t >> -u), // less_than_zero,
812 5, // safe_numerics_error::negative_overflow_error, // zero,
813 6, // - (-t << u), // greater_than_zero,
814 2, // safe_numerics_error::negative_overflow_error, // greater than max,
815 1, // safe_numerics_error::range_error, // indeterminate,
820 3, // 0 // less_than_min,
821 3, // 0 // less_than_zero,
823 3, // 0, // greater_than_zero,
824 3, // 0, // greater than max,
825 3, // safe_numerics_error::range_error, // indeterminate,
827 // t == greater_than_zero,
830 3, // 0, // less_than_min,
831 7, // t << -u, // less_than_zero,
833 8, // t << u // greater_than_zero,
834 9, // safe_numerics_error::positive_overflow_error, // greater than max,
835 1, // safe_numerics_error::range_error, // indeterminate,
837 // t == greater_than_max
840 1, // safe_numerics_error::range_error, // less_than_min,
841 9, // safe_numerics_error::positive_overflow_error), // less_than_zero,
842 9, // safe_numerics_error::positive_overflow_error, // zero,
843 9, // safe_numerics_error::positive_overflow_error), // greater_than_zero,
844 9, // safe_numerics_error::positive_overflow_error, // greater than max,
845 1, // safe_numerics_error::range_error, // indeterminate,
847 // t == indeterminate
849 1, // safe_numerics_error::range_error, // indeterminate,
850 1, // safe_numerics_error::range_error, // indeterminate,
851 1, // safe_numerics_error::range_error, // indeterminate,
852 1, // safe_numerics_error::range_error, // indeterminate,
853 1, // safe_numerics_error::range_error, // indeterminate,
854 1, // safe_numerics_error::range_error, // indeterminate,
858 const value_type tx(t);
859 const value_type ux(u);
860 assert(tx * order + ux < order * order);
862 // I had a switch(i) statment here - but it results in an ICE
863 // on multiple versions of gcc. So make the equivalent in
864 // nested if statments - should be the same (more or less)
866 const unsigned int i = result[tx * order + ux];
869 return safe_numerics_error::range_error;
873 return safe_numerics_error::negative_overflow_error;
877 return checked_result<T>(0);
878 // the following gymnastics are to handle the case where
879 // a value is changed from a negative to a positive number.
880 // For example, and 8 bit number t == -128. Then -t also
881 // equals -128 since 128 cannot be held in an 8 bit signed
885 if(4 == i){ // - (-t >> -u)
886 assert(static_cast<bool>(t < checked_result<T>(0)));
887 assert(static_cast<bool>(u < checked_result<T>(0)));
895 if(6 == i){ // - (-t << u)
896 assert(static_cast<bool>(t < checked_result<T>(0)));
897 assert(static_cast<bool>(u > checked_result<T>(0)));
898 const checked_result<T> temp_t = t * checked_result<T>(2);
899 const checked_result<T> temp_u = u - checked_result<T>(1);
900 return - (-temp_t << temp_u);
903 if(7 == i){ // t >> -u
904 assert(static_cast<bool>(t > checked_result<T>(0)));
905 assert(static_cast<bool>(u < checked_result<T>(0)));
909 if(8 == i){ // t << u
910 assert(static_cast<bool>(t > checked_result<T>(0)));
911 assert(static_cast<bool>(u > checked_result<T>(0)));
912 checked_result<T> r = checked::left_shift<T>(t, u);
913 return (r.m_e == safe_numerics_error::shift_too_large)
914 ? checked_result<T>(safe_numerics_error::positive_overflow_error)
919 return safe_numerics_error::positive_overflow_error;
924 return checked_result<T>(0); // to suppress msvc warning
928 typename std::enable_if<
929 std::is_integral<T>::value,
932 constexpr inline operator>>(
933 const checked_result<T> & t,
934 const checked_result<T> & u
936 using value_type = product_value_type;
937 const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
939 const std::uint8_t result[order * order] = {
940 // t == less_than_min
943 2, // safe_numerics_error::negative_overflow_error, // less_than_min,
944 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
945 2, // safe_numerics_error::negative_overflow_error, // zero,
946 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
947 1, // safe_numerics_error::range_error, // greater than max,
948 1, // safe_numerics_error::range_error, // indeterminate,
950 // t == less_than_zero,
953 2, // safe_numerics_error::negative_overflow_error // less_than_min,
954 4, // - (-t << -u), // less_than_zero,
955 5, // safe_numerics_error::negative_overflow_error. // zero,
956 6, // - (-t >> u), // greater_than_zero,
957 3, // 0, ? or -1 // greater than max,
958 1, // safe_numerics_error::range_error, // indeterminate,
963 3, // 0 // less_than_min,
964 3, // 0 // less_than_zero,
966 3, // 0, // greater_than_zero,
967 3, // 0, // greater than max,
968 3, // safe_numerics_error::range_error, // indeterminate,
970 // t == greater_than_zero,
973 9, // safe_numerics_error::positive_overflow_error // less_than_min,
974 7, // t << -u, // less_than_zero,
976 8, // t >> u // greater_than_zero,
977 3, // 0, // greater than max,
978 1, // safe_numerics_error::range_error, // indeterminate,
980 // t == greater_than_max
983 9, // safe_numerics_error::positive_overflow_error, // less_than_min,
984 9, // safe_numerics_error::positive_overflow_error, // less_than_zero,
985 9, // safe_numerics_error::positive_overflow_error, // zero,
986 9, // safe_numerics_error::positive_overflow_error, // greater_than_zero,
987 1, // safe_numerics_error::range_error, // greater than max,
988 1, // safe_numerics_error::range_error, // indeterminate,
990 // t == indeterminate
992 1, // safe_numerics_error::range_error, // indeterminate,
993 1, // safe_numerics_error::range_error, // indeterminate,
994 1, // safe_numerics_error::range_error, // indeterminate,
995 1, // safe_numerics_error::range_error, // indeterminate,
996 1, // safe_numerics_error::range_error, // indeterminate,
997 1, // safe_numerics_error::range_error, // indeterminate,
1001 const value_type tx(t);
1002 const value_type ux(u);
1003 assert(tx * order + ux < order * order);
1005 // I had a switch(i) statment here - but it results in an ICE
1006 // on multiple versions of gcc. So make the equivalent in
1007 // nested if statments - should be the same (more or less)
1009 const unsigned int i = result[tx * order + ux];
1012 return safe_numerics_error::range_error;
1016 return safe_numerics_error::negative_overflow_error;
1020 return checked_result<T>(0);
1023 if(4 == i){ // - (-t << -u)
1024 assert(static_cast<bool>(t < checked_result<T>(0)));
1025 assert(static_cast<bool>(u < checked_result<T>(0)));
1033 if(6 == i){ // - (-t >> u)
1034 assert(static_cast<bool>(t < checked_result<T>(0)));
1035 assert(static_cast<bool>(u > checked_result<T>(0)));
1036 const checked_result<T> temp_t = t / checked_result<T>(2);
1037 const checked_result<T> temp_u = u - checked_result<T>(1);
1038 return - (-temp_t >> temp_u);
1041 if(7 == i){ // t << -u,
1042 assert(static_cast<bool>(t > checked_result<T>(0)));
1043 assert(static_cast<bool>(u < checked_result<T>(0)));
1047 if(8 == i){ // t >> u
1048 assert(static_cast<bool>(t > checked_result<T>(0)));
1049 assert(static_cast<bool>(u > checked_result<T>(0)));
1050 checked_result<T> r = checked::right_shift<T>(t, u);
1051 return (r.m_e == safe_numerics_error::shift_too_large)
1052 ? checked_result<T>(0)
1057 return safe_numerics_error::positive_overflow_error;
1062 return checked_result<T>(0); // to suppress msvc warning
1066 typename std::enable_if<
1067 std::is_integral<T>::value,
1070 constexpr inline operator|(
1071 const checked_result<T> & t,
1072 const checked_result<T> & u
1075 t.exception() || u.exception()
1076 ? checked_result<T>(safe_numerics_error::range_error)
1077 : checked::bitwise_or<T>(
1083 typename std::enable_if<
1084 std::is_integral<T>::value,
1087 constexpr inline operator^(
1088 const checked_result<T> & t,
1089 const checked_result<T> & u
1092 t.exception() || u.exception()
1093 ? checked_result<T>(safe_numerics_error::range_error)
1094 : checked::bitwise_xor<T>(
1101 typename std::enable_if<
1102 std::is_integral<T>::value,
1105 constexpr inline operator&(
1106 const checked_result<T> & t,
1107 const checked_result<T> & u
1110 t.exception() || u.exception()
1111 ? checked_result<T>(safe_numerics_error::range_error)
1112 : checked::bitwise_and<T>(
1125 template<typename CharT, typename Traits, typename R>
1126 inline std::basic_ostream<CharT, Traits> & operator<<(
1127 std::basic_ostream<CharT, Traits> & os,
1128 const boost::safe_numerics::checked_result<R> & r
1130 bool e = r.exception();
1133 os << static_cast<R>(r);
1135 os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1139 template<typename CharT, typename Traits>
1140 inline std::basic_ostream<CharT, Traits> & operator<<(
1141 std::basic_ostream<CharT, Traits> & os,
1142 const boost::safe_numerics::checked_result<signed char> & r
1144 bool e = r.exception();
1147 os << static_cast<std::int16_t>(r);
1149 os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1153 template<typename CharT, typename Traits, typename R>
1154 inline std::basic_istream<CharT, Traits> & operator>>(
1155 std::basic_istream<CharT, Traits> & is,
1156 boost::safe_numerics::checked_result<R> & r
1161 is >> static_cast<R>(r);
1163 is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1167 template<typename CharT, typename Traits>
1168 inline std::basic_istream<CharT, Traits> & operator>>(
1169 std::basic_istream<CharT, Traits> & is,
1170 boost::safe_numerics::checked_result<signed char> & r
1177 r.m_contents.m_r = static_cast<signed char>(i);
1180 is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1186 /////////////////////////////////////////////////////////////////
1187 // numeric limits for checked<R>
1194 class numeric_limits<boost::safe_numerics::checked_result<R> >
1195 : public std::numeric_limits<R>
1197 using this_type = boost::safe_numerics::checked_result<R>;
1199 constexpr static this_type min() noexcept {
1200 return this_type(std::numeric_limits<R>::min());
1202 constexpr static this_type max() noexcept {
1203 return this_type(std::numeric_limits<R>::max());
1209 #endif // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS