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