Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP
0002 #define BOOST_NUMERIC_CHECKED_INTEGER_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 // contains operations for doing checked aritmetic on NATIVE
0011 // C++ types.
0012 
0013 #include <limits>
0014 #include <type_traits> // is_integral, make_unsigned, enable_if
0015 #include <algorithm>   // std::max
0016 
0017 #include "checked_result.hpp"
0018 #include "checked_default.hpp"
0019 #include "safe_compare.hpp"
0020 #include "utility.hpp"
0021 #include "exception.hpp"
0022 
0023 namespace boost {
0024 namespace safe_numerics {
0025 
0026 // utility
0027 
0028 template<bool tf>
0029 using bool_type = typename std::conditional<tf, std::true_type, std::false_type>::type;
0030 
0031 ////////////////////////////////////////////////////
0032 // layer 0 - implement safe operations for intrinsic integers
0033 // Note presumption of twos complement integer arithmetic
0034 
0035 // convert an integral value to some other integral type
0036 template<
0037     typename R,
0038     R Min,
0039     R Max,
0040     typename T,
0041     class F
0042 >
0043 struct heterogeneous_checked_operation<
0044     R,
0045     Min,
0046     Max,
0047     T,
0048     F,
0049     typename std::enable_if<
0050         std::is_integral<R>::value
0051         && std::is_integral<T>::value
0052     >::type
0053 >{
0054     ////////////////////////////////////////////////////
0055     // safe casting on primitive types
0056 
0057     struct cast_impl_detail {
0058         constexpr static checked_result<R>
0059         cast_impl(
0060             const T & t,
0061             std::true_type, // R is signed
0062             std::true_type  // T is signed
0063         ){
0064             // INT32-C Ensure that operations on signed
0065             // integers do not overflow
0066             return
0067             boost::safe_numerics::safe_compare::greater_than(t, Max) ?
0068                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0069                     "converted signed value too large"
0070                 )
0071             : boost::safe_numerics::safe_compare::less_than(t, Min) ?
0072                 F::template invoke<safe_numerics_error::negative_overflow_error>(
0073                     "converted signed value too small"
0074                 )
0075             :
0076                 checked_result<R>(static_cast<R>(t))
0077             ;
0078         }
0079         constexpr static checked_result<R>
0080         cast_impl(
0081             const T & t,
0082             std::true_type,  // R is signed
0083             std::false_type  // T is unsigned
0084         ){
0085             // INT30-C Ensure that unsigned integer operations
0086             // do not wrap
0087             return
0088             boost::safe_numerics::safe_compare::greater_than(t, Max) ?
0089                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0090                     "converted unsigned value too large"
0091                 )
0092             :
0093             boost::safe_numerics::safe_compare::less_than(t, Min) ?
0094                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0095                     "converted unsigned value too small"
0096                 )
0097             :
0098                 checked_result<R>(static_cast<R>(t))
0099             ;
0100         }
0101         constexpr static checked_result<R>
0102         cast_impl(
0103             const T & t,
0104             std::false_type, // R is unsigned
0105             std::false_type  // T is unsigned
0106         ){
0107             // INT32-C Ensure that operations on unsigned
0108             // integers do not overflow
0109             return
0110             boost::safe_numerics::safe_compare::greater_than(t, Max) ?
0111                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0112                     "converted unsigned value too large"
0113                 )
0114             :
0115             boost::safe_numerics::safe_compare::less_than(t, Min) ?
0116                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0117                     "converted unsigned value too small"
0118                 )
0119             :
0120                 checked_result<R>(static_cast<R>(t))
0121             ;
0122         }
0123         constexpr static checked_result<R>
0124         cast_impl(
0125             const T & t,
0126             std::false_type, // R is unsigned
0127             std::true_type   // T is signed
0128         ){
0129             return
0130             boost::safe_numerics::safe_compare::less_than(t, Min) ?
0131                 F::template invoke<safe_numerics_error::domain_error>(
0132                     "converted value to low or negative"
0133                 )
0134             :
0135             boost::safe_numerics::safe_compare::greater_than(t, Max) ?
0136                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0137                     "converted signed value too large"
0138                 )
0139             :
0140                 checked_result<R>(static_cast<R>(t))
0141             ;
0142         }
0143     }; // cast_impl_detail
0144 
0145     constexpr static checked_result<R>
0146     cast(const T & t){
0147         return
0148             cast_impl_detail::cast_impl(
0149                 t,
0150                 std::is_signed<R>(),
0151                 std::is_signed<T>()
0152             );
0153     }
0154 }; // heterogeneous_checked_operation
0155 
0156 // converting floating point value to integral type
0157 template<
0158     typename R,
0159     R Min,
0160     R Max,
0161     typename T,
0162     class F
0163 >
0164 struct heterogeneous_checked_operation<
0165     R,
0166     Min,
0167     Max,
0168     T,
0169     F,
0170     typename std::enable_if<
0171         std::is_integral<R>::value
0172         && std::is_floating_point<T>::value
0173     >::type
0174 >{
0175     constexpr static checked_result<R>
0176     cast(const T & t){
0177         return static_cast<R>(t);
0178     }
0179 }; // heterogeneous_checked_operation
0180 
0181 // converting integral value to floating point type
0182 
0183 // INT35-C. Use correct integer precisions
0184 template<
0185     typename R,
0186     R Min,
0187     R Max,
0188     typename T,
0189     class F
0190 >
0191 struct heterogeneous_checked_operation<
0192     R,
0193     Min,
0194     Max,
0195     T,
0196     F,
0197     typename std::enable_if<
0198         std::is_floating_point<R>::value
0199         && std::is_integral<T>::value
0200      >::type
0201  >{
0202      constexpr static checked_result<R>
0203      cast(const T & t){
0204         if(std::numeric_limits<R>::digits < std::numeric_limits<T>::digits){
0205             if(utility::significant_bits(t) > std::numeric_limits<R>::digits){
0206                 return F::invoke(
0207                     safe_numerics_error::precision_overflow_error,
0208                     "keep precision"
0209                 );
0210             }
0211         }
0212         return t;
0213     }
0214 }; // heterogeneous_checked_operation
0215 
0216 // binary operations on primitive integer types
0217 
0218 template<
0219     typename R,
0220     class F
0221 >
0222 struct checked_operation<R, F,
0223     typename std::enable_if<
0224         std::is_integral<R>::value
0225     >::type
0226 >{
0227     ////////////////////////////////////////////////////
0228     // safe addition on primitive types
0229 
0230     struct add_impl_detail {
0231         // result unsigned
0232         constexpr static checked_result<R> add(
0233             const R t,
0234             const R u,
0235             std::false_type // R unsigned
0236         ){
0237             return
0238                 // INT30-C. Ensure that unsigned integer operations do not wrap
0239                 std::numeric_limits<R>::max() - u < t ?
0240                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0241                         "addition result too large"
0242                     )
0243                 :
0244                     checked_result<R>(t + u)
0245             ;
0246         }
0247 
0248         // result signed
0249         constexpr static checked_result<R> add(
0250             const R t,
0251             const R u,
0252             std::true_type // R signed
0253         ){
0254         // INT32-C. Ensure that operations on signed integers do not result in overflow
0255             return
0256                 // INT32-C. Ensure that operations on signed integers do not result in overflow
0257                 ((u > 0) && (t > (std::numeric_limits<R>::max() - u))) ?
0258                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0259                         "addition result too large"
0260                     )
0261                 :
0262                 ((u < 0) && (t < (std::numeric_limits<R>::min() - u))) ?
0263                     F::template invoke<safe_numerics_error::negative_overflow_error>(
0264                         "addition result too low"
0265                     )
0266                 :
0267                     checked_result<R>(t + u)
0268             ;
0269         }
0270     }; // add_impl_detail
0271 
0272     constexpr static checked_result<R>
0273     add(const R & t, const R & u){
0274         return add_impl_detail::add(t, u, std::is_signed<R>());
0275     }
0276 
0277     ////////////////////////////////////////////////////
0278     // safe subtraction on primitive types
0279     struct subtract_impl_detail {
0280 
0281         // result unsigned
0282         constexpr static checked_result<R> subtract(
0283             const R t,
0284             const R u,
0285             std::false_type // R is unsigned
0286         ){
0287             // INT30-C. Ensure that unsigned integer operations do not wrap
0288             return
0289                 t < u ?
0290                     F::template invoke<safe_numerics_error::negative_overflow_error>(
0291                         "subtraction result cannot be negative"
0292                     )
0293                 :
0294                     checked_result<R>(t - u)
0295             ;
0296         }
0297 
0298         // result signed
0299         constexpr static checked_result<R> subtract(
0300             const R t,
0301             const R u,
0302             std::true_type // R is signed
0303         ){ // INT32-C
0304             return
0305                 // INT32-C. Ensure that operations on signed integers do not result in overflow
0306                 ((u > 0) && (t < (std::numeric_limits<R>::min() + u))) ?
0307                     F::template invoke<safe_numerics_error::negative_overflow_error>(
0308                         "subtraction result overflows result type"
0309                     )
0310                 :
0311                 ((u < 0) && (t > (std::numeric_limits<R>::max() + u))) ?
0312                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0313                         "subtraction result overflows result type"
0314                     )
0315                 :
0316                     checked_result<R>(t - u)
0317             ;
0318         }
0319 
0320     }; // subtract_impl_detail
0321 
0322     constexpr static checked_result<R> subtract(const R & t, const R & u){
0323         return subtract_impl_detail::subtract(t, u, std::is_signed<R>());
0324     }
0325 
0326     ////////////////////////////////////////////////////
0327     // safe minus on primitive types
0328     struct minus_impl_detail {
0329 
0330         // result unsigned
0331         constexpr static checked_result<R> minus(
0332             const R t,
0333             std::false_type // R is unsigned
0334         ){
0335             return t > 0 ?
0336                     F::template invoke<safe_numerics_error::negative_overflow_error>(
0337                         "minus unsigned would be negative"
0338                     )
0339                 :
0340                     // t == 0
0341                     checked_result<R>(0)
0342             ;
0343         }
0344 
0345         // result signed
0346         constexpr static checked_result<R> minus(
0347             const R t,
0348             std::true_type // R is signed
0349         ){ // INT32-C
0350             return t == std::numeric_limits<R>::min() ?
0351                 F::template invoke<safe_numerics_error::positive_overflow_error>(
0352                     "subtraction result overflows result type"
0353                 )
0354             :
0355                     checked_result<R>(-t)
0356             ;
0357         }
0358 
0359     }; // minus_impl_detail
0360 
0361     constexpr static checked_result<R> minus(const R & t){
0362         return minus_impl_detail::minus(t, std::is_signed<R>());
0363     }
0364 
0365     ////////////////////////////////////////////////////
0366     // safe multiplication on primitive types
0367 
0368     struct multiply_impl_detail {
0369 
0370         // result unsigned
0371         constexpr static checked_result<R> multiply(
0372             const R t,
0373             const R u,
0374             std::false_type,  // R is unsigned
0375             std::false_type   // !(sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
0376 
0377         ){
0378             // INT30-C
0379             // fast method using intermediate result guaranteed not to overflow
0380             // todo - replace std::uintmax_t with a size double the size of R
0381             using i_type = std::uintmax_t;
0382             return
0383                 static_cast<i_type>(t) * static_cast<i_type>(u)
0384                 > std::numeric_limits<R>::max() ?
0385                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0386                         "multiplication overflow"
0387                     )
0388                 :
0389                     checked_result<R>(t * u)
0390             ;
0391         }
0392         constexpr static checked_result<R> multiply(
0393             const R t,
0394             const R u,
0395             std::false_type,  // R is unsigned
0396             std::true_type    // (sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
0397 
0398         ){
0399             // INT30-C
0400             return
0401                 u > 0 && t > std::numeric_limits<R>::max() / u ?
0402                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0403                         "multiplication overflow"
0404                     )
0405                 :
0406                     checked_result<R>(t * u)
0407             ;
0408         }
0409 
0410         // result signed
0411         constexpr static checked_result<R> multiply(
0412             const R t,
0413             const R u,
0414             std::true_type, // R is signed
0415             std::false_type // ! (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
0416 
0417         ){
0418             // INT30-C
0419             // fast method using intermediate result guaranteed not to overflow
0420             // todo - replace std::intmax_t with a size double the size of R
0421             using i_type = std::intmax_t;
0422             return
0423                 (
0424                     static_cast<i_type>(t) * static_cast<i_type>(u)
0425                     > static_cast<i_type>(std::numeric_limits<R>::max())
0426                 ) ?
0427                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0428                         "multiplication overflow"
0429                     )
0430                 :
0431                 (
0432                     static_cast<i_type>(t) * static_cast<i_type>(u)
0433                     < static_cast<i_type>(std::numeric_limits<R>::min())
0434                 ) ?
0435                     F::template invoke<safe_numerics_error::negative_overflow_error>(
0436                         "multiplication overflow"
0437                     )
0438                 :
0439                     checked_result<R>(t * u)
0440             ;
0441         }
0442         constexpr static checked_result<R> multiply(
0443             const R t,
0444             const R u,
0445             std::true_type,   // R is signed
0446             std::true_type    // (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
0447         ){ // INT32-C
0448             return t > 0 ?
0449                 u > 0 ?
0450                     t > std::numeric_limits<R>::max() / u ?
0451                         F::template invoke<safe_numerics_error::positive_overflow_error>(
0452                             "multiplication overflow"
0453                         )
0454                     :
0455                         checked_result<R>(t * u)
0456                 : // u <= 0
0457                     u < std::numeric_limits<R>::min() / t ?
0458                         F::template invoke<safe_numerics_error::negative_overflow_error>(
0459                             "multiplication overflow"
0460                         )
0461                     :
0462                         checked_result<R>(t * u)
0463             : // t <= 0
0464                 u > 0 ?
0465                     t < std::numeric_limits<R>::min() / u ?
0466                         F::template invoke<safe_numerics_error::negative_overflow_error>(
0467                             "multiplication overflow"
0468                         )
0469                     :
0470                         checked_result<R>(t * u)
0471                 : // u <= 0
0472                     t != 0 && u < std::numeric_limits<R>::max() / t ?
0473                         F::template invoke<safe_numerics_error::positive_overflow_error>(
0474                             "multiplication overflow"
0475                         )
0476                     :
0477                         checked_result<R>(t * u)
0478             ;
0479         }
0480     }; // multiply_impl_detail
0481 
0482     constexpr static checked_result<R> multiply(const R & t, const R & u){
0483         return multiply_impl_detail::multiply(
0484             t,
0485             u,
0486             std::is_signed<R>(),
0487             std::integral_constant<
0488                 bool,
0489                 (sizeof(R) > sizeof(std::uintmax_t) / 2)
0490             >()
0491         );
0492     }
0493 
0494     ////////////////////////////////
0495     // safe division on unsafe types
0496 
0497     struct divide_impl_detail {
0498         constexpr static checked_result<R> divide(
0499             const R & t,
0500             const R & u,
0501             std::false_type // R is unsigned
0502         ){
0503             return t / u;
0504         }
0505 
0506         constexpr static checked_result<R> divide(
0507             const R & t,
0508             const R & u,
0509             std::true_type // R is signed
0510         ){
0511             return
0512                 (u == -1 && t == std::numeric_limits<R>::min()) ?
0513                     F::template invoke<safe_numerics_error::positive_overflow_error>(
0514                         "result cannot be represented"
0515                     )
0516                 :
0517                     checked_result<R>(t / u)
0518             ;
0519         }
0520     }; // divide_impl_detail
0521 
0522     // note that we presume that the size of R >= size of T
0523     constexpr static checked_result<R> divide(const R & t, const R & u){
0524         if(u == 0){
0525             return F::template invoke<safe_numerics_error::domain_error>(
0526                 "divide by zero"
0527             );
0528         }
0529         return divide_impl_detail::divide(t, u, std::is_signed<R>());
0530     }
0531 
0532     ////////////////////////////////
0533     // safe modulus on unsafe types
0534 
0535     struct modulus_impl_detail {
0536         constexpr static checked_result<R> modulus(
0537             const R & t,
0538             const R & u,
0539             std::false_type // R is unsigned
0540         ){
0541             return t % u;
0542         }
0543 
0544         constexpr static checked_result<R> modulus(
0545             const R & t,
0546             const R & u,
0547             std::true_type // R is signed
0548         ){
0549             if(u >= 0)
0550                 return t % u;
0551             checked_result<R> ux = checked::minus(u);
0552             if(ux.exception())
0553                 return t;
0554             return t % static_cast<R>(ux);
0555         }
0556     }; // modulus_impl_detail
0557 
0558     constexpr static checked_result<R> modulus(const R & t, const R & u){
0559         if(0 == u)
0560             return F::template invoke<safe_numerics_error::domain_error>(
0561                 "denominator is zero"
0562             );
0563 
0564         // why to we need abs here? the sign of the modulus is the sign of the
0565         // dividend. Consider -128 % -1  The result of this operation should be -1
0566         // but if I use t % u the x86 hardware uses the divide instruction
0567         // capturing the modulus as a side effect.  When it does this, it
0568         // invokes the operation -128 / -1 -> 128 which overflows a signed type
0569         // and provokes a hardware exception.  We can fix this using abs()
0570         // since -128 % -1 = -128 % 1 = 0
0571         return modulus_impl_detail::modulus(t, u, typename std::is_signed<R>::type());
0572     }
0573 
0574     ///////////////////////////////////
0575     // shift operations
0576 
0577     struct left_shift_integer_detail {
0578 
0579         #if 0
0580         // todo - optimize for gcc to exploit builtin
0581         /* for gcc compilers
0582         int __builtin_clz (unsigned int x)
0583               Returns the number of leading 0-bits in x, starting at the
0584               most significant bit position.  If x is 0, the result is undefined.
0585         */
0586 
0587         #ifndef __has_feature         // Optional of course.
0588           #define __has_feature(x) 0  // Compatibility with non-clang compilers.
0589         #endif
0590 
0591         template<typename T>
0592         constexpr unsigned int leading_zeros(const T & t){
0593             if(0 == t)
0594                 return 0;
0595             #if __has_feature(builtin_clz)
0596                 return  __builtin_clz(t);
0597             #else
0598             #endif
0599         }
0600         #endif
0601 
0602         // INT34-C C++
0603 
0604         // standard paragraph 5.8 / 2
0605         // The value of E1 << E2 is E1 left-shifted E2 bit positions;
0606         // vacated bits are zero-filled.
0607         constexpr static checked_result<R> left_shift(
0608             const R & t,
0609             const R & u,
0610             std::false_type // R is unsigned
0611         ){
0612             // the value of the result is E1 x 2^E2, reduced modulo one more than
0613             // the maximum value representable in the result type.
0614 
0615             // see 5.8 & 1
0616             // if right operand is
0617             // greater than or equal to the length in bits of the promoted left operand.
0618             if(
0619                 safe_compare::greater_than(
0620                     u,
0621                     std::numeric_limits<R>::digits - utility::significant_bits(t)
0622                 )
0623             ){
0624                 // behavior is undefined
0625                 return F::template invoke<safe_numerics_error::shift_too_large>(
0626                    "shifting left more bits than available is undefined behavior"
0627                 );
0628             }
0629             return t << u;
0630         }
0631 
0632         constexpr static checked_result<R> left_shift(
0633             const R & t,
0634             const R & u,
0635             std::true_type // R is signed
0636         ){
0637             // and [E1] has a non-negative value
0638             if(t >= 0){
0639                 // and E1 x 2^E2 is representable in the corresponding
0640                 // unsigned type of the result type,
0641 
0642                 // see 5.8 & 1
0643                 // if right operand is
0644                 // greater than or equal to the length in bits of the promoted left operand.
0645                 if(
0646                     safe_compare::greater_than(
0647                         u,
0648                         std::numeric_limits<R>::digits - utility::significant_bits(t)
0649                     )
0650                 ){
0651                     // behavior is undefined
0652                     return F::template invoke<safe_numerics_error::shift_too_large>(
0653                        "shifting left more bits than available"
0654                     );
0655                 }
0656                 else{
0657                     return t << u;
0658                 }
0659             }
0660             // otherwise, the behavior is undefined.
0661             return F::template invoke<safe_numerics_error::negative_shift>(
0662                "shifting a negative value"
0663             );
0664         }
0665 
0666     }; // left_shift_integer_detail
0667 
0668     constexpr static checked_result<R> left_shift(
0669         const R & t,
0670         const R & u
0671     ){
0672         // INT34-C - Do not shift an expression by a negative number of bits
0673 
0674         // standard paragraph 5.8 & 1
0675         // if the right operand is negative
0676         if(u == 0){
0677             return t;
0678         }
0679         if(u < 0){
0680             return F::template invoke<safe_numerics_error::negative_shift>(
0681                "shifting negative amount"
0682             );
0683         }
0684         if(u > std::numeric_limits<R>::digits){
0685             // behavior is undefined
0686             return F::template invoke<safe_numerics_error::shift_too_large>(
0687                "shifting more bits than available"
0688             );
0689         }
0690         return left_shift_integer_detail::left_shift(t, u, std::is_signed<R>());
0691     }
0692 
0693     // right shift
0694 
0695     struct right_shift_integer_detail {
0696 
0697         // INT34-C C++
0698 
0699         // standard paragraph 5.8 / 3
0700         // The value of E1 << E2 is E1 left-shifted E2 bit positions;
0701         // vacated bits are zero-filled.
0702         constexpr static checked_result<R> right_shift(
0703             const R & t,
0704             const R & u,
0705             std::false_type // T is unsigned
0706         ){
0707             // the value of the result is the integral part of the
0708             // quotient of E1/2E2
0709             return t >> u;
0710         }
0711 
0712         constexpr static checked_result<R> right_shift(
0713             const R & t,
0714             const R & u,
0715             std::true_type  // T is signed;
0716         ){
0717         if(t < 0){
0718             // note that the C++ standard considers this case is "implemenation
0719             // defined" rather than "undefined".
0720             return F::template invoke<safe_numerics_error::negative_value_shift>(
0721                 "shifting a negative value"
0722             );
0723          }
0724 
0725          // the value is the integral part of E1 / 2^E2,
0726          return t >> u;
0727         }
0728     }; // right_shift_integer_detail
0729 
0730     constexpr static checked_result<R> right_shift(
0731         const R & t,
0732         const R & u
0733     ){
0734         // INT34-C - Do not shift an expression by a negative number of bits
0735 
0736         // standard paragraph 5.8 & 1
0737         // if the right operand is negative
0738         if(u < 0){
0739             return F::template invoke<safe_numerics_error::negative_shift>(
0740                "shifting negative amount"
0741             );
0742         }
0743         if(u > std::numeric_limits<R>::digits){
0744             // behavior is undefined
0745             return F::template invoke<safe_numerics_error::shift_too_large>(
0746                "shifting more bits than available"
0747             );
0748         }
0749         return right_shift_integer_detail::right_shift(t, u ,std::is_signed<R>());
0750     }
0751 
0752     ///////////////////////////////////
0753     // bitwise operations
0754 
0755     // INT13-C Note: We don't enforce recommendation as acually written
0756     // as it would break too many programs.  Specifically, we permit signed
0757     // integer operands.
0758 
0759     constexpr static checked_result<R> bitwise_or(const R & t, const R & u){
0760         using namespace boost::safe_numerics::utility;
0761         const unsigned int result_size
0762             = std::max(significant_bits(t), significant_bits(u));
0763 
0764         if(result_size > bits_type<R>::value){
0765             return F::template invoke<safe_numerics_error::positive_overflow_error>(
0766                 "result type too small to hold bitwise or"
0767             );
0768         }
0769         return t | u;
0770     }
0771 
0772     constexpr static checked_result<R> bitwise_xor(const R & t, const R & u){
0773         using namespace boost::safe_numerics::utility;
0774         const unsigned int result_size
0775             = std::max(significant_bits(t), significant_bits(u));
0776 
0777         if(result_size > bits_type<R>::value){
0778             return F::template invoke<safe_numerics_error::positive_overflow_error>(
0779                 "result type too small to hold bitwise or"
0780             );
0781         }
0782         return t ^ u;
0783     }
0784 
0785     constexpr static checked_result<R> bitwise_and(const R & t, const R & u){
0786         using namespace boost::safe_numerics::utility;
0787         const unsigned int result_size
0788             = std::min(significant_bits(t), significant_bits(u));
0789 
0790         if(result_size > bits_type<R>::value){
0791             return F::template invoke<safe_numerics_error::positive_overflow_error>(
0792                 "result type too small to hold bitwise and"
0793             );
0794         }
0795         return t & u;
0796     }
0797 
0798     constexpr static checked_result<R> bitwise_not(const R & t){
0799         using namespace boost::safe_numerics::utility;
0800 
0801         if(significant_bits(t) > bits_type<R>::value){
0802             return F::template invoke<safe_numerics_error::positive_overflow_error>(
0803                 "result type too small to hold bitwise inverse"
0804             );
0805         }
0806         return ~t;
0807     }
0808 
0809 }; // checked_operation
0810 } // safe_numerics
0811 } // boost
0812 
0813 #endif // BOOST_NUMERIC_CHECKED_INTEGER_HPP