• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP
2 #define BOOST_NUMERIC_CHECKED_INTEGER_HPP
3 
4 //  Copyright (c) 2012 Robert Ramey
5 //
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 
10 // contains operations for doing checked aritmetic on NATIVE
11 // C++ types.
12 
13 #include <limits>
14 #include <type_traits> // is_integral, make_unsigned, enable_if
15 #include <algorithm>   // std::max
16 
17 #include "checked_result.hpp"
18 #include "checked_default.hpp"
19 #include "safe_compare.hpp"
20 #include "utility.hpp"
21 #include "exception.hpp"
22 
23 namespace boost {
24 namespace safe_numerics {
25 
26 // utility
27 
28 template<bool tf>
29 using bool_type = typename std::conditional<tf, std::true_type, std::false_type>::type;
30 
31 ////////////////////////////////////////////////////
32 // layer 0 - implement safe operations for intrinsic integers
33 // Note presumption of twos complement integer arithmetic
34 
35 // convert an integral value to some other integral type
36 template<
37     typename R,
38     R Min,
39     R Max,
40     typename T,
41     class F
42 >
43 struct heterogeneous_checked_operation<
44     R,
45     Min,
46     Max,
47     T,
48     F,
49     typename std::enable_if<
50         std::is_integral<R>::value
51         && std::is_integral<T>::value
52     >::type
53 >{
54     ////////////////////////////////////////////////////
55     // safe casting on primitive types
56 
57     struct cast_impl_detail {
58         constexpr static checked_result<R>
cast_implboost::safe_numerics::heterogeneous_checked_operation::cast_impl_detail59         cast_impl(
60             const T & t,
61             std::true_type, // R is signed
62             std::true_type  // T is signed
63         ){
64             // INT32-C Ensure that operations on signed
65             // integers do not overflow
66             return
67             boost::safe_numerics::safe_compare::greater_than(
68                 t,
69                 Max
70             ) ?
71                 F::template invoke<safe_numerics_error::positive_overflow_error>(
72                     "converted signed value too large"
73                 )
74             :
75             boost::safe_numerics::safe_compare::less_than(
76                 t,
77                 Min
78             ) ?
79                 F::template invoke<safe_numerics_error::negative_overflow_error>(
80                     "converted signed value too small"
81                 )
82             :
83                 checked_result<R>(static_cast<R>(t))
84             ;
85         }
86         constexpr static checked_result<R>
cast_implboost::safe_numerics::heterogeneous_checked_operation::cast_impl_detail87         cast_impl(
88             const T & t,
89             std::true_type,  // R is signed
90             std::false_type  // T is unsigned
91         ){
92             // INT30-C Ensure that unsigned integer operations
93             // do not wrap
94             return
95             boost::safe_numerics::safe_compare::greater_than(
96                 t,
97                 Max
98             ) ?
99                 F::template invoke<safe_numerics_error::positive_overflow_error>(
100                     "converted unsigned value too large"
101                 )
102             :
103                 checked_result<R>(static_cast<R>(t))
104             ;
105         }
106         constexpr static checked_result<R>
cast_implboost::safe_numerics::heterogeneous_checked_operation::cast_impl_detail107         cast_impl(
108             const T & t,
109             std::false_type, // R is unsigned
110             std::false_type  // T is unsigned
111         ){
112             // INT32-C Ensure that operations on unsigned
113             // integers do not overflow
114             return
115             boost::safe_numerics::safe_compare::greater_than(
116                 t,
117                 Max
118             ) ?
119                 F::template invoke<safe_numerics_error::positive_overflow_error>(
120                     "converted unsigned value too large"
121                 )
122             :
123                 checked_result<R>(static_cast<R>(t))
124             ;
125         }
126         constexpr static checked_result<R>
cast_implboost::safe_numerics::heterogeneous_checked_operation::cast_impl_detail127         cast_impl(
128             const T & t,
129             std::false_type, // R is unsigned
130             std::true_type   // T is signed
131         ){
132             return
133             boost::safe_numerics::safe_compare::less_than(t, 0) ?
134                 F::template invoke<safe_numerics_error::domain_error>(
135                     "converted negative value to unsigned"
136                 )
137             :
138             boost::safe_numerics::safe_compare::greater_than(
139                 t,
140                 Max
141             ) ?
142                 F::template invoke<safe_numerics_error::positive_overflow_error>(
143                     "converted signed value too large"
144                 )
145             :
146                 checked_result<R>(static_cast<R>(t))
147             ;
148         }
149     }; // cast_impl_detail
150 
151     constexpr static checked_result<R>
castboost::safe_numerics::heterogeneous_checked_operation152     cast(const T & t){
153         return
154             cast_impl_detail::cast_impl(
155                 t,
156                 std::is_signed<R>(),
157                 std::is_signed<T>()
158             );
159     }
160 };
161 
162 // converting floating point value to integral type
163 template<
164     typename R,
165     R Min,
166     R Max,
167     typename T,
168     class F
169 >
170 struct heterogeneous_checked_operation<
171     R,
172     Min,
173     Max,
174     T,
175     F,
176     typename std::enable_if<
177         std::is_integral<R>::value
178         && std::is_floating_point<T>::value
179     >::type
180 >{
181     constexpr static checked_result<R>
castboost::safe_numerics::heterogeneous_checked_operation182     cast(const T & t){
183         return static_cast<R>(t);
184     }
185 };
186 
187 // converting integral value to floating point type
188 
189 // INT35-C. Use correct integer precisions
190 template<
191     typename R,
192     R Min,
193     R Max,
194     typename T,
195     class F
196 >
197 struct heterogeneous_checked_operation<
198     R,
199     Min,
200     Max,
201     T,
202     F,
203     typename std::enable_if<
204         std::is_floating_point<R>::value
205         && std::is_integral<T>::value
206      >::type
207  >{
208      constexpr static checked_result<R>
castboost::safe_numerics::heterogeneous_checked_operation209      cast(const T & t){
210         if(std::numeric_limits<R>::digits < std::numeric_limits<T>::digits){
211             if(utility::significant_bits(t) > std::numeric_limits<R>::digits){
212                 return F::invoke(
213                     safe_numerics_error::precision_overflow_error,
214                     "keep precision"
215                 );
216             }
217         }
218         return t;
219     }
220 };
221 
222 // binary operations on primitive integer types
223 
224 template<
225     typename R,
226     class F
227 >
228 struct checked_operation<R, F,
229     typename std::enable_if<
230         std::is_integral<R>::value
231     >::type
232 >{
233     ////////////////////////////////////////////////////
234     // safe addition on primitive types
235 
236     struct add_impl_detail {
237         // result unsigned
addboost::safe_numerics::checked_operation::add_impl_detail238         constexpr static checked_result<R> add(
239             const R t,
240             const R u,
241             std::false_type // R unsigned
242         ){
243             return
244                 // INT30-C. Ensure that unsigned integer operations do not wrap
245                 std::numeric_limits<R>::max() - u < t ?
246                     F::template invoke<safe_numerics_error::positive_overflow_error>(
247                         "addition result too large"
248                     )
249                 :
250                     checked_result<R>(t + u)
251             ;
252         }
253 
254         // result signed
addboost::safe_numerics::checked_operation::add_impl_detail255         constexpr static checked_result<R> add(
256             const R t,
257             const R u,
258             std::true_type // R signed
259         ){
260         // INT32-C. Ensure that operations on signed integers do not result in overflow
261             return
262                 // INT32-C. Ensure that operations on signed integers do not result in overflow
263                 ((u > 0) && (t > (std::numeric_limits<R>::max() - u))) ?
264                     F::template invoke<safe_numerics_error::positive_overflow_error>(
265                         "addition result too large"
266                     )
267                 :
268                 ((u < 0) && (t < (std::numeric_limits<R>::min() - u))) ?
269                     F::template invoke<safe_numerics_error::negative_overflow_error>(
270                         "addition result too low"
271                     )
272                 :
273                     checked_result<R>(t + u)
274             ;
275         }
276     }; // add_impl_detail
277 
278     constexpr static checked_result<R>
addboost::safe_numerics::checked_operation279     add(const R & t, const R & u){
280         return add_impl_detail::add(t, u, std::is_signed<R>());
281     }
282 
283     ////////////////////////////////////////////////////
284     // safe subtraction on primitive types
285     struct subtract_impl_detail {
286 
287         // result unsigned
subtractboost::safe_numerics::checked_operation::subtract_impl_detail288         constexpr static checked_result<R> subtract(
289             const R t,
290             const R u,
291             std::false_type // R is unsigned
292         ){
293             // INT30-C. Ensure that unsigned integer operations do not wrap
294             return
295                 t < u ?
296                     F::template invoke<safe_numerics_error::negative_overflow_error>(
297                         "subtraction result cannot be negative"
298                     )
299                 :
300                     checked_result<R>(t - u)
301             ;
302         }
303 
304         // result signed
subtractboost::safe_numerics::checked_operation::subtract_impl_detail305         constexpr static checked_result<R> subtract(
306             const R t,
307             const R u,
308             std::true_type // R is signed
309         ){ // INT32-C
310             return
311                 // INT32-C. Ensure that operations on signed integers do not result in overflow
312                 ((u > 0) && (t < (std::numeric_limits<R>::min() + u))) ?
313                     F::template invoke<safe_numerics_error::negative_overflow_error>(
314                         "subtraction result overflows result type"
315                     )
316                 :
317                 ((u < 0) && (t > (std::numeric_limits<R>::max() + u))) ?
318                     F::template invoke<safe_numerics_error::positive_overflow_error>(
319                         "subtraction result overflows result type"
320                     )
321                 :
322                     checked_result<R>(t - u)
323             ;
324         }
325 
326     }; // subtract_impl_detail
327 
subtractboost::safe_numerics::checked_operation328     constexpr static checked_result<R> subtract(const R & t, const R & u){
329         return subtract_impl_detail::subtract(t, u, std::is_signed<R>());
330     }
331 
332     ////////////////////////////////////////////////////
333     // safe minus on primitive types
334     struct minus_impl_detail {
335 
336         // result unsigned
minusboost::safe_numerics::checked_operation::minus_impl_detail337         constexpr static checked_result<R> minus(
338             const R t,
339             std::false_type // R is unsigned
340         ){
341             return t > 0 ?
342                     F::template invoke<safe_numerics_error::negative_overflow_error>(
343                         "minus unsigned would be negative"
344                     )
345                 :
346                     // t == 0
347                     checked_result<R>(0)
348             ;
349         }
350 
351         // result signed
minusboost::safe_numerics::checked_operation::minus_impl_detail352         constexpr static checked_result<R> minus(
353             const R t,
354             std::true_type // R is signed
355         ){ // INT32-C
356             return t == std::numeric_limits<R>::min() ?
357                 F::template invoke<safe_numerics_error::positive_overflow_error>(
358                     "subtraction result overflows result type"
359                 )
360             :
361                     checked_result<R>(-t)
362             ;
363         }
364 
365     }; // minus_impl_detail
366 
minusboost::safe_numerics::checked_operation367     constexpr static checked_result<R> minus(const R & t){
368         return minus_impl_detail::minus(t, std::is_signed<R>());
369     }
370 
371     ////////////////////////////////////////////////////
372     // safe multiplication on primitive types
373 
374     struct multiply_impl_detail {
375 
376         // result unsigned
multiplyboost::safe_numerics::checked_operation::multiply_impl_detail377         constexpr static checked_result<R> multiply(
378             const R t,
379             const R u,
380             std::false_type,  // R is unsigned
381             std::false_type   // !(sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
382 
383         ){
384             // INT30-C
385             // fast method using intermediate result guaranteed not to overflow
386             // todo - replace std::uintmax_t with a size double the size of R
387             using i_type = std::uintmax_t;
388             return
389                 static_cast<i_type>(t) * static_cast<i_type>(u)
390                 > std::numeric_limits<R>::max() ?
391                     F::template invoke<safe_numerics_error::positive_overflow_error>(
392                         "multiplication overflow"
393                     )
394                 :
395                     checked_result<R>(t * u)
396             ;
397         }
multiplyboost::safe_numerics::checked_operation::multiply_impl_detail398         constexpr static checked_result<R> multiply(
399             const R t,
400             const R u,
401             std::false_type,  // R is unsigned
402             std::true_type    // (sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
403 
404         ){
405             // INT30-C
406             return
407                 u > 0 && t > std::numeric_limits<R>::max() / u ?
408                     F::template invoke<safe_numerics_error::positive_overflow_error>(
409                         "multiplication overflow"
410                     )
411                 :
412                     checked_result<R>(t * u)
413             ;
414         }
415 
416         // result signed
multiplyboost::safe_numerics::checked_operation::multiply_impl_detail417         constexpr static checked_result<R> multiply(
418             const R t,
419             const R u,
420             std::true_type, // R is signed
421             std::false_type // ! (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
422 
423         ){
424             // INT30-C
425             // fast method using intermediate result guaranteed not to overflow
426             // todo - replace std::intmax_t with a size double the size of R
427             using i_type = std::intmax_t;
428             return
429                 (
430                     static_cast<i_type>(t) * static_cast<i_type>(u)
431                     > static_cast<i_type>(std::numeric_limits<R>::max())
432                 ) ?
433                     F::template invoke<safe_numerics_error::positive_overflow_error>(
434                         "multiplication overflow"
435                     )
436                 :
437                 (
438                     static_cast<i_type>(t) * static_cast<i_type>(u)
439                     < static_cast<i_type>(std::numeric_limits<R>::min())
440                 ) ?
441                     F::template invoke<safe_numerics_error::negative_overflow_error>(
442                         "multiplication overflow"
443                     )
444                 :
445                     checked_result<R>(t * u)
446             ;
447         }
multiplyboost::safe_numerics::checked_operation::multiply_impl_detail448         constexpr static checked_result<R> multiply(
449             const R t,
450             const R u,
451             std::true_type,   // R is signed
452             std::true_type    // (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
453         ){ // INT32-C
454             return t > 0 ?
455                 u > 0 ?
456                     t > std::numeric_limits<R>::max() / u ?
457                         F::template invoke<safe_numerics_error::positive_overflow_error>(
458                             "multiplication overflow"
459                         )
460                     :
461                         checked_result<R>(t * u)
462                 : // u <= 0
463                     u < std::numeric_limits<R>::min() / t ?
464                         F::template invoke<safe_numerics_error::negative_overflow_error>(
465                             "multiplication overflow"
466                         )
467                     :
468                         checked_result<R>(t * u)
469             : // t <= 0
470                 u > 0 ?
471                     t < std::numeric_limits<R>::min() / u ?
472                         F::template invoke<safe_numerics_error::negative_overflow_error>(
473                             "multiplication overflow"
474                         )
475                     :
476                         checked_result<R>(t * u)
477                 : // u <= 0
478                     t != 0 && u < std::numeric_limits<R>::max() / t ?
479                         F::template invoke<safe_numerics_error::positive_overflow_error>(
480                             "multiplication overflow"
481                         )
482                     :
483                         checked_result<R>(t * u)
484             ;
485         }
486     }; // multiply_impl_detail
487 
multiplyboost::safe_numerics::checked_operation488     constexpr static checked_result<R> multiply(const R & t, const R & u){
489         return multiply_impl_detail::multiply(
490             t,
491             u,
492             std::is_signed<R>(),
493             std::integral_constant<
494                 bool,
495                 (sizeof(R) > sizeof(std::uintmax_t) / 2)
496             >()
497         );
498     }
499 
500     ////////////////////////////////
501     // safe division on unsafe types
502 
503     struct divide_impl_detail {
divideboost::safe_numerics::checked_operation::divide_impl_detail504         constexpr static checked_result<R> divide(
505             const R & t,
506             const R & u,
507             std::false_type // R is unsigned
508         ){
509             return t / u;
510         }
511 
divideboost::safe_numerics::checked_operation::divide_impl_detail512         constexpr static checked_result<R> divide(
513             const R & t,
514             const R & u,
515             std::true_type // R is signed
516         ){
517             return
518                 (u == -1 && t == std::numeric_limits<R>::min()) ?
519                     F::template invoke<safe_numerics_error::positive_overflow_error>(
520                         "result cannot be represented"
521                     )
522                 :
523                     checked_result<R>(t / u)
524             ;
525         }
526     }; // divide_impl_detail
527 
528     // note that we presume that the size of R >= size of T
divideboost::safe_numerics::checked_operation529     constexpr static checked_result<R> divide(const R & t, const R & u){
530         if(u == 0){
531             return F::template invoke<safe_numerics_error::domain_error>(
532                 "divide by zero"
533             );
534         }
535         return divide_impl_detail::divide(t, u, std::is_signed<R>());
536     }
537 
538     ////////////////////////////////
539     // safe modulus on unsafe types
540 
541     struct modulus_impl_detail {
modulusboost::safe_numerics::checked_operation::modulus_impl_detail542         constexpr static checked_result<R> modulus(
543             const R & t,
544             const R & u,
545             std::false_type // R is unsigned
546         ){
547             return t % u;
548         }
549 
modulusboost::safe_numerics::checked_operation::modulus_impl_detail550         constexpr static checked_result<R> modulus(
551             const R & t,
552             const R & u,
553             std::true_type // R is signed
554         ){
555             if(u >= 0)
556                 return t % u;
557             checked_result<R> ux = checked::minus(u);
558             if(ux.exception())
559                 return t;
560             return t % static_cast<R>(ux);
561         }
562     }; // modulus_impl_detail
563 
modulusboost::safe_numerics::checked_operation564     constexpr static checked_result<R> modulus(const R & t, const R & u){
565         if(0 == u)
566             return F::template invoke<safe_numerics_error::domain_error>(
567                 "denominator is zero"
568             );
569 
570         // why to we need abs here? the sign of the modulus is the sign of the
571         // dividend. Consider -128 % -1  The result of this operation should be -1
572         // but if I use t % u the x86 hardware uses the divide instruction
573         // capturing the modulus as a side effect.  When it does this, it
574         // invokes the operation -128 / -1 -> 128 which overflows a signed type
575         // and provokes a hardware exception.  We can fix this using abs()
576         // since -128 % -1 = -128 % 1 = 0
577         return modulus_impl_detail::modulus(t, u, typename std::is_signed<R>::type());
578     }
579 
580     ///////////////////////////////////
581     // shift operations
582 
583     struct left_shift_integer_detail {
584 
585         #if 0
586         // todo - optimize for gcc to exploit builtin
587         /* for gcc compilers
588         int __builtin_clz (unsigned int x)
589               Returns the number of leading 0-bits in x, starting at the
590               most significant bit position.  If x is 0, the result is undefined.
591         */
592 
593         #ifndef __has_feature         // Optional of course.
594           #define __has_feature(x) 0  // Compatibility with non-clang compilers.
595         #endif
596 
597         template<typename T>
598         constexpr unsigned int leading_zeros(const T & t){
599             if(0 == t)
600                 return 0;
601             #if __has_feature(builtin_clz)
602                 return  __builtin_clz(t);
603             #else
604             #endif
605         }
606         #endif
607 
608         // INT34-C C++
609 
610         // standard paragraph 5.8 / 2
611         // The value of E1 << E2 is E1 left-shifted E2 bit positions;
612         // vacated bits are zero-filled.
left_shiftboost::safe_numerics::checked_operation::left_shift_integer_detail613         constexpr static checked_result<R> left_shift(
614             const R & t,
615             const R & u,
616             std::false_type // R is unsigned
617         ){
618             // the value of the result is E1 x 2^E2, reduced modulo one more than
619             // the maximum value representable in the result type.
620 
621             // see 5.8 & 1
622             // if right operand is
623             // greater than or equal to the length in bits of the promoted left operand.
624             if(
625                 safe_compare::greater_than(
626                     u,
627                     std::numeric_limits<R>::digits - utility::significant_bits(t)
628                 )
629             ){
630                 // behavior is undefined
631                 return F::template invoke<safe_numerics_error::shift_too_large>(
632                    "shifting left more bits than available is undefined behavior"
633                 );
634             }
635             return t << u;
636         }
637 
left_shiftboost::safe_numerics::checked_operation::left_shift_integer_detail638         constexpr static checked_result<R> left_shift(
639             const R & t,
640             const R & u,
641             std::true_type // R is signed
642         ){
643             // and [E1] has a non-negative value
644             if(t >= 0){
645                 // and E1 x 2^E2 is representable in the corresponding
646                 // unsigned type of the result type,
647 
648                 // see 5.8 & 1
649                 // if right operand is
650                 // greater than or equal to the length in bits of the promoted left operand.
651                 if(
652                     safe_compare::greater_than(
653                         u,
654                         std::numeric_limits<R>::digits - utility::significant_bits(t)
655                     )
656                 ){
657                     // behavior is undefined
658                     return F::template invoke<safe_numerics_error::shift_too_large>(
659                        "shifting left more bits than available"
660                     );
661                 }
662                 else{
663                     return t << u;
664                 }
665             }
666             // otherwise, the behavior is undefined.
667             return F::template invoke<safe_numerics_error::negative_shift>(
668                "shifting a negative value"
669             );
670         }
671 
672     }; // left_shift_integer_detail
673 
left_shiftboost::safe_numerics::checked_operation674     constexpr static checked_result<R> left_shift(
675         const R & t,
676         const R & u
677     ){
678         // INT34-C - Do not shift an expression by a negative number of bits
679 
680         // standard paragraph 5.8 & 1
681         // if the right operand is negative
682         if(u == 0){
683             return t;
684         }
685         if(u < 0){
686             return F::template invoke<safe_numerics_error::negative_shift>(
687                "shifting negative amount"
688             );
689         }
690         if(u > std::numeric_limits<R>::digits){
691             // behavior is undefined
692             return F::template invoke<safe_numerics_error::shift_too_large>(
693                "shifting more bits than available"
694             );
695         }
696         return left_shift_integer_detail::left_shift(t, u, std::is_signed<R>());
697     }
698 
699 // right shift
700 
701     struct right_shift_integer_detail {
702 
703         // INT34-C C++
704 
705         // standard paragraph 5.8 / 3
706         // The value of E1 << E2 is E1 left-shifted E2 bit positions;
707         // vacated bits are zero-filled.
right_shiftboost::safe_numerics::checked_operation::right_shift_integer_detail708         constexpr static checked_result<R> right_shift(
709             const R & t,
710             const R & u,
711             std::false_type // T is unsigned
712         ){
713             // the value of the result is the integral part of the
714             // quotient of E1/2E2
715             return t >> u;
716         }
717 
right_shiftboost::safe_numerics::checked_operation::right_shift_integer_detail718         constexpr static checked_result<R> right_shift(
719             const R & t,
720             const R & u,
721             std::true_type  // T is signed;
722         ){
723         if(t < 0){
724             // note that the C++ standard considers this case is "implemenation
725             // defined" rather than "undefined".
726             return F::template invoke<safe_numerics_error::negative_value_shift>(
727                 "shifting a negative value"
728             );
729          }
730 
731          // the value is the integral part of E1 / 2^E2,
732          return t >> u;
733         }
734     }; // right_shift_integer_detail
735 
right_shiftboost::safe_numerics::checked_operation736 constexpr static checked_result<R> right_shift(
737     const R & t,
738     const R & u
739 ){
740     // INT34-C - Do not shift an expression by a negative number of bits
741 
742     // standard paragraph 5.8 & 1
743     // if the right operand is negative
744     if(u < 0){
745         return F::template invoke<safe_numerics_error::negative_shift>(
746            "shifting negative amount"
747         );
748     }
749     if(u > std::numeric_limits<R>::digits){
750         // behavior is undefined
751         return F::template invoke<safe_numerics_error::shift_too_large>(
752            "shifting more bits than available"
753         );
754     }
755     return right_shift_integer_detail::right_shift(t, u ,std::is_signed<R>());
756 }
757 
758 ///////////////////////////////////
759 // bitwise operations
760 
761 // INT13-C Note: We don't enforce recommendation as acually written
762 // as it would break too many programs.  Specifically, we permit signed
763 // integer operands.
764 
bitwise_orboost::safe_numerics::checked_operation765 constexpr static checked_result<R> bitwise_or(const R & t, const R & u){
766     using namespace boost::safe_numerics::utility;
767     const unsigned int result_size
768         = std::max(significant_bits(t), significant_bits(u));
769 
770     if(result_size > bits_type<R>::value){
771         return F::template invoke<safe_numerics_error::positive_overflow_error>(
772             "result type too small to hold bitwise or"
773         );
774     }
775     return t | u;
776 }
777 
bitwise_xorboost::safe_numerics::checked_operation778 constexpr static checked_result<R> bitwise_xor(const R & t, const R & u){
779     using namespace boost::safe_numerics::utility;
780     const unsigned int result_size
781         = std::max(significant_bits(t), significant_bits(u));
782 
783     if(result_size > bits_type<R>::value){
784         return F::template invoke<safe_numerics_error::positive_overflow_error>(
785             "result type too small to hold bitwise or"
786         );
787     }
788     return t ^ u;
789 }
790 
bitwise_andboost::safe_numerics::checked_operation791 constexpr static checked_result<R> bitwise_and(const R & t, const R & u){
792     using namespace boost::safe_numerics::utility;
793     const unsigned int result_size
794         = std::min(significant_bits(t), significant_bits(u));
795 
796     if(result_size > bits_type<R>::value){
797         return F::template invoke<safe_numerics_error::positive_overflow_error>(
798             "result type too small to hold bitwise and"
799         );
800     }
801     return t & u;
802 }
803 
bitwise_notboost::safe_numerics::checked_operation804 constexpr static checked_result<R> bitwise_not(const R & t){
805     using namespace boost::safe_numerics::utility;
806 
807     if(significant_bits(t) > bits_type<R>::value){
808         return F::template invoke<safe_numerics_error::positive_overflow_error>(
809             "result type too small to hold bitwise inverse"
810         );
811     }
812     return ~t;
813 }
814 
815 }; // checked_operation
816 } // safe_numerics
817 } // boost
818 
819 #endif // BOOST_NUMERIC_CHECKED_INTEGER_HPP
820