Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:37

0001 #ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
0002 #define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
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 #include <limits>
0011 #include <type_traits> // is_base_of, is_same, is_floating_point, conditional
0012 #include <algorithm>   // max
0013 #include <istream>
0014 #include <ostream>
0015 #include <utility> // declval
0016 
0017 #include <boost/config.hpp>
0018 
0019 #include <boost/core/enable_if.hpp> // lazy_enable_if
0020 #include <boost/integer.hpp>
0021 #include <boost/logic/tribool.hpp>
0022 
0023 #include "concept/numeric.hpp"
0024 
0025 #include "checked_integer.hpp"
0026 #include "checked_result.hpp"
0027 #include "safe_base.hpp"
0028 
0029 #include "interval.hpp"
0030 #include "utility.hpp"
0031 
0032 #include <boost/mp11/utility.hpp> // mp_valid
0033 #include <boost/mp11/function.hpp> // mp_and, mp_or
0034 
0035 namespace boost {
0036 namespace safe_numerics {
0037 
0038 ////////////////////////////////////////////////////////////////////////////////
0039 // compile time error dispatcher
0040 
0041 // note slightly baroque implementation of a compile time switch statement
0042 // which instatiates only those cases which are actually invoked.  This is
0043 // motivated to implement the "trap" functionality which will generate a syntax
0044 // error if and only a function which might fail is called.
0045 
0046 namespace dispatch_switch {
0047 
0048     template<class EP, safe_numerics_actions>
0049     struct dispatch_case {};
0050 
0051     template<class EP>
0052     struct dispatch_case<EP, safe_numerics_actions::uninitialized_value> {
0053         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
0054             EP::on_uninitialized_value(e, msg);
0055         }
0056     };
0057     template<class EP>
0058     struct dispatch_case<EP, safe_numerics_actions::arithmetic_error> {
0059         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
0060             EP::on_arithmetic_error(e, msg);
0061         }
0062     };
0063     template<class EP>
0064     struct dispatch_case<EP, safe_numerics_actions::implementation_defined_behavior> {
0065         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
0066             EP::on_implementation_defined_behavior(e, msg);
0067         }
0068     };
0069     template<class EP>
0070     struct dispatch_case<EP, safe_numerics_actions::undefined_behavior> {
0071         constexpr static void invoke(const safe_numerics_error & e, const char * msg){
0072             EP::on_undefined_behavior(e, msg);
0073         }
0074     };
0075 
0076 } // dispatch_switch
0077 
0078 template<class EP, safe_numerics_error E>
0079 constexpr inline void
0080 dispatch(const char * msg){
0081     constexpr safe_numerics_actions a = make_safe_numerics_action(E);
0082     dispatch_switch::dispatch_case<EP, a>::invoke(E, msg);
0083 }
0084 
0085 template<class EP, class R>
0086 class dispatch_and_return {
0087 public:
0088     template<safe_numerics_error E>
0089     constexpr static checked_result<R> invoke(
0090         char const * const & msg
0091     ) {
0092         dispatch<EP, E>(msg);
0093         return checked_result<R>(E, msg);
0094     }
0095 };
0096 
0097 /////////////////////////////////////////////////////////////////
0098 // validation
0099 
0100 template<typename R, R Min, R Max, typename E>
0101 struct validate_detail {
0102     using r_type = checked_result<R>;
0103 
0104     struct exception_possible {
0105         template<typename T>
0106         constexpr static R return_value(
0107             const T & t
0108         ){
0109             // INT08-C
0110             const r_type rx = heterogeneous_checked_operation<
0111                 R,
0112                 Min,
0113                 Max,
0114                 typename base_type<T>::type,
0115                 dispatch_and_return<E, R>
0116             >::cast(t);
0117 
0118             return rx;
0119         }
0120     };
0121     struct exception_not_possible {
0122         template<typename T>
0123         constexpr static R return_value(
0124             const T & t
0125         ){
0126             return static_cast<R>(base_value(t));
0127         }
0128     };
0129 
0130     template<typename T>
0131     constexpr static R return_value(const T & t){
0132         constexpr const interval<r_type> t_interval{
0133             checked::cast<R>(base_value(std::numeric_limits<T>::min())),
0134             checked::cast<R>(base_value(std::numeric_limits<T>::max()))
0135         };
0136         constexpr const interval<r_type> r_interval{r_type(Min), r_type(Max)};
0137 
0138         static_assert(
0139             true != static_cast<bool>(r_interval.excludes(t_interval)),
0140             "can't cast from ranges that don't overlap"
0141         );
0142         return std::conditional<
0143             static_cast<bool>(r_interval.includes(t_interval)),
0144             exception_not_possible,
0145             exception_possible
0146         >::type::return_value(t);
0147     }
0148 };
0149 
0150 template<class Stored, Stored Min, Stored Max, class P, class E>
0151 template<class T>
0152 constexpr inline Stored safe_base<Stored, Min, Max, P, E>::
0153 validated_cast(const T & t) const {
0154     return validate_detail<Stored,Min,Max,E>::return_value(t);
0155 }
0156 
0157 /////////////////////////////////////////////////////////////////
0158 // constructors
0159 
0160 // default constructor
0161 template<class Stored, Stored Min, Stored Max, class P, class E>
0162 constexpr inline /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){
0163     static_assert(
0164         std::is_arithmetic<Stored>(),
0165         "currently, safe numeric base types must currently be arithmetic types"
0166     );
0167     dispatch<E, safe_numerics_error::uninitialized_value>(
0168         "safe values must be initialized"
0169     );
0170 }
0171 // construct an instance of a safe type from an instance of a convertible underlying type.
0172 template<class Stored, Stored Min, Stored Max, class P, class E>
0173 constexpr inline /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
0174     const Stored & rhs,
0175     skip_validation
0176 ) :
0177     m_t(rhs)
0178 {
0179     static_assert(
0180         std::is_arithmetic<Stored>(),
0181         "currently, safe numeric base types must currently be arithmetic types"
0182     );
0183 }
0184 
0185 // construct an instance from an instance of a convertible underlying type.
0186 template<class Stored, Stored Min, Stored Max, class P, class E>
0187     template<
0188         class T,
0189         typename std::enable_if<
0190             std::is_convertible<T, Stored>::value,
0191             bool
0192         >::type
0193     >
0194 constexpr inline /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(const T &t) :
0195     m_t(validated_cast(t))
0196 {
0197     static_assert(
0198         std::is_arithmetic<Stored>(),
0199         "currently, safe numeric base types must currently be arithmetic types"
0200     );
0201 }
0202 
0203 // construct an instance of a safe type from a literal value
0204 template<class Stored, Stored Min, Stored Max, class P, class E>
0205 template<typename T, T N, class Px, class Ex>
0206 constexpr inline /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
0207     const safe_literal_impl<T, N, Px, Ex> & t
0208 ) :
0209     m_t(validated_cast(t))
0210 {    static_assert(
0211         std::is_arithmetic<Stored>(),
0212         "currently, safe numeric base types must currently be arithmetic types"
0213     );
0214 }
0215 
0216 /////////////////////////////////////////////////////////////////
0217 // casting operators
0218 
0219 // cast to a builtin type from a safe type
0220 template< class Stored, Stored Min, Stored Max, class P, class E>
0221 template<
0222     class R,
0223     typename std::enable_if<
0224         ! boost::safe_numerics::is_safe<R>::value,
0225         int
0226     >::type
0227 >
0228 constexpr inline safe_base<Stored, Min, Max, P, E>::
0229 operator R () const {
0230     // if static values don't overlap, the program can never function
0231     constexpr const interval<R> r_interval;
0232     constexpr const interval<Stored> this_interval(Min, Max);
0233     static_assert(
0234         ! r_interval.excludes(this_interval),
0235         "safe type cannot be constructed with this type"
0236     );
0237     return validate_detail<
0238         R,
0239         std::numeric_limits<R>::min(),
0240         std::numeric_limits<R>::max(),
0241         E
0242     >::return_value(m_t);
0243 }
0244 
0245 /////////////////////////////////////////////////////////////////
0246 // binary operators
0247 
0248 template<class T, class U>
0249 struct common_exception_policy {
0250     static_assert(is_safe<T>::value || is_safe<U>::value,
0251         "at least one type must be a safe type"
0252     );
0253 
0254     using t_exception_policy = typename get_exception_policy<T>::type;
0255     using u_exception_policy = typename get_exception_policy<U>::type;
0256 
0257     static_assert(
0258         std::is_same<t_exception_policy, u_exception_policy>::value
0259         || std::is_same<t_exception_policy, void>::value
0260         || std::is_same<void, u_exception_policy>::value,
0261         "if the exception policies are different, one must be void!"
0262     );
0263 
0264     static_assert(
0265         ! (std::is_same<t_exception_policy, void>::value
0266         && std::is_same<void, u_exception_policy>::value),
0267         "at least one exception policy must not be void"
0268     );
0269 
0270     using type =
0271         typename std::conditional<
0272             !std::is_same<void, u_exception_policy>::value,
0273             u_exception_policy,
0274         typename std::conditional<
0275             !std::is_same<void, t_exception_policy>::value,
0276             t_exception_policy,
0277         //
0278             void
0279         >::type >::type;
0280 
0281     static_assert(
0282         !std::is_same<void, type>::value,
0283         "exception_policy is void"
0284     );
0285 };
0286 
0287 template<class T, class U>
0288 struct common_promotion_policy {
0289     static_assert(is_safe<T>::value || is_safe<U>::value,
0290         "at least one type must be a safe type"
0291     );
0292     using t_promotion_policy = typename get_promotion_policy<T>::type;
0293     using u_promotion_policy = typename get_promotion_policy<U>::type;
0294     static_assert(
0295         std::is_same<t_promotion_policy, u_promotion_policy>::value
0296         ||std::is_same<t_promotion_policy, void>::value
0297         ||std::is_same<void, u_promotion_policy>::value,
0298         "if the promotion policies are different, one must be void!"
0299     );
0300     static_assert(
0301         ! (std::is_same<t_promotion_policy, void>::value
0302         && std::is_same<void, u_promotion_policy>::value),
0303         "at least one promotion policy must not be void"
0304     );
0305 
0306     using type =
0307         typename std::conditional<
0308             ! std::is_same<void, u_promotion_policy>::value,
0309             u_promotion_policy,
0310         typename std::conditional<
0311             ! std::is_same<void, t_promotion_policy>::value,
0312             t_promotion_policy,
0313         //
0314             void
0315         >::type >::type;
0316 
0317     static_assert(
0318         ! std::is_same<void, type>::value,
0319         "promotion_policy is void"
0320     );
0321 
0322 };
0323 
0324 // give the resultant base type, figure out what the final result
0325 // type will be.  Note we currently need this because we support
0326 // return of only safe integer types. Someday ..., we'll support
0327 // all other safe types including float and user defined ones.
0328 
0329 // helper - cast arguments to binary operators to a specified
0330 // result type
0331 
0332 template<class EP, class R, class T, class U>
0333 constexpr inline static std::pair<R, R> casting_helper(const T & t, const U & u){
0334     using r_type = checked_result<R>;
0335     const r_type tx = heterogeneous_checked_operation<
0336         R,
0337         std::numeric_limits<R>::min(),
0338         std::numeric_limits<R>::max(),
0339         typename base_type<T>::type,
0340         dispatch_and_return<EP, R>
0341     >::cast(base_value(t));
0342     const R tr = tx.exception()
0343         ? static_cast<R>(t)
0344         : tx.m_contents.m_r;
0345 
0346     const r_type ux = heterogeneous_checked_operation<
0347         R,
0348         std::numeric_limits<R>::min(),
0349         std::numeric_limits<R>::max(),
0350         typename base_type<U>::type,
0351         dispatch_and_return<EP, R>
0352     >::cast(base_value(u));
0353     const R ur = ux.exception()
0354         ? static_cast<R>(u)
0355         : ux.m_contents.m_r;
0356     return std::pair<R, R>(tr, ur);
0357 }
0358 
0359 // Note: the following global operators will be found via
0360 // argument dependent lookup.
0361 namespace {
0362 template<template<class...> class F, class T, class U >
0363 using legal_overload =
0364     boost::mp11::mp_and<
0365         boost::mp11::mp_or< is_safe<T>, is_safe<U> >,
0366         boost::mp11::mp_valid<
0367             F,
0368             typename base_type<T>::type,
0369             typename base_type<U>::type
0370         >
0371     >;
0372 } // anon
0373 
0374 /////////////////////////////////////////////////////////////////
0375 // addition
0376 
0377 template<class T, class U>
0378 struct addition_result {
0379 private:
0380     using promotion_policy = typename common_promotion_policy<T, U>::type;
0381     using result_base_type =
0382         typename promotion_policy::template addition_result<T,U>::type;
0383 
0384     // if exception not possible
0385     constexpr static result_base_type
0386     return_value(const T & t, const U & u, std::false_type){
0387         return
0388             static_cast<result_base_type>(base_value(t))
0389             + static_cast<result_base_type>(base_value(u));
0390     }
0391 
0392     // if exception possible
0393     using exception_policy = typename common_exception_policy<T, U>::type;
0394 
0395     using r_type = checked_result<result_base_type>;
0396 
0397     constexpr static result_base_type
0398     return_value(const T & t, const U & u, std::true_type){
0399         const std::pair<result_base_type, result_base_type> r = casting_helper<
0400             exception_policy,
0401             result_base_type
0402         >(t, u);
0403 
0404         const r_type rx = checked_operation<
0405             result_base_type,
0406             dispatch_and_return<exception_policy, result_base_type>
0407         >::add(r.first, r.second);
0408 
0409         return
0410             rx.exception()
0411             ? r.first + r.second
0412             : rx.m_contents.m_r;
0413     }
0414 
0415     using r_type_interval_t = interval<r_type>;
0416 
0417     constexpr static const r_type_interval_t get_r_type_interval(){
0418         constexpr const r_type_interval_t t_interval{
0419             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
0420             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
0421         };
0422         constexpr const r_type_interval_t u_interval{
0423             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
0424             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
0425         };
0426         return t_interval + u_interval;
0427     }
0428     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
0429 
0430     constexpr static const interval<result_base_type> return_interval{
0431         r_type_interval.l.exception()
0432             ? std::numeric_limits<result_base_type>::min()
0433             : static_cast<result_base_type>(r_type_interval.l),
0434         r_type_interval.u.exception()
0435             ? std::numeric_limits<result_base_type>::max()
0436             : static_cast<result_base_type>(r_type_interval.u)
0437     };
0438 
0439     constexpr static bool exception_possible(){
0440         if(r_type_interval.l.exception())
0441             return true;
0442         if(r_type_interval.u.exception())
0443             return true;
0444         if(! return_interval.includes(r_type_interval))
0445             return true;
0446         return false;
0447     }
0448 
0449     constexpr static auto rl = return_interval.l;
0450     constexpr static auto ru = return_interval.u;
0451 
0452 public:
0453     using type =
0454         safe_base<
0455             result_base_type,
0456             rl,
0457             ru,
0458             promotion_policy,
0459             exception_policy
0460         >;
0461 
0462     constexpr static type return_value(const T & t, const U & u){
0463         return type(
0464             return_value(
0465                 t,
0466                 u,
0467                 std::integral_constant<bool, exception_possible()>()
0468             ),
0469             typename type::skip_validation()
0470         );
0471     }
0472 };
0473 
0474 template<class T, class U> using addition_operator
0475     = decltype( std::declval<T const&>() + std::declval<U const&>() );
0476 
0477 template<class T, class U>
0478 typename boost::lazy_enable_if_c<
0479     legal_overload<addition_operator, T, U>::value,
0480     addition_result<T, U>
0481 >::type
0482 constexpr inline operator+(const T & t, const U & u){
0483     return addition_result<T, U>::return_value(t, u);
0484 }
0485 
0486 template<class T, class U>
0487 typename std::enable_if<
0488     legal_overload<addition_operator, T, U>::value,
0489     T
0490 >::type
0491 constexpr inline operator+=(T & t, const U & u){
0492     t = static_cast<T>(t + u);
0493     return t;
0494 }
0495 
0496 /////////////////////////////////////////////////////////////////
0497 // subtraction
0498 
0499 template<class T, class U>
0500 struct subtraction_result {
0501 private:
0502     using promotion_policy = typename common_promotion_policy<T, U>::type;
0503     using result_base_type =
0504         typename promotion_policy::template subtraction_result<T, U>::type;
0505 
0506     // if exception not possible
0507     constexpr static result_base_type
0508     return_value(const T & t, const U & u, std::false_type){
0509         return
0510             static_cast<result_base_type>(base_value(t))
0511             - static_cast<result_base_type>(base_value(u));
0512     }
0513 
0514     // if exception possible
0515     using exception_policy = typename common_exception_policy<T, U>::type;
0516 
0517     using r_type = checked_result<result_base_type>;
0518 
0519     constexpr static result_base_type
0520     return_value(const T & t, const U & u, std::true_type){
0521         const std::pair<result_base_type, result_base_type> r = casting_helper<
0522             exception_policy,
0523             result_base_type
0524         >(t, u);
0525 
0526         const r_type rx = checked_operation<
0527             result_base_type,
0528             dispatch_and_return<exception_policy, result_base_type>
0529         >::subtract(r.first, r.second);
0530 
0531         return
0532             rx.exception()
0533             ? r.first + r.second
0534             : rx.m_contents.m_r;
0535     }
0536     using r_type_interval_t = interval<r_type>;
0537 
0538     constexpr static const r_type_interval_t get_r_type_interval(){
0539         constexpr const r_type_interval_t t_interval{
0540             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
0541             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
0542         };
0543 
0544         constexpr const r_type_interval_t u_interval{
0545             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
0546             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
0547         };
0548 
0549         return t_interval - u_interval;
0550     }
0551     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
0552 
0553     constexpr static const interval<result_base_type> return_interval{
0554         r_type_interval.l.exception()
0555             ? std::numeric_limits<result_base_type>::min()
0556             : static_cast<result_base_type>(r_type_interval.l),
0557         r_type_interval.u.exception()
0558             ? std::numeric_limits<result_base_type>::max()
0559             : static_cast<result_base_type>(r_type_interval.u)
0560     };
0561 
0562     constexpr static bool exception_possible(){
0563         if(r_type_interval.l.exception())
0564             return true;
0565         if(r_type_interval.u.exception())
0566             return true;
0567         if(! return_interval.includes(r_type_interval))
0568             return true;
0569         return false;
0570     }
0571 
0572 public:
0573     constexpr static auto rl = return_interval.l;
0574     constexpr static auto ru = return_interval.u;
0575 
0576     using type =
0577         safe_base<
0578             result_base_type,
0579             rl,
0580             ru,
0581             promotion_policy,
0582             exception_policy
0583         >;
0584 
0585     constexpr static type return_value(const T & t, const U & u){
0586         return type(
0587             return_value(
0588                 t,
0589                 u,
0590                 std::integral_constant<bool, exception_possible()>()
0591             ),
0592             typename type::skip_validation()
0593         );
0594     }
0595 };
0596 
0597 template<class T, class U> using subtraction_operator
0598     = decltype( std::declval<T const&>() - std::declval<U const&>() );
0599 
0600 template<class T, class U>
0601 typename boost::lazy_enable_if_c<
0602     legal_overload<subtraction_operator, T, U>::value,
0603     subtraction_result<T, U>
0604 >::type
0605 constexpr inline operator-(const T & t, const U & u){
0606     return subtraction_result<T, U>::return_value(t, u);
0607 }
0608 
0609 template<class T, class U>
0610 typename std::enable_if<
0611     legal_overload<subtraction_operator, T, U>::value,
0612     T
0613 >::type
0614 constexpr inline operator-=(T & t, const U & u){
0615     t = static_cast<T>(t - u);
0616     return t;
0617 }
0618 
0619 /////////////////////////////////////////////////////////////////
0620 // multiplication
0621 
0622 template<class T, class U>
0623 struct multiplication_result {
0624 private:
0625     using promotion_policy = typename common_promotion_policy<T, U>::type;
0626     using result_base_type =
0627         typename promotion_policy::template multiplication_result<T, U>::type;
0628 
0629     // if exception not possible
0630     constexpr static result_base_type
0631     return_value(const T & t, const U & u, std::false_type){
0632         return
0633             static_cast<result_base_type>(base_value(t))
0634             * static_cast<result_base_type>(base_value(u));
0635     }
0636 
0637     // if exception possible
0638     using exception_policy = typename common_exception_policy<T, U>::type;
0639 
0640     using r_type = checked_result<result_base_type>;
0641     
0642     constexpr static result_base_type
0643     return_value(const T & t, const U & u, std::true_type){
0644         const std::pair<result_base_type, result_base_type> r = casting_helper<
0645             exception_policy,
0646             result_base_type
0647         >(t, u);
0648 
0649         const r_type rx = checked_operation<
0650             result_base_type,
0651             dispatch_and_return<exception_policy, result_base_type>
0652         >::multiply(r.first, r.second);
0653 
0654         return
0655             rx.exception()
0656             ? r.first * r.second
0657             : rx.m_contents.m_r;
0658     }
0659 
0660     using r_type_interval_t = interval<r_type>;
0661 
0662     constexpr static r_type_interval_t get_r_type_interval(){
0663         constexpr const r_type_interval_t t_interval{
0664             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
0665             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
0666         };
0667 
0668         constexpr const r_type_interval_t u_interval{
0669             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
0670             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
0671         };
0672 
0673         return t_interval * u_interval;
0674     }
0675 
0676     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
0677 
0678     constexpr static const interval<result_base_type> return_interval{
0679         r_type_interval.l.exception()
0680             ? std::numeric_limits<result_base_type>::min()
0681             : static_cast<result_base_type>(r_type_interval.l),
0682         r_type_interval.u.exception()
0683             ? std::numeric_limits<result_base_type>::max()
0684             : static_cast<result_base_type>(r_type_interval.u)
0685     };
0686 
0687     constexpr static bool exception_possible(){
0688         if(r_type_interval.l.exception())
0689             return true;
0690         if(r_type_interval.u.exception())
0691             return true;
0692         if(! return_interval.includes(r_type_interval))
0693             return true;
0694         return false;
0695     }
0696 
0697     constexpr static auto rl = return_interval.l;
0698     constexpr static auto ru = return_interval.u;
0699 
0700 public:
0701     using type =
0702         safe_base<
0703             result_base_type,
0704             rl,
0705             ru,
0706             promotion_policy,
0707             exception_policy
0708         >;
0709 
0710     constexpr static type return_value(const T & t, const U & u){
0711         return type(
0712             return_value(
0713                 t,
0714                 u,
0715                 std::integral_constant<bool, exception_possible()>()
0716             ),
0717             typename type::skip_validation()
0718         );
0719     }
0720 };
0721 
0722 template<class T, class U> using multiplication_operator
0723     = decltype( std::declval<T const&>() * std::declval<U const&>() );
0724 
0725 template<class T, class U>
0726 typename boost::lazy_enable_if_c<
0727     legal_overload<multiplication_operator, T, U>::value,
0728     multiplication_result<T, U>
0729 >::type
0730 constexpr inline operator*(const T & t, const U & u){
0731     return multiplication_result<T, U>::return_value(t, u);
0732 }
0733 
0734 template<class T, class U>
0735 typename std::enable_if<
0736     legal_overload<multiplication_operator, T, U>::value,
0737     T
0738 >::type
0739 constexpr inline operator*=(T & t, const U & u){
0740     t = static_cast<T>(t * u);
0741     return t;
0742 }
0743 
0744 /////////////////////////////////////////////////////////////////
0745 // division
0746 
0747 // key idea here - result will never be larger than T
0748 template<class T, class U>
0749 struct division_result {
0750 private:
0751     using promotion_policy = typename common_promotion_policy<T, U>::type;
0752     using result_base_type =
0753         typename promotion_policy::template division_result<T, U>::type;
0754 
0755     // if exception not possible
0756     constexpr static result_base_type
0757     return_value(const T & t, const U & u, std::false_type){
0758         return
0759             static_cast<result_base_type>(base_value(t))
0760             / static_cast<result_base_type>(base_value(u));
0761     }
0762 
0763     // if exception possible
0764     using exception_policy = typename common_exception_policy<T, U>::type;
0765 
0766     constexpr static const int bits = std::min(
0767         std::numeric_limits<std::uintmax_t>::digits,
0768         std::max(std::initializer_list<int>{
0769             std::numeric_limits<result_base_type>::digits,
0770             std::numeric_limits<typename base_type<T>::type>::digits,
0771             std::numeric_limits<typename base_type<U>::type>::digits
0772         }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
0773     );
0774 
0775     using r_type = checked_result<result_base_type>;
0776 
0777     constexpr static result_base_type
0778     return_value(const T & t, const U & u, std::true_type){
0779         using temp_base = typename std::conditional<
0780             std::numeric_limits<result_base_type>::is_signed,
0781             typename boost::int_t<bits>::least,
0782             typename boost::uint_t<bits>::least
0783         >::type;
0784         using t_type = checked_result<temp_base>;
0785 
0786         const std::pair<t_type, t_type> r = casting_helper<
0787             exception_policy,
0788             temp_base
0789         >(t, u);
0790 
0791         const t_type rx = checked_operation<
0792             temp_base,
0793             dispatch_and_return<exception_policy, temp_base>
0794         >::divide(r.first, r.second);
0795 
0796         return
0797             rx.exception()
0798             ? r.first / r.second
0799             : rx;
0800     }
0801     using r_type_interval_t = interval<r_type>;
0802 
0803     constexpr static r_type_interval_t t_interval(){
0804         return r_type_interval_t{
0805             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
0806             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
0807         };
0808     };
0809 
0810     constexpr static r_type_interval_t u_interval(){
0811         return r_type_interval_t{
0812             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
0813             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
0814         };
0815     };
0816 
0817     constexpr static r_type_interval_t get_r_type_interval(){
0818         constexpr const r_type_interval_t t = t_interval();
0819         constexpr const r_type_interval_t u = u_interval();
0820 
0821         if(u.u < r_type(0) || u.l > r_type(0))
0822             return t / u;
0823         return utility::minmax(
0824             std::initializer_list<r_type> {
0825                 t.l / u.l,
0826                 t.l / r_type(-1),
0827                 t.l / r_type(1),
0828                 t.l / u.u,
0829                 t.u / u.l,
0830                 t.u / r_type(-1),
0831                 t.u / r_type(1),
0832                 t.u / u.u,
0833             }
0834         );
0835     }
0836 
0837     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
0838 
0839     constexpr static const interval<result_base_type> return_interval{
0840         r_type_interval.l.exception()
0841             ? std::numeric_limits<result_base_type>::min()
0842             : static_cast<result_base_type>(r_type_interval.l),
0843         r_type_interval.u.exception()
0844             ? std::numeric_limits<result_base_type>::max()
0845             : static_cast<result_base_type>(r_type_interval.u)
0846     };
0847 
0848     constexpr static bool exception_possible(){
0849         constexpr const r_type_interval_t ri = get_r_type_interval();
0850         constexpr const r_type_interval_t ui = u_interval();
0851         return
0852             static_cast<bool>(ui.includes(r_type(0)))
0853             || ri.l.exception()
0854             || ri.u.exception();
0855     }
0856 
0857     constexpr static auto rl = return_interval.l;
0858     constexpr static auto ru = return_interval.u;
0859 
0860 public:
0861     using type =
0862         safe_base<
0863             result_base_type,
0864             rl,
0865             ru,
0866             promotion_policy,
0867             exception_policy
0868         >;
0869 
0870     constexpr static type return_value(const T & t, const U & u){
0871         return type(
0872             return_value(
0873                 t,
0874                 u,
0875                 std::integral_constant<bool, exception_possible()>()
0876             ),
0877             typename type::skip_validation()
0878         );
0879     }
0880 };
0881 
0882 template<class T, class U> using division_operator
0883     = decltype( std::declval<T const&>() / std::declval<U const&>() );
0884 
0885 template<class T, class U>
0886 typename boost::lazy_enable_if_c<
0887     legal_overload<division_operator, T, U>::value,
0888     division_result<T, U>
0889 >::type
0890 constexpr inline operator/(const T & t, const U & u){
0891     return division_result<T, U>::return_value(t, u);
0892 }
0893 
0894 template<class T, class U>
0895 typename std::enable_if<
0896     legal_overload<division_operator, T, U>::value,
0897     T
0898 >::type
0899 constexpr inline operator/=(T & t, const U & u){
0900     t = static_cast<T>(t / u);
0901     return t;
0902 }
0903 
0904 /////////////////////////////////////////////////////////////////
0905 // modulus
0906 
0907 template<class T, class U>
0908 struct modulus_result {
0909 private:
0910     using promotion_policy = typename common_promotion_policy<T, U>::type;
0911     using result_base_type = typename promotion_policy::template modulus_result<T, U>::type;
0912 
0913     // if exception not possible
0914     constexpr static result_base_type
0915     return_value(const T & t, const U & u, std::false_type){
0916         return
0917             static_cast<result_base_type>(base_value(t))
0918             % static_cast<result_base_type>(base_value(u));
0919     }
0920 
0921     // if exception possible
0922     using exception_policy = typename common_exception_policy<T, U>::type;
0923 
0924     constexpr static const int bits = std::min(
0925         std::numeric_limits<std::uintmax_t>::digits,
0926         std::max(std::initializer_list<int>{
0927             std::numeric_limits<result_base_type>::digits,
0928             std::numeric_limits<typename base_type<T>::type>::digits,
0929             std::numeric_limits<typename base_type<U>::type>::digits
0930         }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
0931     );
0932 
0933     using r_type = checked_result<result_base_type>;
0934 
0935     constexpr static result_base_type
0936     return_value(const T & t, const U & u, std::true_type){
0937         using temp_base = typename std::conditional<
0938             std::numeric_limits<result_base_type>::is_signed,
0939             typename boost::int_t<bits>::least,
0940             typename boost::uint_t<bits>::least
0941         >::type;
0942         using t_type = checked_result<temp_base>;
0943         
0944         const std::pair<t_type, t_type> r = casting_helper<
0945             exception_policy,
0946             temp_base
0947         >(t, u);
0948 
0949         const t_type rx = checked_operation<
0950             temp_base,
0951             dispatch_and_return<exception_policy, temp_base>
0952         >::modulus(r.first, r.second);
0953 
0954         return
0955             rx.exception()
0956             ? r.first % r.second
0957             : rx;
0958     }
0959 
0960     using r_type_interval_t = interval<r_type>;
0961 
0962     constexpr static const r_type_interval_t t_interval(){
0963         return r_type_interval_t{
0964             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
0965             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
0966         };
0967     };
0968 
0969     constexpr static const r_type_interval_t u_interval(){
0970         return r_type_interval_t{
0971             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
0972             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
0973         };
0974     };
0975 
0976     constexpr static const r_type_interval_t get_r_type_interval(){
0977         constexpr const r_type_interval_t t = t_interval();
0978         constexpr const r_type_interval_t u = u_interval();
0979 
0980         if(u.u < r_type(0)
0981         || u.l > r_type(0))
0982             return t % u;
0983         return utility::minmax(
0984             std::initializer_list<r_type> {
0985                 t.l % u.l,
0986                 t.l % r_type(-1),
0987                 t.l % r_type(1),
0988                 t.l % u.u,
0989                 t.u % u.l,
0990                 t.u % r_type(-1),
0991                 t.u % r_type(1),
0992                 t.u % u.u,
0993             }
0994         );
0995     }
0996 
0997     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
0998 
0999     constexpr static const interval<result_base_type> return_interval{
1000         r_type_interval.l.exception()
1001             ? std::numeric_limits<result_base_type>::min()
1002             : static_cast<result_base_type>(r_type_interval.l),
1003         r_type_interval.u.exception()
1004             ? std::numeric_limits<result_base_type>::max()
1005             : static_cast<result_base_type>(r_type_interval.u)
1006     };
1007 
1008     constexpr static bool exception_possible(){
1009         constexpr const r_type_interval_t ri = get_r_type_interval();
1010         constexpr const r_type_interval_t ui = u_interval();
1011         return
1012             static_cast<bool>(ui.includes(r_type(0)))
1013             || ri.l.exception()
1014             || ri.u.exception();
1015     }
1016 
1017     constexpr static auto rl = return_interval.l;
1018     constexpr static auto ru = return_interval.u;
1019 
1020 public:
1021     using type =
1022         safe_base<
1023             result_base_type,
1024             rl,
1025             ru,
1026             promotion_policy,
1027             exception_policy
1028         >;
1029 
1030     constexpr static type return_value(const T & t, const U & u){
1031         return type(
1032             return_value(
1033                 t,
1034                 u,
1035                 std::integral_constant<bool, exception_possible()>()
1036             ),
1037             typename type::skip_validation()
1038         );
1039     }
1040 };
1041 
1042 template<class T, class U> using modulus_operator
1043     = decltype( std::declval<T const&>() % std::declval<U const&>() );
1044 
1045 template<class T, class U>
1046 typename boost::lazy_enable_if_c<
1047     legal_overload<modulus_operator, T, U>::value,
1048     modulus_result<T, U>
1049 >::type
1050 constexpr inline operator%(const T & t, const U & u){
1051     // see https://en.wikipedia.org/wiki/Modulo_operation
1052     return modulus_result<T, U>::return_value(t, u);
1053 }
1054 
1055 template<class T, class U>
1056 typename std::enable_if<
1057     legal_overload<modulus_operator, T, U>::value,
1058     T
1059 >::type
1060 constexpr inline operator%=(T & t, const U & u){
1061     t = static_cast<T>(t % u);
1062     return t;
1063 }
1064 
1065 /////////////////////////////////////////////////////////////////
1066 // comparison
1067 
1068 // less than
1069 
1070 template<class T, class U>
1071 struct less_than_result {
1072 private:
1073     using promotion_policy = typename common_promotion_policy<T, U>::type;
1074 
1075     using result_base_type =
1076         typename promotion_policy::template comparison_result<T, U>::type;
1077 
1078     // if exception not possible
1079     constexpr static bool
1080     return_value(const T & t, const U & u, std::false_type){
1081         return
1082             static_cast<result_base_type>(base_value(t))
1083             < static_cast<result_base_type>(base_value(u));
1084     }
1085 
1086     using exception_policy = typename common_exception_policy<T, U>::type;
1087 
1088     using r_type = checked_result<result_base_type>;
1089 
1090     // if exception possible
1091     constexpr static bool
1092     return_value(const T & t, const U & u, std::true_type){
1093         const std::pair<result_base_type, result_base_type> r = casting_helper<
1094             exception_policy,
1095             result_base_type
1096         >(t, u);
1097 
1098         return safe_compare::less_than(r.first, r.second);
1099     }
1100 
1101     using r_type_interval_t = interval<r_type>;
1102 
1103     constexpr static bool interval_open(const r_type_interval_t & t){
1104         return t.l.exception() || t.u.exception();
1105     }
1106 
1107 public:
1108     constexpr static bool
1109     return_value(const T & t, const U & u){
1110         constexpr const r_type_interval_t t_interval{
1111             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1112             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1113         };
1114         constexpr const r_type_interval_t u_interval{
1115             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1116             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1117         };
1118 
1119         if(t_interval < u_interval)
1120             return true;
1121         if(t_interval > u_interval)
1122             return false;
1123 
1124         constexpr bool exception_possible
1125             = interval_open(t_interval) || interval_open(u_interval);
1126 
1127         return return_value(
1128             t,
1129             u,
1130             std::integral_constant<bool, exception_possible>()
1131         );
1132     }
1133 };
1134 
1135 template<class T, class U> using less_than_operator
1136     = decltype( std::declval<T const&>() < std::declval<U const&>() );
1137 template<class T, class U> using greater_than_operator
1138     = decltype( std::declval<T const&>() > std::declval<U const&>() );
1139 template<class T, class U> using less_than_or_equal_operator
1140     = decltype( std::declval<T const&>() <= std::declval<U const&>() );
1141 template<class T, class U> using greater_than_or_equal_operator
1142     = decltype( std::declval<T const&>() >= std::declval<U const&>() );
1143 
1144 template<class T, class U>
1145 typename std::enable_if<
1146     legal_overload<less_than_operator, T, U>::value,
1147     bool
1148 >::type
1149 constexpr inline operator<(const T & lhs, const U & rhs) {
1150     return less_than_result<T, U>::return_value(lhs, rhs);
1151 }
1152 
1153 template<class T, class U>
1154 typename std::enable_if<
1155     legal_overload<greater_than_operator, T, U>::value,
1156     bool
1157 >::type
1158 constexpr inline operator>(const T & lhs, const U & rhs) {
1159     return rhs < lhs;
1160 }
1161 
1162 template<class T, class U>
1163 typename std::enable_if<
1164     legal_overload<greater_than_or_equal_operator, T, U>::value,
1165     bool
1166 >::type
1167 constexpr inline operator>=(const T & lhs, const U & rhs) {
1168     return ! ( lhs < rhs );
1169 }
1170 
1171 template<class T, class U>
1172 typename std::enable_if<
1173     legal_overload<less_than_or_equal_operator, T, U>::value,
1174     bool
1175 >::type
1176 constexpr inline operator<=(const T & lhs, const U & rhs) {
1177     return ! ( lhs > rhs );
1178 }
1179 
1180 // equal
1181 
1182 template<class T, class U>
1183 struct equal_result {
1184 private:
1185     using promotion_policy = typename common_promotion_policy<T, U>::type;
1186 
1187     using result_base_type =
1188         typename promotion_policy::template comparison_result<T, U>::type;
1189 
1190     // if exception not possible
1191     constexpr static bool
1192     return_value(const T & t, const U & u, std::false_type){
1193         return
1194             static_cast<result_base_type>(base_value(t))
1195             == static_cast<result_base_type>(base_value(u));
1196     }
1197 
1198     using exception_policy = typename common_exception_policy<T, U>::type;
1199 
1200     using r_type = checked_result<result_base_type>;
1201 
1202     // exception possible
1203     constexpr static bool
1204     return_value(const T & t, const U & u, std::true_type){
1205         const std::pair<result_base_type, result_base_type> r = casting_helper<
1206             exception_policy,
1207             result_base_type
1208         >(t, u);
1209 
1210         return safe_compare::equal(r.first, r.second);
1211     }
1212 
1213     using r_type_interval = interval<r_type>;
1214 
1215     constexpr static bool interval_open(const r_type_interval & t){
1216         return t.l.exception() || t.u.exception();
1217     }
1218 
1219 public:
1220     constexpr static bool
1221     return_value(const T & t, const U & u){
1222         constexpr const r_type_interval t_interval{
1223             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1224             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1225         };
1226 
1227         constexpr const r_type_interval u_interval{
1228             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1229             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1230         };
1231 
1232         if(! intersect(t_interval, u_interval))
1233             return false;
1234 
1235         constexpr bool exception_possible
1236             = interval_open(t_interval) || interval_open(u_interval);
1237 
1238         return return_value(
1239             t,
1240             u,
1241             std::integral_constant<bool, exception_possible>()
1242         );
1243     }
1244 };
1245 
1246 template<class T, class U> using equal_to_operator
1247     = decltype( std::declval<T const&>() == std::declval<U const&>() );
1248 template<class T, class U> using not_equal_to_operator
1249     = decltype( std::declval<T const&>() != std::declval<U const&>() );
1250 
1251 template<class T, class U>
1252 typename std::enable_if<
1253     legal_overload<equal_to_operator, T, U>::value,
1254     bool
1255 >::type
1256 constexpr inline operator==(const T & lhs, const U & rhs) {
1257     return equal_result<T, U>::return_value(lhs, rhs);
1258 }
1259 
1260 template<class T, class U>
1261 typename std::enable_if<
1262     legal_overload<not_equal_to_operator, T, U>::value,
1263     bool
1264 >::type
1265 constexpr inline operator!=(const T & lhs, const U & rhs) {
1266     return ! (lhs == rhs);
1267 }
1268 
1269 /////////////////////////////////////////////////////////////////////////
1270 // The following operators only make sense when applied to integet types
1271 
1272 /////////////////////////////////////////////////////////////////////////
1273 // shift operators
1274 
1275 // left shift
1276 template<class T, class U>
1277 struct left_shift_result {
1278 private:
1279     using promotion_policy = typename common_promotion_policy<T, U>::type;
1280     using result_base_type =
1281         typename promotion_policy::template left_shift_result<T, U>::type;
1282 
1283     // if exception not possible
1284     constexpr static result_base_type
1285     return_value(const T & t, const U & u, std::false_type){
1286         return
1287             static_cast<result_base_type>(base_value(t))
1288             << static_cast<result_base_type>(base_value(u));
1289     }
1290 
1291     // exception possible
1292     using exception_policy = typename common_exception_policy<T, U>::type;
1293     
1294     using r_type = checked_result<result_base_type>;
1295 
1296     constexpr static result_base_type
1297     return_value(const T & t, const U & u, std::true_type){
1298         const std::pair<result_base_type, result_base_type> r = casting_helper<
1299             exception_policy,
1300             result_base_type
1301         >(t, u);
1302 
1303         const r_type rx = checked_operation<
1304             result_base_type,
1305             dispatch_and_return<exception_policy, result_base_type>
1306         >::left_shift(r.first, r.second);
1307 
1308         return
1309             rx.exception()
1310             ? r.first << r.second
1311             : rx.m_contents.m_r;
1312     }
1313 
1314     using r_type_interval_t = interval<r_type>;
1315 
1316     constexpr static r_type_interval_t get_r_type_interval(){
1317         constexpr const r_type_interval_t t_interval{
1318             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1319             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1320         };
1321 
1322         constexpr const r_type_interval_t u_interval{
1323             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1324             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1325         };
1326         return (t_interval << u_interval);
1327     }
1328 
1329     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
1330 
1331     constexpr static const interval<result_base_type> return_interval{
1332         r_type_interval.l.exception()
1333             ? std::numeric_limits<result_base_type>::min()
1334             : static_cast<result_base_type>(r_type_interval.l),
1335         r_type_interval.u.exception()
1336             ? std::numeric_limits<result_base_type>::max()
1337             : static_cast<result_base_type>(r_type_interval.u)
1338     };
1339 
1340     constexpr static bool exception_possible(){
1341         if(r_type_interval.l.exception())
1342             return true;
1343         if(r_type_interval.u.exception())
1344             return true;
1345         if(! return_interval.includes(r_type_interval))
1346             return true;
1347         return false;
1348     }
1349 
1350     constexpr static const auto rl = return_interval.l;
1351     constexpr static const auto ru = return_interval.u;
1352 
1353 public:
1354     using type =
1355         safe_base<
1356             result_base_type,
1357             rl,
1358             ru,
1359             promotion_policy,
1360             exception_policy
1361         >;
1362 
1363     constexpr static type return_value(const T & t, const U & u){
1364         return type(
1365             return_value(
1366                 t,
1367                 u,
1368                 std::integral_constant<bool, exception_possible()>()
1369             ),
1370             typename type::skip_validation()
1371         );
1372     }
1373 };
1374 
1375 template<class T, class U> using left_shift_operator
1376     = decltype( std::declval<T const&>() << std::declval<U const&>() );
1377 
1378 template<class T, class U>
1379 typename boost::lazy_enable_if_c<
1380     // exclude usage of << for file input here
1381     boost::safe_numerics::Numeric<T>()
1382     && legal_overload<left_shift_operator, T, U>::value,
1383     left_shift_result<T, U>
1384 >::type
1385 constexpr inline operator<<(const T & t, const U & u){
1386     // INT13-CPP
1387     // C++ standards document N4618 & 5.8.2
1388     return left_shift_result<T, U>::return_value(t, u);
1389 }
1390 
1391 template<class T, class U>
1392 typename std::enable_if<
1393     // exclude usage of << for file output here
1394     boost::safe_numerics::Numeric<T>()
1395     && legal_overload<left_shift_operator, T, U>::value,
1396     T
1397 >::type
1398 constexpr inline operator<<=(T & t, const U & u){
1399     t = static_cast<T>(t << u);
1400     return t;
1401 }
1402 
1403 template<class T, class CharT, class Traits> using stream_output_operator
1404     = decltype( std::declval<std::basic_ostream<CharT, Traits> &>() >> std::declval<T const&>() );
1405 
1406 template<class T, class CharT, class Traits>
1407 typename boost::lazy_enable_if_c<
1408     boost::mp11::mp_valid< stream_output_operator, T, CharT, Traits>::value,
1409     std::basic_ostream<CharT, Traits> &
1410 >::type
1411 constexpr inline operator>>(
1412     std::basic_ostream<CharT, Traits> & os,
1413     const T & t
1414 ){
1415     // INT13-CPP
1416     // C++ standards document N4618 & 5.8.2
1417     t.output(os);
1418     return os;
1419 }
1420 
1421 /////////////////////////////////////////////////////////////////
1422 // right shift
1423 template<class T, class U>
1424 struct right_shift_result {
1425     using promotion_policy = typename common_promotion_policy<T, U>::type;
1426     using result_base_type =
1427         typename promotion_policy::template right_shift_result<T, U>::type;
1428 
1429     // if exception not possible
1430     constexpr static result_base_type
1431     return_value(const T & t, const U & u, std::false_type){
1432         return
1433             static_cast<result_base_type>(base_value(t))
1434             >> static_cast<result_base_type>(base_value(u));
1435     }
1436 
1437     // exception possible
1438     using exception_policy = typename common_exception_policy<T, U>::type;
1439 
1440     using r_type = checked_result<result_base_type>;
1441 
1442     constexpr static result_base_type
1443     return_value(const T & t, const U & u, std::true_type){
1444         const std::pair<result_base_type, result_base_type> r = casting_helper<
1445             exception_policy,
1446             result_base_type
1447         >(t, u);
1448 
1449         const r_type rx = checked_operation<
1450             result_base_type,
1451             dispatch_and_return<exception_policy, result_base_type>
1452         >::right_shift(r.first, r.second);
1453 
1454         return
1455             rx.exception()
1456             ? r.first >> r.second
1457             : rx.m_contents.m_r;
1458     }
1459 
1460     using r_type_interval_t = interval<r_type>;
1461 
1462     constexpr static r_type_interval_t t_interval(){
1463         return r_type_interval_t(
1464             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1465             checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1466         );
1467     };
1468 
1469     constexpr static r_type_interval_t u_interval(){
1470         return r_type_interval_t(
1471             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1472             checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1473         );
1474     }
1475     constexpr static r_type_interval_t get_r_type_interval(){;
1476         return (t_interval() >> u_interval());
1477     }
1478 
1479     constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
1480 
1481     constexpr static const interval<result_base_type> return_interval{
1482         r_type_interval.l.exception()
1483             ? std::numeric_limits<result_base_type>::min()
1484             : static_cast<result_base_type>(r_type_interval.l),
1485         r_type_interval.u.exception()
1486             ? std::numeric_limits<result_base_type>::max()
1487             : static_cast<result_base_type>(r_type_interval.u)
1488     };
1489 
1490     constexpr static bool exception_possible(){
1491         constexpr const r_type_interval_t ri = r_type_interval;
1492         constexpr const r_type_interval_t ti = t_interval();
1493         constexpr const r_type_interval_t ui = u_interval();
1494         return static_cast<bool>(
1495             // note undesirable coupling with checked::shift right here !
1496             ui.u > checked_result<result_base_type>(
1497                 std::numeric_limits<result_base_type>::digits
1498             )
1499             || ti.l < checked_result<result_base_type>(0)
1500             || ui.l < checked_result<result_base_type>(0)
1501             || ri.l.exception()
1502             || ri.u.exception()
1503         );
1504     }
1505 
1506     constexpr static auto rl = return_interval.l;
1507     constexpr static auto ru = return_interval.u;
1508 
1509 public:
1510     using type =
1511         safe_base<
1512             result_base_type,
1513             rl,
1514             ru,
1515             promotion_policy,
1516             exception_policy
1517         >;
1518 
1519     constexpr static type return_value(const T & t, const U & u){
1520         return type(
1521             return_value(
1522                 t,
1523                 u,
1524                 std::integral_constant<bool, exception_possible()>()
1525             ),
1526             typename type::skip_validation()
1527         );
1528     }
1529 };
1530 
1531 template<class T, class U> using right_shift_operator
1532     = decltype( std::declval<T const&>() >> std::declval<U const&>() );
1533 
1534 template<class T, class U>
1535 typename boost::lazy_enable_if_c<
1536     // exclude usage of >> for file input here
1537     boost::safe_numerics::Numeric<T>()
1538     && legal_overload<right_shift_operator, T, U>::value,
1539     right_shift_result<T, U>
1540 >::type
1541 constexpr inline operator>>(const T & t, const U & u){
1542     // INT13-CPP
1543     // C++ standards document N4618 & 5.8.2
1544     return right_shift_result<T, U>::return_value(t, u);
1545 }
1546 
1547 template<class T, class U>
1548 typename std::enable_if<
1549     // exclude usage of << for file output here
1550     boost::safe_numerics::Numeric<T>()
1551     && legal_overload<right_shift_operator, T, U>::value,
1552     T
1553 >::type
1554 constexpr inline operator>>=(T & t, const U & u){
1555     t = static_cast<T>(t >> u);
1556     return t;
1557 }
1558 
1559 template<class T, class CharT, class Traits> using stream_input_operator
1560     = decltype( std::declval<std::basic_istream<CharT, Traits> &>() >> std::declval<T const&>() );
1561 
1562 template<class T, class CharT, class Traits>
1563 typename boost::lazy_enable_if_c<
1564     boost::mp11::mp_valid< stream_input_operator, T, CharT, Traits>::value,
1565     std::basic_istream<CharT, Traits> &
1566 >::type
1567 constexpr inline operator>>(
1568     std::basic_istream<CharT, Traits> & is,
1569     const T & t
1570 ){
1571     // INT13-CPP
1572     // C++ standards document N4618 & 5.8.2
1573     t.input(is);
1574     return is;
1575 }
1576 
1577 /////////////////////////////////////////////////////////////////
1578 // bitwise operators
1579 
1580 // operator |
1581 template<class T, class U>
1582 struct bitwise_or_result {
1583 private:
1584     using promotion_policy = typename common_promotion_policy<T, U>::type;
1585     using result_base_type =
1586         typename promotion_policy::template bitwise_or_result<T, U>::type;
1587 
1588     // according to the C++ standard, the bitwise operators are executed as if
1589     // the operands are consider a logical array of bits.  That is, there is no
1590     // sense that these are signed numbers.
1591 
1592     using r_type = typename std::make_unsigned<result_base_type>::type;
1593     using r_type_interval_t = interval<r_type>;
1594     using exception_policy = typename common_exception_policy<T, U>::type;
1595 
1596 public:
1597     // lazy_enable_if_c depends on this
1598     using type = safe_base<
1599         result_base_type,
1600         //r_interval.l,
1601         r_type(0),
1602         //r_interval.u,
1603         utility::round_out(
1604             std::max(
1605                 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1606                 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1607             )
1608         ),
1609         promotion_policy,
1610         exception_policy
1611     >;
1612 
1613     constexpr static type return_value(const T & t, const U & u){
1614         return type(
1615             static_cast<result_base_type>(base_value(t))
1616             | static_cast<result_base_type>(base_value(u)),
1617             typename type::skip_validation()
1618         );
1619     }
1620 };
1621 
1622 template<class T, class U> using bitwise_or_operator
1623     = decltype( std::declval<T const&>() | std::declval<U const&>() );
1624 
1625 template<class T, class U>
1626 typename boost::lazy_enable_if_c<
1627     legal_overload<bitwise_or_operator, T, U>::value,
1628     bitwise_or_result<T, U>
1629 >::type
1630 constexpr inline operator|(const T & t, const U & u){
1631     return bitwise_or_result<T, U>::return_value(t, u);
1632 }
1633 
1634 template<class T, class U>
1635 typename std::enable_if<
1636     legal_overload<bitwise_or_operator, T, U>::value,
1637     T
1638 >::type
1639 constexpr inline operator|=(T & t, const U & u){
1640     t = static_cast<T>(t | u);
1641     return t;
1642 }
1643 
1644 // operator &
1645 template<class T, class U>
1646 struct bitwise_and_result {
1647 private:
1648     using promotion_policy = typename common_promotion_policy<T, U>::type;
1649     using result_base_type =
1650         typename promotion_policy::template bitwise_and_result<T, U>::type;
1651 
1652     // according to the C++ standard, the bitwise operators are executed as if
1653     // the operands are consider a logical array of bits.  That is, there is no
1654     // sense that these are signed numbers.
1655 
1656     using r_type = typename std::make_unsigned<result_base_type>::type;
1657     using r_type_interval_t = interval<r_type>;
1658     using exception_policy = typename common_exception_policy<T, U>::type;
1659 
1660 public:
1661     // lazy_enable_if_c depends on this
1662     using type = safe_base<
1663         result_base_type,
1664         //r_interval.l,
1665         r_type(0),
1666         //r_interval.u,
1667         utility::round_out(
1668             std::min(
1669                 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1670                 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1671             )
1672         ),
1673         promotion_policy,
1674         exception_policy
1675     >;
1676     
1677     constexpr static type return_value(const T & t, const U & u){
1678         return type(
1679             static_cast<result_base_type>(base_value(t))
1680             & static_cast<result_base_type>(base_value(u)),
1681             typename type::skip_validation()
1682         );
1683     }
1684 };
1685 
1686 template<class T, class U> using bitwise_and_operator
1687     = decltype( std::declval<T const&>() & std::declval<U const&>() );
1688 
1689 template<class T, class U>
1690 typename boost::lazy_enable_if_c<
1691     legal_overload<bitwise_and_operator, T, U>::value,
1692     bitwise_and_result<T, U>
1693 >::type
1694 constexpr inline operator&(const T & t, const U & u){
1695     return bitwise_and_result<T, U>::return_value(t, u);
1696 }
1697 
1698 template<class T, class U>
1699 typename std::enable_if<
1700     legal_overload<bitwise_and_operator, T, U>::value,
1701     T
1702 >::type
1703 constexpr inline operator&=(T & t, const U & u){
1704     t = static_cast<T>(t & u);
1705     return t;
1706 }
1707 
1708 // operator ^
1709 template<class T, class U>
1710 struct bitwise_xor_result {
1711     using promotion_policy = typename common_promotion_policy<T, U>::type;
1712     using result_base_type =
1713         typename promotion_policy::template bitwise_xor_result<T, U>::type;
1714 
1715     // according to the C++ standard, the bitwise operators are executed as if
1716     // the operands are consider a logical array of bits.  That is, there is no
1717     // sense that these are signed numbers.
1718 
1719     using r_type = typename std::make_unsigned<result_base_type>::type;
1720     using r_type_interval_t = interval<r_type>;
1721     using exception_policy = typename common_exception_policy<T, U>::type;
1722 
1723 public:
1724     // lazy_enable_if_c depends on this
1725     using type = safe_base<
1726         result_base_type,
1727         //r_interval.l,
1728         r_type(0),
1729         //r_interval.u,
1730         utility::round_out(
1731             std::max(
1732                 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1733                 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1734             )
1735         ),
1736         promotion_policy,
1737         exception_policy
1738     >;
1739 
1740     constexpr static type return_value(const T & t, const U & u){
1741         return type(
1742             static_cast<result_base_type>(base_value(t))
1743             ^ static_cast<result_base_type>(base_value(u)),
1744             typename type::skip_validation()
1745         );
1746     }
1747 };
1748 
1749 template<class T, class U> using bitwise_xor_operator
1750     = decltype( std::declval<T const&>() ^ std::declval<U const&>() );
1751 
1752 template<class T, class U>
1753 typename boost::lazy_enable_if_c<
1754     legal_overload<bitwise_xor_operator, T, U>::value,
1755     bitwise_xor_result<T, U>
1756 >::type
1757 constexpr inline operator^(const T & t, const U & u){
1758     return bitwise_xor_result<T, U>::return_value(t, u);
1759 }
1760 
1761 template<class T, class U>
1762 typename std::enable_if<
1763     legal_overload<bitwise_xor_operator, T, U>::value,
1764     T
1765 >::type
1766 constexpr inline operator^=(T & t, const U & u){
1767     t = static_cast<T>(t ^ u);
1768     return t;
1769 }
1770 
1771 /////////////////////////////////////////////////////////////////
1772 // stream helpers
1773 
1774 template<
1775     class T,
1776     T Min,
1777     T Max,
1778     class P, // promotion polic
1779     class E  // exception policy
1780 >
1781 template<
1782     class CharT,
1783     class Traits
1784 >
1785 inline void safe_base<T, Min, Max, P, E>::output(
1786     std::basic_ostream<CharT, Traits> & os
1787 ) const {
1788     os << (
1789         (std::is_same<T, signed char>::value
1790         || std::is_same<T, unsigned char>::value
1791         || std::is_same<T, wchar_t>::value
1792         ) ?
1793             static_cast<int>(m_t)
1794         :
1795             m_t
1796     );
1797 }
1798 
1799 template<
1800     class T,
1801     T Min,
1802     T Max,
1803     class P, // promotion polic
1804     class E  // exception policy
1805 >
1806 template<
1807     class CharT,
1808     class Traits
1809 >
1810 inline void safe_base<T, Min, Max, P, E>::input(
1811     std::basic_istream<CharT, Traits> & is
1812 ){
1813     if(std::is_same<T, signed char>::value
1814     || std::is_same<T, unsigned char>::value
1815     || std::is_same<T, wchar_t>::value
1816     ){
1817         int x;
1818         is >> x;
1819         m_t = validated_cast(x);
1820     }
1821     else{
1822         if(std::is_unsigned<T>::value){
1823             // reading a negative number into an unsigned variable cannot result in
1824             // a correct result.  But, C++ reads the absolute value, multiplies
1825             // it by -1 and stores the resulting value.  This is crazy - but there
1826             // it is!  Oh, and it doesn't set the failbit. We fix this behavior here
1827             is >> std::ws;
1828             int x = is.peek();
1829             // if the input string starts with a '-', we know its an error
1830             if(x == '-'){
1831                 // set fail bit
1832                 is.setstate(std::ios_base::failbit);
1833             }
1834         }
1835         is >> m_t;
1836         if(is.fail()){
1837             boost::safe_numerics::dispatch<
1838                 E,
1839                 boost::safe_numerics::safe_numerics_error::domain_error
1840             >(
1841                 "error in file input"
1842             );
1843         }
1844         else
1845             validated_cast(m_t);
1846     }
1847 }
1848 
1849 } // safe_numerics
1850 } // boost
1851 
1852 #endif // BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP