Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:59:42

0001 #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
0002 #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
0003 
0004 //  Copyright (c) 2012 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 // Implemenation of arithmetic on "extended" integers.
0011 // Extended integers are defined in terms of C++ primitive integers as
0012 //     a) an interger range
0013 //     b) extra elements +inf, -inf, indeterminate
0014 //
0015 // Integer operations are closed on the set of extended integers
0016 // but operations are not necessarily associative when they result in the
0017 // extensions +inf, -inf, and indeterminate
0018 //
0019 // in this code, the type "checked_result<T>" where T is some
0020 // integer type is an "extended" integer.
0021 
0022 #include <cassert>
0023 
0024 #include <boost/logic/tribool.hpp>
0025 
0026 #include "checked_result.hpp"
0027 #include "checked_integer.hpp"
0028 
0029 //////////////////////////////////////////////////////////////////////////
0030 // the following idea of "value_type" is used by several of the operations
0031 // defined by checked_result arithmetic.
0032 
0033 namespace boost {
0034 namespace safe_numerics {
0035 
0036 template<typename T>
0037 constexpr inline void display(const boost::safe_numerics::checked_result<T> & c){
0038     switch(c.m_e){
0039     case safe_numerics_error::success:
0040         std::terminate();
0041     case safe_numerics_error::positive_overflow_error:    // result is above representational maximum
0042         std::terminate();
0043     case safe_numerics_error::negative_overflow_error:    // result is below representational minimum
0044         std::terminate();
0045     case safe_numerics_error::domain_error:               // one operand is out of valid range
0046         std::terminate();
0047     case safe_numerics_error::range_error:                // result cannot be produced for this operation
0048         std::terminate();
0049     case safe_numerics_error::precision_overflow_error:   // result lost precision
0050         std::terminate();
0051     case safe_numerics_error::underflow_error:            // result is too small to be represented
0052         std::terminate();
0053     case safe_numerics_error::negative_value_shift:       // negative value in shift operator
0054         std::terminate();
0055     case safe_numerics_error::negative_shift:             // shift a negative value
0056         std::terminate();
0057     case safe_numerics_error::shift_too_large:            // l/r shift exceeds variable size
0058         std::terminate();
0059     case safe_numerics_error::uninitialized_value:        // creating of uninitialized value
0060         std::terminate();
0061     }
0062 }
0063 
0064 //////////////////////////////////////////////////////////////////////////
0065 // implement C++ operators for check_result<T>
0066 
0067 struct sum_value_type {
0068     // characterization of various values
0069     const enum flag {
0070         known_value = 0,
0071         less_than_min,
0072         greater_than_max,
0073         indeterminate,
0074         count
0075     } m_flag;
0076     template<class T>
0077     constexpr flag to_flag(const checked_result<T> & t) const {
0078         switch(static_cast<safe_numerics_error>(t)){
0079         case safe_numerics_error::success:
0080             return known_value;
0081         case safe_numerics_error::negative_overflow_error:
0082             // result is below representational minimum
0083             return less_than_min;
0084         case safe_numerics_error::positive_overflow_error:
0085             // result is above representational maximum
0086             return greater_than_max;
0087         default:
0088             return indeterminate;
0089         }
0090     }
0091     template<class T>
0092     constexpr sum_value_type(const checked_result<T> & t) :
0093         m_flag(to_flag(t))
0094     {}
0095     constexpr operator std::uint8_t () const {
0096         return static_cast<std::uint8_t>(m_flag);
0097     }
0098 };
0099 
0100 // integers addition
0101 template<class T>
0102 typename std::enable_if<
0103     std::is_integral<T>::value,
0104     checked_result<T>
0105 >::type
0106 constexpr inline operator+(
0107     const checked_result<T> & t,
0108     const checked_result<T> & u
0109 ){
0110     using value_type = sum_value_type;
0111     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0112 
0113     // note major pain.  Clang constexpr multi-dimensional array is fine.
0114     // but gcc doesn't permit a multi-dimensional array to be be constexpr.
0115     // so we need to some ugly gymnastics to make our system work for all
0116     // all systems.
0117     const enum safe_numerics_error result[order * order] = {
0118         // t == known_value
0119         //{
0120             // u == ...
0121             safe_numerics_error::success,                   // known_value,
0122             safe_numerics_error::negative_overflow_error,   // less_than_min,
0123             safe_numerics_error::positive_overflow_error,   // greater_than_max,
0124             safe_numerics_error::range_error,               // indeterminate,
0125         //},
0126         // t == less_than_min,
0127         //{
0128             // u == ...
0129             safe_numerics_error::negative_overflow_error,   // known_value,
0130             safe_numerics_error::negative_overflow_error,   // less_than_min,
0131             safe_numerics_error::range_error,               // greater_than_max,
0132             safe_numerics_error::range_error,               // indeterminate,
0133         //},
0134         // t == greater_than_max,
0135         //{
0136             // u == ...
0137             safe_numerics_error::positive_overflow_error,   // known_value,
0138             safe_numerics_error::range_error,               // less_than_min,
0139             safe_numerics_error::positive_overflow_error,   // greater_than_max,
0140             safe_numerics_error::range_error,               // indeterminate,
0141         //},
0142         // t == indeterminate,
0143         //{
0144             // u == ...
0145             safe_numerics_error::range_error,      // known_value,
0146             safe_numerics_error::range_error,      // less_than_min,
0147             safe_numerics_error::range_error,      // greater_than_max,
0148             safe_numerics_error::range_error,      // indeterminate,
0149         //},
0150     };
0151 
0152     const value_type tx(t);
0153     const value_type ux(u);
0154 
0155     const safe_numerics_error e = result[tx * order + ux];
0156     if(safe_numerics_error::success == e)
0157         return checked::add<T>(t, u);
0158     return checked_result<T>(e, "addition result");
0159 }
0160 
0161 // unary +
0162 template<class T>
0163 typename std::enable_if<
0164     std::is_integral<T>::value,
0165     checked_result<T>
0166 >::type
0167 constexpr inline operator+(
0168     const checked_result<T> & t
0169 ){
0170     return t;
0171 }
0172 
0173 // integers subtraction
0174 template<class T>
0175 typename std::enable_if<
0176     std::is_integral<T>::value,
0177     checked_result<T>
0178 >::type
0179 constexpr inline operator-(
0180     const checked_result<T> & t,
0181     const checked_result<T> & u
0182 ){
0183     using value_type = sum_value_type;
0184     constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0185 
0186     constexpr const enum safe_numerics_error result[order * order] = {
0187         // t == known_value
0188         //{
0189             // u == ...
0190             safe_numerics_error::success,                   // known_value,
0191             safe_numerics_error::positive_overflow_error,   // less_than_min,
0192             safe_numerics_error::negative_overflow_error,   // greater_than_max,
0193             safe_numerics_error::range_error,               // indeterminate,
0194         //},
0195         // t == less_than_min,
0196         //{
0197             // u == ...
0198             safe_numerics_error::negative_overflow_error,   // known_value,
0199             safe_numerics_error::range_error,               // less_than_min,
0200             safe_numerics_error::negative_overflow_error,   // greater_than_max,
0201             safe_numerics_error::range_error,               // indeterminate,
0202         //},
0203         // t == greater_than_max,
0204         //{
0205             // u == ...
0206             safe_numerics_error::positive_overflow_error,   // known_value,
0207             safe_numerics_error::positive_overflow_error,   // less_than_min,
0208             safe_numerics_error::range_error,               // greater_than_max,
0209             safe_numerics_error::range_error,               // indeterminate,
0210         //},
0211         // t == indeterminate,
0212         //{
0213             // u == ...
0214             safe_numerics_error::range_error,               // known_value,
0215             safe_numerics_error::range_error,               // less_than_min,
0216             safe_numerics_error::range_error,               // greater_than_max,
0217             safe_numerics_error::range_error,               // indeterminate,
0218         //},
0219     };
0220 
0221     const value_type tx(t);
0222     const value_type ux(u);
0223 
0224     const safe_numerics_error e = result[tx * order + ux];
0225     if(safe_numerics_error::success == e)
0226         return checked::subtract<T>(t, u);
0227     return checked_result<T>(e, "subtraction result");
0228 }
0229 
0230 // unary -
0231 template<class T>
0232 typename std::enable_if<
0233     std::is_integral<T>::value,
0234     checked_result<T>
0235 >::type
0236 constexpr inline operator-(
0237     const checked_result<T> & t
0238 ){
0239 //    assert(false);
0240     return checked_result<T>(0) - t;
0241 }
0242 
0243 struct product_value_type {
0244     // characterization of various values
0245     const enum flag {
0246         less_than_min = 0,
0247         less_than_zero,
0248         zero,
0249         greater_than_zero,
0250         greater_than_max,
0251         indeterminate,
0252         // count of number of cases for values
0253         count,
0254         // temporary values for special cases
0255         t_value,
0256         u_value,
0257         z_value
0258     } m_flag;
0259     template<class T>
0260     constexpr flag to_flag(const checked_result<T> & t) const {
0261         switch(static_cast<safe_numerics_error>(t)){
0262         case safe_numerics_error::success:
0263             return (t < checked_result<T>(0))
0264                 ? less_than_zero
0265                 : (t > checked_result<T>(0))
0266                 ? greater_than_zero
0267                 : zero;
0268         case safe_numerics_error::negative_overflow_error:
0269             // result is below representational minimum
0270             return less_than_min;
0271         case safe_numerics_error::positive_overflow_error:
0272             // result is above representational maximum
0273             return greater_than_max;
0274         default:
0275             return indeterminate;
0276         }
0277     }
0278     template<class T>
0279     constexpr product_value_type(const checked_result<T> & t) :
0280         m_flag(to_flag(t))
0281     {}
0282     constexpr operator std::uint8_t () const {
0283         return static_cast<std::uint8_t>(m_flag);
0284     }
0285 };
0286 
0287 // integers multiplication
0288 template<class T>
0289 typename std::enable_if<
0290     std::is_integral<T>::value,
0291     checked_result<T>
0292 >::type
0293 constexpr inline operator*(
0294     const checked_result<T> & t,
0295     const checked_result<T> & u
0296 ){
0297     using value_type = product_value_type;
0298     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0299 
0300     constexpr const enum value_type::flag result[order * order] = {
0301         // t == less_than_min
0302         //{
0303             // u == ...
0304             value_type::greater_than_max,   // less_than_min,
0305             value_type::greater_than_max,   // less_than_zero,
0306             value_type::zero,               // zero,
0307             value_type::less_than_min,      // greater_than_zero,
0308             value_type::less_than_min,      // greater than max,
0309             value_type::indeterminate,      // indeterminate,
0310         //},
0311         // t == less_than_zero,
0312         //{
0313             // u == ...
0314             value_type::greater_than_max,   // less_than_min,
0315             value_type::greater_than_zero,  // less_than_zero,
0316             value_type::zero,               // zero,
0317             value_type::less_than_zero,     // greater_than_zero,
0318             value_type::less_than_min,      // greater than max,
0319             value_type::indeterminate,      // indeterminate,
0320         //},
0321         // t == zero,
0322         //{
0323             // u == ...
0324             value_type::zero,               // less_than_min,
0325             value_type::zero,               // less_than_zero,
0326             value_type::zero,               // zero,
0327             value_type::zero,               // greater_than_zero,
0328             value_type::zero,               // greater than max,
0329             value_type::indeterminate,      // indeterminate,
0330         //},
0331         // t == greater_than_zero,
0332         //{
0333             // u == ...
0334             value_type::less_than_min,      // less_than_min,
0335             value_type::less_than_zero,     // less_than_zero,
0336             value_type::zero,               // zero,
0337             value_type::greater_than_zero,  // greater_than_zero,
0338             value_type::greater_than_max,   // greater than max,
0339             value_type::indeterminate,      // indeterminate,
0340         //},
0341         // t == greater_than_max
0342         //{
0343             value_type::less_than_min,      // less_than_min,
0344             value_type::less_than_min,      // less_than_zero,
0345             value_type::zero,               // zero,
0346             value_type::greater_than_max,   // greater_than_zero,
0347             value_type::greater_than_max,   // greater than max,
0348             value_type::indeterminate,      // indeterminate,
0349         //},
0350         // t == indeterminate
0351         //{
0352             value_type::indeterminate,      // less_than_min,
0353             value_type::indeterminate,      // less_than_zero,
0354             value_type::indeterminate,      // zero,
0355             value_type::indeterminate,      // greater_than_zero,
0356             value_type::indeterminate,      // greater than max,
0357             value_type::indeterminate,      // indeterminate,
0358         //}
0359     };
0360 
0361     const value_type tx(t);
0362     const value_type ux(u);
0363 
0364     switch(result[tx * order + ux]){
0365         case value_type::less_than_min:
0366             return safe_numerics_error::negative_overflow_error;
0367         case value_type::zero:
0368             return T(0);
0369         case value_type::greater_than_max:
0370             return safe_numerics_error::positive_overflow_error;
0371         case value_type::less_than_zero:
0372         case value_type::greater_than_zero:
0373             return checked::multiply<T>(t, u);
0374         case value_type::indeterminate:
0375             return safe_numerics_error::range_error;
0376         default:
0377             assert(false);
0378         }
0379     return checked_result<T>(0); // to suppress msvc warning
0380 }
0381 
0382 // integers division
0383 template<class T>
0384 typename std::enable_if<
0385     std::is_integral<T>::value,
0386     checked_result<T>
0387 >::type
0388 constexpr inline operator/(
0389     const checked_result<T> & t,
0390     const checked_result<T> & u
0391 ){
0392     using value_type = product_value_type;
0393     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0394 
0395     constexpr const enum value_type::flag result[order * order] = {
0396         // t == less_than_min
0397         //{
0398             // u == ...
0399             value_type::indeterminate,   // less_than_min,
0400             value_type::greater_than_max,   // less_than_zero,
0401             value_type::less_than_min,      // zero,
0402             value_type::less_than_min,      // greater_than_zero,
0403             value_type::less_than_min,      // greater than max,
0404             value_type::indeterminate,      // indeterminate,
0405         //},
0406         // t == less_than_zero,
0407         //{
0408             // u == ...
0409             value_type::zero,               // less_than_min,
0410             value_type::greater_than_zero,  // less_than_zero,
0411             value_type::less_than_min,      // zero,
0412             value_type::less_than_zero,     // greater_than_zero,
0413             value_type::zero,               // greater than max,
0414             value_type::indeterminate,      // indeterminate,
0415         //},
0416         // t == zero,
0417         //{
0418             // u == ...
0419             value_type::zero,               // less_than_min,
0420             value_type::zero,               // less_than_zero,
0421             value_type::indeterminate,      // zero,
0422             value_type::zero,               // greater_than_zero,
0423             value_type::zero,               // greater than max,
0424             value_type::indeterminate,               // indeterminate,
0425         //},
0426         // t == greater_than_zero,
0427         //{
0428             // u == ...
0429             value_type::zero,               // less_than_min,
0430             value_type::less_than_zero,     // less_than_zero,
0431             value_type::greater_than_max,   // zero,
0432             value_type::greater_than_zero,  // greater_than_zero,
0433             value_type::zero,               // greater than max,
0434             value_type::indeterminate,      // indeterminate,
0435         //},
0436         // t == greater_than_max
0437         //{
0438             value_type::less_than_min,      // less_than_min,
0439             value_type::less_than_min,      // less_than_zero,
0440             value_type::greater_than_max,   // zero,
0441             value_type::greater_than_max,   // greater_than_zero,
0442             value_type::indeterminate,   // greater than max,
0443             value_type::indeterminate,      // indeterminate,
0444         //},
0445         // t == indeterminate
0446         //{
0447             value_type::indeterminate,      // less_than_min,
0448             value_type::indeterminate,      // less_than_zero,
0449             value_type::indeterminate,      // zero,
0450             value_type::indeterminate,      // greater_than_zero,
0451             value_type::indeterminate,      // greater than max,
0452             value_type::indeterminate,      // indeterminate,
0453         //}
0454     };
0455 
0456     const value_type tx(t);
0457     const value_type ux(u);
0458 
0459     switch(result[tx * order + ux]){
0460         case value_type::less_than_min:
0461             return safe_numerics_error::negative_overflow_error;
0462         case value_type::zero:
0463             return 0;
0464         case value_type::greater_than_max:
0465             return safe_numerics_error::positive_overflow_error;
0466         case value_type::less_than_zero:
0467         case value_type::greater_than_zero:
0468             return checked::divide<T>(t, u);
0469         case value_type::indeterminate:
0470             return safe_numerics_error::range_error;
0471         default:
0472             assert(false);
0473     }
0474     return checked_result<T>(0); // to suppress msvc warning
0475 }
0476 
0477 // integers modulus
0478 template<class T>
0479 typename std::enable_if<
0480     std::is_integral<T>::value,
0481     checked_result<T>
0482 >::type
0483 constexpr inline operator%(
0484     const checked_result<T> & t,
0485     const checked_result<T> & u
0486 ){
0487     using value_type = product_value_type;
0488     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0489 
0490     constexpr const enum value_type::flag result[order * order] = {
0491         // t == less_than_min
0492         //{
0493             // u == ...
0494             value_type::indeterminate,      // less_than_min,
0495             value_type::z_value,            // less_than_zero,
0496             value_type::indeterminate,      // zero,
0497             value_type::z_value,            // greater_than_zero,
0498             value_type::indeterminate,      // greater than max,
0499             value_type::indeterminate,      // indeterminate,
0500         //},
0501         // t == less_than_zero,
0502         //{
0503             // u == ...
0504             value_type::t_value,            // less_than_min,
0505             value_type::greater_than_zero,  // less_than_zero,
0506             value_type::indeterminate,      // zero,
0507             value_type::less_than_zero,     // greater_than_zero,
0508             value_type::t_value,            // greater than max,
0509             value_type::indeterminate,      // indeterminate,
0510         //},
0511         // t == zero,
0512         //{
0513             // u == ...
0514             value_type::zero,               // less_than_min,
0515             value_type::zero,               // less_than_zero,
0516             value_type::indeterminate,      // zero,
0517             value_type::zero,               // greater_than_zero,
0518             value_type::zero,               // greater than max,
0519             value_type::indeterminate,      // indeterminate,
0520         //},
0521         // t == greater_than_zero,
0522         //{
0523             // u == ...
0524             value_type::t_value,            // less_than_min,
0525             value_type::less_than_zero,     // less_than_zero,
0526             value_type::indeterminate,      // zero,
0527             value_type::greater_than_zero,  // greater_than_zero,
0528             value_type::t_value,            // greater than max,
0529             value_type::indeterminate,      // indeterminate,
0530         //},
0531         // t == greater_than_max
0532         //{
0533             value_type::indeterminate,      // less_than_min,
0534             value_type::u_value,            // less_than_zero,
0535             value_type::indeterminate,      // zero,
0536             value_type::u_value,            // greater_than_zero,
0537             value_type::indeterminate,      // greater than max,
0538             value_type::indeterminate,      // indeterminate,
0539         //},
0540         // t == indeterminate
0541         //{
0542             value_type::indeterminate,      // less_than_min,
0543             value_type::indeterminate,      // less_than_zero,
0544             value_type::indeterminate,      // zero,
0545             value_type::indeterminate,      // greater_than_zero,
0546             value_type::indeterminate,      // greater than max,
0547             value_type::indeterminate,      // indeterminate,
0548         //}
0549     };
0550 
0551     const value_type tx(t);
0552     const value_type ux(u);
0553 
0554     switch(result[tx * order + ux]){
0555         case value_type::zero:
0556             return 0;
0557         case value_type::less_than_zero:
0558         case value_type::greater_than_zero:
0559             return checked::modulus<T>(t, u);
0560         case value_type::indeterminate:
0561             return safe_numerics_error::range_error;
0562         case value_type::t_value:
0563             return t;
0564         case value_type::u_value:
0565             return checked::subtract<T>(u, 1);
0566         case value_type::z_value:
0567             return checked::subtract<T>(1, u);
0568         case value_type::greater_than_max:
0569         case value_type::less_than_min:
0570         default:
0571             assert(false);
0572     }
0573     // suppress msvc warning
0574     return checked_result<T>(0);
0575 }
0576 
0577 // comparison operators
0578 
0579 template<class T>
0580 constexpr boost::logic::tribool operator<(
0581     const checked_result<T> & t,
0582     const checked_result<T> & u
0583 ){
0584     using value_type = sum_value_type;
0585     constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0586 
0587     // the question arises about how to order values of type greater_than_min.
0588     // that is: what should greater_than_min < greater_than_min return.
0589     //
0590     // a) return indeterminate because we're talking about the "true" values for
0591     //    which greater_than_min is a placholder.
0592     //
0593     // b) return false because the two values are "equal"
0594     //
0595     // for our purposes, a) seems the better interpretation.
0596     
0597     enum class result_type : std::uint8_t {
0598         runtime,
0599         false_value,
0600         true_value,
0601         indeterminate,
0602     };
0603     constexpr const result_type resultx[order * order]{
0604         // t == known_value
0605         //{
0606             // u == ...
0607             result_type::runtime,       // known_value,
0608             result_type::false_value,   // less_than_min,
0609             result_type::true_value,    // greater_than_max,
0610             result_type::indeterminate, // indeterminate,
0611         //},
0612         // t == less_than_min
0613         //{
0614             // u == ...
0615             result_type::true_value,    // known_value,
0616             result_type::indeterminate, // less_than_min, see above argument
0617             result_type::true_value,    // greater_than_max,
0618             result_type::indeterminate, // indeterminate,
0619         //},
0620         // t == greater_than_max
0621         //{
0622             // u == ...
0623             result_type::false_value,   // known_value,
0624             result_type::false_value,   // less_than_min,
0625             result_type::indeterminate, // greater_than_max, see above argument
0626             result_type::indeterminate, // indeterminate,
0627         //},
0628         // t == indeterminate
0629         //{
0630             // u == ...
0631             result_type::indeterminate, // known_value,
0632             result_type::indeterminate, // less_than_min,
0633             result_type::indeterminate, // greater_than_max,
0634             result_type::indeterminate, // indeterminate,
0635         //},
0636     };
0637 
0638     const value_type tx(t);
0639     const value_type ux(u);
0640 
0641     switch(resultx[tx * order + ux]){
0642     case result_type::runtime:
0643         return static_cast<const T &>(t) < static_cast<const T &>(u);
0644     case result_type::false_value:
0645         return false;
0646     case result_type::true_value:
0647         return true;
0648     case result_type::indeterminate:
0649         return boost::logic::indeterminate;
0650     default:
0651         assert(false);
0652     }
0653     return true;
0654 }
0655 
0656 template<class T>
0657 constexpr boost::logic::tribool
0658 operator>=(
0659     const checked_result<T> & t,
0660     const checked_result<T> & u
0661 ){
0662     return !(t < u);
0663 }
0664 
0665 template<class T>
0666 constexpr boost::logic::tribool
0667 operator>(
0668     const checked_result<T> & t,
0669     const checked_result<T> & u
0670 ){
0671     return u < t;
0672 }
0673 
0674 template<class T>
0675 constexpr boost::logic::tribool
0676 operator<=(
0677     const checked_result<T> & t,
0678     const checked_result<T> & u
0679 ){
0680     return !(u < t);
0681 }
0682 
0683 template<class T>
0684 constexpr boost::logic::tribool
0685 operator==(
0686     const checked_result<T> & t,
0687     const checked_result<T> & u
0688 ){
0689     using value_type = sum_value_type;
0690     constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0691 
0692     enum class result_type : std::uint8_t {
0693         runtime,
0694         false_value,
0695         true_value,
0696         indeterminate,
0697     };
0698 
0699     constexpr const result_type result[order * order]{
0700         // t == known_value
0701         //{
0702             // u == ...
0703             result_type::runtime,       // known_value,
0704             result_type::false_value,   // less_than_min,
0705             result_type::false_value,   // greater_than_max,
0706             result_type::indeterminate, // indeterminate,
0707         //},
0708         // t == less_than_min
0709         //{
0710             // u == ...
0711             result_type::false_value,   // known_value,
0712             result_type::indeterminate, // less_than_min,
0713             result_type::false_value,   // greater_than_max,
0714             result_type::indeterminate, // indeterminate,
0715         //},
0716         // t == greater_than_max
0717         //{
0718             // u == ...
0719             result_type::false_value,   // known_value,
0720             result_type::false_value,   // less_than_min,
0721             result_type::indeterminate, // greater_than_max,
0722             result_type::indeterminate, // indeterminate,
0723         //},
0724         // t == indeterminate
0725         //{
0726             // u == ...
0727             result_type::indeterminate, // known_value,
0728             result_type::indeterminate, // less_than_min,
0729             result_type::indeterminate, // greater_than_max,
0730             result_type::indeterminate, // indeterminate,
0731         //},
0732     };
0733 
0734     const value_type tx(t);
0735     const value_type ux(u);
0736 
0737     switch(result[tx * order + ux]){
0738     case result_type::runtime:
0739         return static_cast<const T &>(t) == static_cast<const T &>(u);
0740     case result_type::false_value:
0741         return false;
0742     case result_type::true_value:
0743         return true;
0744     case result_type::indeterminate:
0745         return boost::logic::indeterminate;
0746     default:
0747         assert(false);
0748     }
0749     // suppress msvc warning - not all control paths return a value
0750     return false;
0751 }
0752 
0753 template<class T>
0754 constexpr boost::logic::tribool
0755 operator!=(
0756     const checked_result<T> & t,
0757     const checked_result<T> & u
0758 ){
0759     return ! (t == u);
0760 }
0761 
0762 template<class T>
0763 typename std::enable_if<
0764     std::is_integral<T>::value,
0765     checked_result<T>
0766 >::type
0767 constexpr inline operator>>(
0768     const checked_result<T> & t,
0769     const checked_result<T> & u
0770 );
0771 
0772 template<class T>
0773 typename std::enable_if<
0774     std::is_integral<T>::value,
0775     checked_result<T>
0776 >::type
0777 constexpr inline operator~(
0778     const checked_result<T> & t
0779 ){
0780 //    assert(false);
0781     return ~t.m_r;
0782 }
0783 
0784 template<class T>
0785 typename std::enable_if<
0786     std::is_integral<T>::value,
0787     checked_result<T>
0788 >::type
0789 constexpr inline operator<<(
0790     const checked_result<T> & t,
0791     const checked_result<T> & u
0792 ){
0793     using value_type = product_value_type;
0794     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0795 
0796     constexpr const std::uint8_t result[order * order] = {
0797         // t == less_than_min
0798         //{
0799             // u == ...
0800             1, // -1,                                           // less_than_min,
0801             2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
0802             2, // safe_numerics_error::negative_overflow_error, // zero,
0803             2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
0804             2, // safe_numerics_error::negative_overflow_error, // greater than max,
0805             1, // safe_numerics_error::range_error,             // indeterminate,
0806         //},
0807         // t == less_than_zero,
0808         //{
0809             // u == ...
0810             3, // -1,                                           // less_than_min,
0811             4, // - (-t >> -u),                                 // less_than_zero,
0812             5, // safe_numerics_error::negative_overflow_error, // zero,
0813             6, // - (-t << u),                                  // greater_than_zero,
0814             2, // safe_numerics_error::negative_overflow_error, // greater than max,
0815             1, // safe_numerics_error::range_error,             // indeterminate,
0816         //},
0817         // t == zero,
0818         //{
0819             // u == ...
0820             3, // 0     // less_than_min,
0821             3, // 0     // less_than_zero,
0822             3, // 0,    // zero,
0823             3, // 0,    // greater_than_zero,
0824             3, // 0,    // greater than max,
0825             3, // safe_numerics_error::range_error,    // indeterminate,
0826         //},
0827         // t == greater_than_zero,
0828         //{
0829             // u == ...
0830             3, // 0,                                            // less_than_min,
0831             7, // t << -u,                                      // less_than_zero,
0832             5, // t,                                            // zero,
0833             8, // t << u                                        // greater_than_zero,
0834             9, // safe_numerics_error::positive_overflow_error, // greater than max,
0835             1, // safe_numerics_error::range_error,             // indeterminate,
0836         //},
0837         // t == greater_than_max
0838         //{
0839             // u == ...
0840             1, // safe_numerics_error::range_error,               // less_than_min,
0841             9, // safe_numerics_error::positive_overflow_error),  // less_than_zero,
0842             9, // safe_numerics_error::positive_overflow_error,   // zero,
0843             9, // safe_numerics_error::positive_overflow_error),  // greater_than_zero,
0844             9, // safe_numerics_error::positive_overflow_error,   // greater than max,
0845             1, // safe_numerics_error::range_error,               // indeterminate,
0846         //},
0847         // t == indeterminate
0848         //{
0849             1, // safe_numerics_error::range_error,    // indeterminate,
0850             1, // safe_numerics_error::range_error,    // indeterminate,
0851             1, // safe_numerics_error::range_error,    // indeterminate,
0852             1, // safe_numerics_error::range_error,    // indeterminate,
0853             1, // safe_numerics_error::range_error,    // indeterminate,
0854             1, // safe_numerics_error::range_error,    // indeterminate,
0855         //}
0856     };
0857 
0858     const value_type tx(t);
0859     const value_type ux(u);
0860     assert(tx * order + ux < order * order);
0861 
0862     // I had a switch(i) statment here - but it results in an ICE
0863     // on multiple versions of gcc.  So make the equivalent in
0864     // nested if statments - should be the same (more or less)
0865     // performancewise.
0866     const unsigned int i = result[tx * order + ux];
0867     assert(i <= 9);
0868     if(1 == i){
0869         return safe_numerics_error::range_error;
0870     }
0871     else
0872     if(2 == i){
0873         return safe_numerics_error::negative_overflow_error;
0874     }
0875     else
0876     if(3 == i){
0877         return checked_result<T>(0);
0878     // the following gymnastics are to handle the case where 
0879     // a value is changed from a negative to a positive number.
0880     // For example, and 8 bit number t == -128.  Then -t also
0881     // equals -128 since 128 cannot be held in an 8 bit signed
0882     // integer.
0883     }
0884     else
0885     if(4 == i){ // - (-t >> -u)
0886         assert(static_cast<bool>(t < checked_result<T>(0)));
0887         assert(static_cast<bool>(u < checked_result<T>(0)));
0888         return t >> -u;
0889     }
0890     else
0891     if(5 == i){
0892         return t;
0893     }
0894     else
0895     if(6 == i){ // - (-t << u)
0896         assert(static_cast<bool>(t < checked_result<T>(0)));
0897         assert(static_cast<bool>(u > checked_result<T>(0)));
0898         const checked_result<T> temp_t = t * checked_result<T>(2);
0899         const checked_result<T> temp_u = u - checked_result<T>(1);
0900         return  - (-temp_t << temp_u);
0901     }
0902     else
0903     if(7 == i){  // t >> -u
0904         assert(static_cast<bool>(t > checked_result<T>(0)));
0905         assert(static_cast<bool>(u < checked_result<T>(0)));
0906         return t >> -u;
0907     }
0908     else
0909     if(8 == i){ // t << u
0910         assert(static_cast<bool>(t > checked_result<T>(0)));
0911         assert(static_cast<bool>(u > checked_result<T>(0)));
0912         checked_result<T> r = checked::left_shift<T>(t, u);
0913         return (r.m_e == safe_numerics_error::shift_too_large)
0914         ? checked_result<T>(safe_numerics_error::positive_overflow_error)
0915         : r;
0916     }
0917     else
0918     if(9 == i){
0919         return safe_numerics_error::positive_overflow_error;
0920     }
0921     else{
0922         assert(false);
0923     };
0924     return checked_result<T>(0); // to suppress msvc warning
0925 }
0926 
0927 template<class T>
0928 typename std::enable_if<
0929     std::is_integral<T>::value,
0930     checked_result<T>
0931 >::type
0932 constexpr inline operator>>(
0933     const checked_result<T> & t,
0934     const checked_result<T> & u
0935 ){
0936     using value_type = product_value_type;
0937     const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
0938 
0939     const std::uint8_t result[order * order] = {
0940         // t == less_than_min
0941         //{
0942             // u == ...
0943             2, // safe_numerics_error::negative_overflow_error, // less_than_min,
0944             2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
0945             2, // safe_numerics_error::negative_overflow_error, // zero,
0946             2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
0947             1, // safe_numerics_error::range_error,             // greater than max,
0948             1, // safe_numerics_error::range_error,             // indeterminate,
0949         //},
0950         // t == less_than_zero,
0951         //{
0952             // u == ...
0953             2, // safe_numerics_error::negative_overflow_error  // less_than_min,
0954             4, // - (-t << -u),                                 // less_than_zero,
0955             5, // safe_numerics_error::negative_overflow_error. // zero,
0956             6, // - (-t >> u),                                  // greater_than_zero,
0957             3, // 0, ? or -1                                    // greater than max,
0958             1, // safe_numerics_error::range_error,             // indeterminate,
0959         //},
0960         // t == zero,
0961         //{
0962             // u == ...
0963             3, // 0     // less_than_min,
0964             3, // 0     // less_than_zero,
0965             3, // 0,    // zero,
0966             3, // 0,    // greater_than_zero,
0967             3, // 0,    // greater than max,
0968             3, // safe_numerics_error::range_error,    // indeterminate,
0969         //},
0970         // t == greater_than_zero,
0971         //{
0972             // u == ...
0973             9, // safe_numerics_error::positive_overflow_error  // less_than_min,
0974             7, // t << -u,                                      // less_than_zero,
0975             5, // t,                                            // zero,
0976             8, // t >> u                                        // greater_than_zero,
0977             3, // 0,                                            // greater than max,
0978             1, // safe_numerics_error::range_error,             // indeterminate,
0979         //},
0980         // t == greater_than_max
0981         //{
0982             // u == ...
0983             9, // safe_numerics_error::positive_overflow_error, // less_than_min,
0984             9, // safe_numerics_error::positive_overflow_error, // less_than_zero,
0985             9, // safe_numerics_error::positive_overflow_error, // zero,
0986             9, // safe_numerics_error::positive_overflow_error, // greater_than_zero,
0987             1, // safe_numerics_error::range_error,             // greater than max,
0988             1, // safe_numerics_error::range_error,             // indeterminate,
0989         //},
0990         // t == indeterminate
0991         //{
0992             1, // safe_numerics_error::range_error,    // indeterminate,
0993             1, // safe_numerics_error::range_error,    // indeterminate,
0994             1, // safe_numerics_error::range_error,    // indeterminate,
0995             1, // safe_numerics_error::range_error,    // indeterminate,
0996             1, // safe_numerics_error::range_error,    // indeterminate,
0997             1, // safe_numerics_error::range_error,    // indeterminate,
0998         //}
0999     };
1000 
1001     const value_type tx(t);
1002     const value_type ux(u);
1003     assert(tx * order + ux < order * order);
1004 
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)
1008     // performancewise.
1009     const unsigned int i = result[tx * order + ux];
1010     assert(i <= 9);
1011     if(1 == i){
1012         return safe_numerics_error::range_error;
1013     }
1014     else
1015     if(2 == i){
1016         return safe_numerics_error::negative_overflow_error;
1017     }
1018     else
1019     if(3 == i){
1020         return checked_result<T>(0);
1021     }
1022     else
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)));
1026         return t << -u;
1027     }
1028     else
1029     if(5 == i){
1030         return t;
1031     }
1032     else
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);
1039     }
1040     else
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)));
1044         return t << -u;
1045     }
1046     else
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)
1053         : r;
1054     }
1055     else
1056     if(9 == i){
1057         return safe_numerics_error::positive_overflow_error;
1058     }
1059     else{
1060         assert(false);
1061     };
1062     return checked_result<T>(0); // to suppress msvc warning
1063 }
1064 
1065 template<class T>
1066 typename std::enable_if<
1067     std::is_integral<T>::value,
1068     checked_result<T>
1069 >::type
1070 constexpr inline operator|(
1071     const checked_result<T> & t,
1072     const checked_result<T> & u
1073 ){
1074     return
1075         t.exception() || u.exception()
1076         ? checked_result<T>(safe_numerics_error::range_error)
1077         : checked::bitwise_or<T>(
1078             static_cast<T>(t),
1079             static_cast<T>(u)
1080         );
1081 }
1082 template<class T>
1083 typename std::enable_if<
1084     std::is_integral<T>::value,
1085     checked_result<T>
1086 >::type
1087 constexpr inline operator^(
1088     const checked_result<T> & t,
1089     const checked_result<T> & u
1090 ){
1091     return
1092         t.exception() || u.exception()
1093         ? checked_result<T>(safe_numerics_error::range_error)
1094         : checked::bitwise_xor<T>(
1095             static_cast<T>(t),
1096             static_cast<T>(u)
1097         );
1098 }
1099 
1100 template<class T>
1101 typename std::enable_if<
1102     std::is_integral<T>::value,
1103     checked_result<T>
1104 >::type
1105 constexpr inline operator&(
1106     const checked_result<T> & t,
1107     const checked_result<T> & u
1108 ){
1109     return
1110         t.exception() || u.exception()
1111         ? checked_result<T>(safe_numerics_error::range_error)
1112         : checked::bitwise_and<T>(
1113             static_cast<T>(t),
1114             static_cast<T>(u)
1115         );
1116 }
1117 
1118 } // safe_numerics
1119 } // boost
1120 
1121 #include <iosfwd>
1122 
1123 namespace std {
1124 
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
1129 ){
1130     bool e = r.exception();
1131     os << e;
1132     if(!e)
1133         os << static_cast<R>(r);
1134     else
1135         os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1136     return os;
1137 }
1138 
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
1143 ){
1144     bool e = r.exception();
1145     os << e;
1146     if(! e)
1147         os << static_cast<std::int16_t>(r);
1148     else
1149         os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
1150     return os;
1151 }
1152 
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
1157 ){
1158     bool e;
1159     is >> e;
1160     if(!e)
1161         is >> static_cast<R>(r);
1162     else
1163         is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1164     return is;
1165 }
1166 
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
1171 ){
1172     bool e;
1173     is >> e;
1174     if(!e){
1175         std::int16_t i;
1176         is >> i;
1177         r.m_contents.m_r = static_cast<signed char>(i);
1178     }
1179     else
1180         is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
1181     return is;
1182 }
1183 
1184 } // std
1185 
1186 /////////////////////////////////////////////////////////////////
1187 // numeric limits for checked<R>
1188 
1189 #include <limits>
1190 
1191 namespace std {
1192 
1193 template<class R>
1194 class numeric_limits<boost::safe_numerics::checked_result<R> >
1195     : public std::numeric_limits<R>
1196 {
1197     using this_type = boost::safe_numerics::checked_result<R>;
1198 public:
1199     constexpr static this_type min() noexcept {
1200         return this_type(std::numeric_limits<R>::min());
1201     }
1202     constexpr static this_type max() noexcept {
1203         return this_type(std::numeric_limits<R>::max());
1204     }
1205 };
1206 
1207 } // std
1208 
1209 #endif  // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS