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