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
0005
0006
0007
0008
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
0040
0041
0042
0043
0044
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 }
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
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
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
0159
0160
0161 template<class Stored, Stored Min, Stored Max, class P, class E>
0162 constexpr inline 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
0172 template<class Stored, Stored Min, Stored Max, class P, class E>
0173 constexpr inline 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
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 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
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 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
0218
0219
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
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
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
0325
0326
0327
0328
0329
0330
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
0360
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 }
0373
0374
0375
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
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
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
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
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
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
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
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
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
0746
0747
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
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
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
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
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
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
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
1067
1068
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
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
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
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
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
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
1271
1272
1273
1274
1275
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
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
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
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
1387
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
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
1416
1417 t.output(os);
1418 return os;
1419 }
1420
1421
1422
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
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
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
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
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
1543
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
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
1572
1573 t.input(is);
1574 return is;
1575 }
1576
1577
1578
1579
1580
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
1589
1590
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
1598 using type = safe_base<
1599 result_base_type,
1600
1601 r_type(0),
1602
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
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
1653
1654
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
1662 using type = safe_base<
1663 result_base_type,
1664
1665 r_type(0),
1666
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
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
1716
1717
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
1725 using type = safe_base<
1726 result_base_type,
1727
1728 r_type(0),
1729
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
1773
1774 template<
1775 class T,
1776 T Min,
1777 T Max,
1778 class P,
1779 class E
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,
1804 class E
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
1824
1825
1826
1827 is >> std::ws;
1828 int x = is.peek();
1829
1830 if(x == '-'){
1831
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 }
1850 }
1851
1852 #endif