1 #ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
2 #define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
4 // Copyright (c) 2012 Robert Ramey
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)
11 #include <type_traits> // is_base_of, is_same, is_floating_point, conditional
12 #include <algorithm> // max
15 #include <boost/config.hpp>
17 #include <boost/core/enable_if.hpp> // lazy_enable_if
18 #include <boost/integer.hpp>
19 #include <boost/logic/tribool.hpp>
21 #include "checked_integer.hpp"
22 #include "checked_result.hpp"
23 #include "safe_base.hpp"
25 #include "interval.hpp"
26 #include "utility.hpp"
29 namespace safe_numerics {
31 /////////////////////////////////////////////////////////////////
34 template<typename R, R Min, R Max, typename E>
35 struct validate_detail {
36 using r_type = checked_result<R>;
38 struct exception_possible {
40 constexpr static R return_value(
44 const r_type rx = heterogeneous_checked_operation<
48 typename base_type<T>::type,
49 dispatch_and_return<E, R>
55 struct exception_not_possible {
57 constexpr static R return_value(
60 return static_cast<R>(base_value(t));
65 constexpr static R return_value(const T & t){
67 constexpr const interval<r_type> t_interval{
68 checked::cast<R>(base_value(std::numeric_limits<T>::min())),
69 checked::cast<R>(base_value(std::numeric_limits<T>::max()))
71 constexpr const interval<r_type> r_interval{r_type(Min), r_type(Max)};
74 true != static_cast<bool>(r_interval.excludes(t_interval)),
75 "can't cast from ranges that don't overlap"
78 return std::conditional<
79 static_cast<bool>(r_interval.includes(t_interval)),
80 exception_not_possible,
82 >::type::return_value(t);
86 template<class Stored, Stored Min, Stored Max, class P, class E>
88 constexpr Stored safe_base<Stored, Min, Max, P, E>::
89 validated_cast(const T & t) const {
90 return validate_detail<Stored,Min,Max,E>::return_value(t);
93 template<class Stored, Stored Min, Stored Max, class P, class E>
94 template<typename T, T N, class P1, class E1>
95 constexpr Stored safe_base<Stored, Min, Max, P, E>::
96 validated_cast(const safe_literal_impl<T, N, P1, E1> &) const {
97 constexpr const interval<Stored> this_interval{};
98 // if static values don't overlap, the program can never function
100 this_interval.includes(N),
101 "safe type cannot be constructed from this value"
103 return static_cast<Stored>(N);
106 /////////////////////////////////////////////////////////////////
109 template<class Stored, Stored Min, Stored Max, class P, class E>
110 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
117 template<class Stored, Stored Min, Stored Max, class P, class E>
118 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){
119 dispatch<E, safe_numerics_error::uninitialized_value>(
120 "safe values must be initialized"
124 // construct an instance of a safe type
125 // from an instance of a convertible underlying type.
126 template<class Stored, Stored Min, Stored Max, class P, class E>
128 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
130 typename std::enable_if<
135 m_t(validated_cast(t))
138 template<class Stored, Stored Min, Stored Max, class P, class E>
140 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
142 typename std::enable_if<
143 std::is_integral<T>::value,
147 m_t(validated_cast(t))
150 template<class Stored, Stored Min, Stored Max, class P, class E>
151 template<class T, T value>
152 constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
154 const std::integral_constant<T, value> &
156 m_t(validated_cast(value))
159 /////////////////////////////////////////////////////////////////
162 // cast to a builtin type from a safe type
163 template< class Stored, Stored Min, Stored Max, class P, class E>
166 typename std::enable_if<
167 ! boost::safe_numerics::is_safe<R>::value,
171 constexpr safe_base<Stored, Min, Max, P, E>::
172 operator R () const {
173 // if static values don't overlap, the program can never function
175 constexpr const interval<R> r_interval;
176 constexpr const interval<Stored> this_interval(Min, Max);
178 ! r_interval.excludes(this_interval),
179 "safe type cannot be constructed with this type"
183 return validate_detail<
185 std::numeric_limits<R>::min(),
186 std::numeric_limits<R>::max(),
188 >::return_value(*this);
191 // cast to the underlying builtin type from a safe type
192 template<class Stored, Stored Min, Stored Max, class P, class E>
193 constexpr safe_base<Stored, Min, Max, P, E>::
194 operator Stored () const {
198 /////////////////////////////////////////////////////////////////
201 template<class T, class U>
202 struct common_exception_policy {
203 static_assert(is_safe<T>::value || is_safe<U>::value,
204 "at least one type must be a safe type"
207 using t_exception_policy = typename get_exception_policy<T>::type;
208 using u_exception_policy = typename get_exception_policy<U>::type;
211 std::is_same<t_exception_policy, u_exception_policy>::value
212 || std::is_same<t_exception_policy, void>::value
213 || std::is_same<void, u_exception_policy>::value,
214 "if the exception policies are different, one must be void!"
218 ! (std::is_same<t_exception_policy, void>::value
219 && std::is_same<void, u_exception_policy>::value),
220 "at least one exception policy must not be void"
224 typename std::conditional<
225 !std::is_same<void, u_exception_policy>::value,
227 typename std::conditional<
228 !std::is_same<void, t_exception_policy>::value,
235 !std::is_same<void, type>::value,
236 "exception_policy is void"
240 template<class T, class U>
241 struct common_promotion_policy {
242 static_assert(is_safe<T>::value || is_safe<U>::value,
243 "at least one type must be a safe type"
245 using t_promotion_policy = typename get_promotion_policy<T>::type;
246 using u_promotion_policy = typename get_promotion_policy<U>::type;
248 std::is_same<t_promotion_policy, u_promotion_policy>::value
249 ||std::is_same<t_promotion_policy, void>::value
250 ||std::is_same<void, u_promotion_policy>::value,
251 "if the promotion policies are different, one must be void!"
254 ! (std::is_same<t_promotion_policy, void>::value
255 && std::is_same<void, u_promotion_policy>::value),
256 "at least one promotion policy must not be void"
260 typename std::conditional<
261 ! std::is_same<void, u_promotion_policy>::value,
263 typename std::conditional<
264 ! std::is_same<void, t_promotion_policy>::value,
271 ! std::is_same<void, type>::value,
272 "promotion_policy is void"
277 // give the resultant base type, figure out what the final result
278 // type will be. Note we currently need this because we support
279 // return of only safe integer types. Someday ..., we'll support
280 // all other safe types including float and user defined ones.
282 // helper - cast arguments to binary operators to a specified
285 template<class EP, class R, class T, class U>
287 constexpr static casting_helper(const T & t, const U & u){
288 using r_type = checked_result<R>;
289 const r_type tx = heterogeneous_checked_operation<
291 std::numeric_limits<R>::min(),
292 std::numeric_limits<R>::max(),
293 typename base_type<T>::type,
294 dispatch_and_return<EP, R>
295 >::cast(base_value(t));
296 const R tr = tx.exception()
300 const r_type ux = heterogeneous_checked_operation<
302 std::numeric_limits<R>::min(),
303 std::numeric_limits<R>::max(),
304 typename base_type<U>::type,
305 dispatch_and_return<EP, R>
306 >::cast(base_value(u));
307 const R ur = ux.exception()
310 return std::pair<R, R>(tr, ur);
313 // Note: the following global operators will be found via
314 // argument dependent lookup.
316 /////////////////////////////////////////////////////////////////
319 template<class T, class U>
320 struct addition_result {
322 using promotion_policy = typename common_promotion_policy<T, U>::type;
323 using result_base_type =
324 typename promotion_policy::template addition_result<T,U>::type;
326 // if exception not possible
327 constexpr static result_base_type
328 return_value(const T & t, const U & u, std::false_type){
330 static_cast<result_base_type>(base_value(t))
331 + static_cast<result_base_type>(base_value(u));
334 // if exception possible
335 using exception_policy = typename common_exception_policy<T, U>::type;
337 using r_type = checked_result<result_base_type>;
339 constexpr static result_base_type
340 return_value(const T & t, const U & u, std::true_type){
341 const std::pair<result_base_type, result_base_type> r = casting_helper<
346 const r_type rx = checked_operation<
348 dispatch_and_return<exception_policy, result_base_type>
349 >::add(r.first, r.second);
357 using r_type_interval_t = interval<r_type>;
359 constexpr static const r_type_interval_t get_r_type_interval(){
360 constexpr const r_type_interval_t t_interval{
361 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
362 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
364 constexpr const r_type_interval_t u_interval{
365 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
366 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
368 return t_interval + u_interval;
370 constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
372 constexpr static const interval<result_base_type> return_interval{
373 r_type_interval.l.exception()
374 ? std::numeric_limits<result_base_type>::min()
375 : static_cast<result_base_type>(r_type_interval.l),
376 r_type_interval.u.exception()
377 ? std::numeric_limits<result_base_type>::max()
378 : static_cast<result_base_type>(r_type_interval.u)
381 constexpr static bool exception_possible(){
382 if(r_type_interval.l.exception())
384 if(r_type_interval.u.exception())
386 if(! return_interval.includes(r_type_interval))
391 constexpr static auto rl = return_interval.l;
392 constexpr static auto ru = return_interval.u;
404 constexpr static type return_value(const T & t, const U & u){
409 std::integral_constant<bool, exception_possible()>()
411 typename type::skip_validation()
416 template<class T, class U>
417 typename boost::lazy_enable_if_c<
418 is_safe<T>::value || is_safe<U>::value,
419 addition_result<T, U>
421 constexpr operator+(const T & t, const U & u){
422 return addition_result<T, U>::return_value(t, u);
425 template<class T, class U>
426 typename std::enable_if<
427 is_safe<T>::value || is_safe<U>::value,
430 constexpr operator+=(T & t, const U & u){
431 t = static_cast<T>(t + u);
435 /////////////////////////////////////////////////////////////////
438 template<class T, class U>
439 struct subtraction_result {
441 using promotion_policy = typename common_promotion_policy<T, U>::type;
442 using result_base_type =
443 typename promotion_policy::template subtraction_result<T, U>::type;
445 // if exception not possible
446 constexpr static result_base_type
447 return_value(const T & t, const U & u, std::false_type){
449 static_cast<result_base_type>(base_value(t))
450 - static_cast<result_base_type>(base_value(u));
453 // if exception possible
454 using exception_policy = typename common_exception_policy<T, U>::type;
456 using r_type = checked_result<result_base_type>;
458 constexpr static result_base_type
459 return_value(const T & t, const U & u, std::true_type){
460 const std::pair<result_base_type, result_base_type> r = casting_helper<
465 const r_type rx = checked_operation<
467 dispatch_and_return<exception_policy, result_base_type>
468 >::subtract(r.first, r.second);
475 using r_type_interval_t = interval<r_type>;
477 constexpr static const r_type_interval_t get_r_type_interval(){
478 constexpr const r_type_interval_t t_interval{
479 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
480 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
483 constexpr const r_type_interval_t u_interval{
484 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
485 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
488 return t_interval - u_interval;
490 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
492 constexpr static const interval<result_base_type> return_interval{
493 r_type_interval.l.exception()
494 ? std::numeric_limits<result_base_type>::min()
495 : static_cast<result_base_type>(r_type_interval.l),
496 r_type_interval.u.exception()
497 ? std::numeric_limits<result_base_type>::max()
498 : static_cast<result_base_type>(r_type_interval.u)
501 constexpr static bool exception_possible(){
502 if(r_type_interval.l.exception())
504 if(r_type_interval.u.exception())
506 if(! return_interval.includes(r_type_interval))
512 constexpr static auto rl = return_interval.l;
513 constexpr static auto ru = return_interval.u;
524 constexpr static type return_value(const T & t, const U & u){
529 std::integral_constant<bool, exception_possible()>()
531 typename type::skip_validation()
536 template<class T, class U>
537 typename boost::lazy_enable_if_c<
538 is_safe<T>::value || is_safe<U>::value,
539 subtraction_result<T, U>
541 constexpr operator-(const T & t, const U & u){
542 return subtraction_result<T, U>::return_value(t, u);
545 template<class T, class U>
546 typename std::enable_if<
547 is_safe<T>::value || is_safe<U>::value,
550 constexpr operator-=(T & t, const U & u){
551 t = static_cast<T>(t - u);
555 /////////////////////////////////////////////////////////////////
558 template<class T, class U>
559 struct multiplication_result {
561 using promotion_policy = typename common_promotion_policy<T, U>::type;
562 using result_base_type =
563 typename promotion_policy::template multiplication_result<T, U>::type;
565 // if exception not possible
566 constexpr static result_base_type
567 return_value(const T & t, const U & u, std::false_type){
569 static_cast<result_base_type>(base_value(t))
570 * static_cast<result_base_type>(base_value(u));
573 // if exception possible
574 using exception_policy = typename common_exception_policy<T, U>::type;
576 using r_type = checked_result<result_base_type>;
578 constexpr static result_base_type
579 return_value(const T & t, const U & u, std::true_type){
580 const std::pair<result_base_type, result_base_type> r = casting_helper<
585 const r_type rx = checked_operation<
587 dispatch_and_return<exception_policy, result_base_type>
588 >::multiply(r.first, r.second);
596 using r_type_interval_t = interval<r_type>;
598 constexpr static r_type_interval_t get_r_type_interval(){
599 constexpr const r_type_interval_t t_interval{
600 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
601 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
604 constexpr const r_type_interval_t u_interval{
605 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
606 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
609 return t_interval * u_interval;
612 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
614 constexpr static const interval<result_base_type> return_interval{
615 r_type_interval.l.exception()
616 ? std::numeric_limits<result_base_type>::min()
617 : static_cast<result_base_type>(r_type_interval.l),
618 r_type_interval.u.exception()
619 ? std::numeric_limits<result_base_type>::max()
620 : static_cast<result_base_type>(r_type_interval.u)
623 constexpr static bool exception_possible(){
624 if(r_type_interval.l.exception())
626 if(r_type_interval.u.exception())
628 if(! return_interval.includes(r_type_interval))
633 constexpr static auto rl = return_interval.l;
634 constexpr static auto ru = return_interval.u;
646 constexpr static type return_value(const T & t, const U & u){
651 std::integral_constant<bool, exception_possible()>()
653 typename type::skip_validation()
658 template<class T, class U>
659 typename boost::lazy_enable_if_c<
660 is_safe<T>::value || is_safe<U>::value,
661 multiplication_result<T, U>
663 constexpr operator*(const T & t, const U & u){
664 // argument dependent lookup should guarentee that we only get here
665 return multiplication_result<T, U>::return_value(t, u);
668 template<class T, class U>
669 typename std::enable_if<
670 is_safe<T>::value || is_safe<U>::value,
673 constexpr operator*=(T & t, const U & u){
674 t = static_cast<T>(t * u);
678 /////////////////////////////////////////////////////////////////
681 // key idea here - result will never be larger than T
682 template<class T, class U>
683 struct division_result {
685 using promotion_policy = typename common_promotion_policy<T, U>::type;
686 using result_base_type =
687 typename promotion_policy::template division_result<T, U>::type;
689 // if exception not possible
690 constexpr static result_base_type
691 return_value(const T & t, const U & u, std::false_type){
693 static_cast<result_base_type>(base_value(t))
694 / static_cast<result_base_type>(base_value(u));
697 // if exception possible
698 using exception_policy = typename common_exception_policy<T, U>::type;
700 constexpr static int bits = std::min(
701 std::numeric_limits<std::uintmax_t>::digits,
702 std::max(std::initializer_list<int>{
703 std::numeric_limits<result_base_type>::digits,
704 std::numeric_limits<typename base_type<T>::type>::digits,
705 std::numeric_limits<typename base_type<U>::type>::digits
706 }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
709 using r_type = checked_result<result_base_type>;
711 constexpr static result_base_type
712 return_value(const T & t, const U & u, std::true_type){
713 using temp_base = typename std::conditional<
714 std::numeric_limits<result_base_type>::is_signed,
715 typename boost::int_t<bits>::least,
716 typename boost::uint_t<bits>::least
718 using t_type = checked_result<temp_base>;
720 const std::pair<t_type, t_type> r = casting_helper<
725 const t_type rx = checked_operation<
727 dispatch_and_return<exception_policy, temp_base>
728 >::divide(r.first, r.second);
735 using r_type_interval_t = interval<r_type>;
737 constexpr static r_type_interval_t t_interval(){
738 return r_type_interval_t{
739 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
740 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
744 constexpr static r_type_interval_t u_interval(){
745 return r_type_interval_t{
746 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
747 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
751 constexpr static r_type_interval_t get_r_type_interval(){
752 constexpr const r_type_interval_t t = t_interval();
753 constexpr const r_type_interval_t u = u_interval();
755 if(u.u < r_type(0) || u.l > r_type(0))
757 return utility::minmax(
758 std::initializer_list<r_type> {
771 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
773 constexpr static const interval<result_base_type> return_interval{
774 r_type_interval.l.exception()
775 ? std::numeric_limits<result_base_type>::min()
776 : static_cast<result_base_type>(r_type_interval.l),
777 r_type_interval.u.exception()
778 ? std::numeric_limits<result_base_type>::max()
779 : static_cast<result_base_type>(r_type_interval.u)
782 constexpr static bool exception_possible(){
783 constexpr const r_type_interval_t ri = get_r_type_interval();
784 constexpr const r_type_interval_t ui = u_interval();
786 static_cast<bool>(ui.includes(r_type(0)))
791 constexpr static auto rl = return_interval.l;
792 constexpr static auto ru = return_interval.u;
804 constexpr static type return_value(const T & t, const U & u){
809 std::integral_constant<bool, exception_possible()>()
811 typename type::skip_validation()
816 template<class T, class U>
817 typename boost::lazy_enable_if_c<
818 is_safe<T>::value || is_safe<U>::value,
819 division_result<T, U>
821 constexpr operator/(const T & t, const U & u){
822 return division_result<T, U>::return_value(t, u);
825 template<class T, class U>
826 typename std::enable_if<
827 is_safe<T>::value || is_safe<U>::value,
830 constexpr operator/=(T & t, const U & u){
831 t = static_cast<T>(t / u);
835 /////////////////////////////////////////////////////////////////
838 template<class T, class U>
839 struct modulus_result {
841 using promotion_policy = typename common_promotion_policy<T, U>::type;
842 using result_base_type = typename promotion_policy::template modulus_result<T, U>::type;
844 // if exception not possible
845 constexpr static result_base_type
846 return_value(const T & t, const U & u, std::false_type){
848 static_cast<result_base_type>(base_value(t))
849 % static_cast<result_base_type>(base_value(u));
852 // if exception possible
853 using exception_policy = typename common_exception_policy<T, U>::type;
855 constexpr static int bits = std::min(
856 std::numeric_limits<std::uintmax_t>::digits,
857 std::max(std::initializer_list<int>{
858 std::numeric_limits<result_base_type>::digits,
859 std::numeric_limits<typename base_type<T>::type>::digits,
860 std::numeric_limits<typename base_type<U>::type>::digits
861 }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
864 using r_type = checked_result<result_base_type>;
866 constexpr static result_base_type
867 return_value(const T & t, const U & u, std::true_type){
868 using temp_base = typename std::conditional<
869 std::numeric_limits<result_base_type>::is_signed,
870 typename boost::int_t<bits>::least,
871 typename boost::uint_t<bits>::least
873 using t_type = checked_result<temp_base>;
875 const std::pair<t_type, t_type> r = casting_helper<
880 const t_type rx = checked_operation<
882 dispatch_and_return<exception_policy, temp_base>
883 >::modulus(r.first, r.second);
891 using r_type_interval_t = interval<r_type>;
893 constexpr static const r_type_interval_t t_interval(){
894 return r_type_interval_t{
895 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
896 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
900 constexpr static const r_type_interval_t u_interval(){
901 return r_type_interval_t{
902 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
903 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
907 constexpr static const r_type_interval_t get_r_type_interval(){
908 constexpr const r_type_interval_t t = t_interval();
909 constexpr const r_type_interval_t u = u_interval();
914 return utility::minmax(
915 std::initializer_list<r_type> {
928 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
930 constexpr static const interval<result_base_type> return_interval{
931 r_type_interval.l.exception()
932 ? std::numeric_limits<result_base_type>::min()
933 : static_cast<result_base_type>(r_type_interval.l),
934 r_type_interval.u.exception()
935 ? std::numeric_limits<result_base_type>::max()
936 : static_cast<result_base_type>(r_type_interval.u)
939 constexpr static bool exception_possible(){
940 constexpr const r_type_interval_t ri = get_r_type_interval();
941 constexpr const r_type_interval_t ui = u_interval();
943 static_cast<bool>(ui.includes(r_type(0)))
948 constexpr static auto rl = return_interval.l;
949 constexpr static auto ru = return_interval.u;
961 constexpr static type return_value(const T & t, const U & u){
966 std::integral_constant<bool, exception_possible()>()
968 typename type::skip_validation()
973 template<class T, class U>
974 typename boost::lazy_enable_if_c<
975 is_safe<T>::value || is_safe<U>::value,
978 constexpr operator%(const T & t, const U & u){
979 // see https://en.wikipedia.org/wiki/Modulo_operation
980 return modulus_result<T, U>::return_value(t, u);
983 template<class T, class U>
984 typename std::enable_if<
985 is_safe<T>::value || is_safe<U>::value,
988 constexpr operator%=(T & t, const U & u){
989 t = static_cast<T>(t % u);
993 /////////////////////////////////////////////////////////////////
998 template<class T, class U>
999 struct less_than_result {
1001 using promotion_policy = typename common_promotion_policy<T, U>::type;
1003 using result_base_type =
1004 typename promotion_policy::template comparison_result<T, U>::type;
1006 // if exception not possible
1007 constexpr static bool
1008 return_value(const T & t, const U & u, std::false_type){
1010 static_cast<result_base_type>(base_value(t))
1011 < static_cast<result_base_type>(base_value(u));
1014 using exception_policy = typename common_exception_policy<T, U>::type;
1016 using r_type = checked_result<result_base_type>;
1018 // if exception possible
1019 constexpr static bool
1020 return_value(const T & t, const U & u, std::true_type){
1021 const std::pair<result_base_type, result_base_type> r = casting_helper<
1026 return safe_compare::less_than(r.first, r.second);
1029 using r_type_interval_t = interval<r_type>;
1031 constexpr static bool interval_open(const r_type_interval_t & t){
1032 return t.l.exception() || t.u.exception();
1036 constexpr static bool
1037 return_value(const T & t, const U & u){
1038 constexpr const r_type_interval_t t_interval{
1039 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1040 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1042 constexpr const r_type_interval_t u_interval{
1043 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1044 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1047 if(t_interval < u_interval)
1049 if(t_interval > u_interval)
1052 constexpr bool exception_possible
1053 = interval_open(t_interval) || interval_open(u_interval);
1055 return return_value(
1058 std::integral_constant<bool, exception_possible>()
1063 template<class T, class U>
1064 typename std::enable_if<
1065 is_safe<T>::value || is_safe<U>::value,
1068 constexpr operator<(const T & lhs, const U & rhs) {
1069 return less_than_result<T, U>::return_value(lhs, rhs);
1072 template<class T, class U>
1073 typename std::enable_if<
1074 is_safe<T>::value || is_safe<U>::value,
1077 constexpr operator>(const T & lhs, const U & rhs) {
1081 template<class T, class U>
1082 typename std::enable_if<
1083 is_safe<T>::value || is_safe<U>::value,
1086 constexpr operator>=(const T & lhs, const U & rhs) {
1087 return ! ( lhs < rhs );
1090 template<class T, class U>
1091 typename std::enable_if<
1092 is_safe<T>::value || is_safe<U>::value,
1095 constexpr operator<=(const T & lhs, const U & rhs) {
1096 return ! ( lhs > rhs );
1101 template<class T, class U>
1102 struct equal_result {
1104 using promotion_policy = typename common_promotion_policy<T, U>::type;
1106 using result_base_type =
1107 typename promotion_policy::template comparison_result<T, U>::type;
1109 // if exception not possible
1110 constexpr static bool
1111 return_value(const T & t, const U & u, std::false_type){
1113 static_cast<result_base_type>(base_value(t))
1114 == static_cast<result_base_type>(base_value(u));
1117 using exception_policy = typename common_exception_policy<T, U>::type;
1119 using r_type = checked_result<result_base_type>;
1121 // exception possible
1122 constexpr static bool
1123 return_value(const T & t, const U & u, std::true_type){
1124 const std::pair<result_base_type, result_base_type> r = casting_helper<
1129 return safe_compare::equal(r.first, r.second);
1132 using r_type_interval = interval<r_type>;
1134 constexpr static bool interval_open(const r_type_interval & t){
1135 return t.l.exception() || t.u.exception();
1139 constexpr static bool
1140 return_value(const T & t, const U & u){
1141 constexpr const r_type_interval t_interval{
1142 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1143 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1146 constexpr const r_type_interval u_interval{
1147 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1148 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1151 if(! intersect(t_interval, u_interval))
1154 constexpr bool exception_possible
1155 = interval_open(t_interval) || interval_open(u_interval);
1157 return return_value(
1160 std::integral_constant<bool, exception_possible>()
1165 template<class T, class U>
1166 typename std::enable_if<
1167 is_safe<T>::value || is_safe<U>::value,
1170 constexpr operator==(const T & lhs, const U & rhs) {
1171 return equal_result<T, U>::return_value(lhs, rhs);
1174 template<class T, class U>
1175 typename std::enable_if<
1176 is_safe<T>::value || is_safe<U>::value,
1179 constexpr operator!=(const T & lhs, const U & rhs) {
1180 return ! (lhs == rhs);
1183 /////////////////////////////////////////////////////////////////
1187 template<class T, class U>
1188 struct left_shift_result {
1190 using promotion_policy = typename common_promotion_policy<T, U>::type;
1191 using result_base_type =
1192 typename promotion_policy::template left_shift_result<T, U>::type;
1194 // if exception not possible
1195 constexpr static result_base_type
1196 return_value(const T & t, const U & u, std::false_type){
1198 static_cast<result_base_type>(base_value(t))
1199 << static_cast<result_base_type>(base_value(u));
1202 // exception possible
1203 using exception_policy = typename common_exception_policy<T, U>::type;
1205 using r_type = checked_result<result_base_type>;
1207 constexpr static result_base_type
1208 return_value(const T & t, const U & u, std::true_type){
1209 const std::pair<result_base_type, result_base_type> r = casting_helper<
1214 const r_type rx = checked_operation<
1216 dispatch_and_return<exception_policy, result_base_type>
1217 >::left_shift(r.first, r.second);
1221 ? r.first << r.second
1225 using r_type_interval_t = interval<r_type>;
1227 constexpr static r_type_interval_t get_r_type_interval(){
1228 constexpr const r_type_interval_t t_interval{
1229 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1230 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1233 constexpr const r_type_interval_t u_interval{
1234 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1235 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1237 return (t_interval << u_interval);
1240 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
1242 constexpr static const interval<result_base_type> return_interval{
1243 r_type_interval.l.exception()
1244 ? std::numeric_limits<result_base_type>::min()
1245 : static_cast<result_base_type>(r_type_interval.l),
1246 r_type_interval.u.exception()
1247 ? std::numeric_limits<result_base_type>::max()
1248 : static_cast<result_base_type>(r_type_interval.u)
1251 constexpr static bool exception_possible(){
1252 if(r_type_interval.l.exception())
1254 if(r_type_interval.u.exception())
1256 if(! return_interval.includes(r_type_interval))
1261 constexpr static auto rl = return_interval.l;
1262 constexpr static auto ru = return_interval.u;
1274 constexpr static type return_value(const T & t, const U & u){
1279 std::integral_constant<bool, exception_possible()>()
1281 typename type::skip_validation()
1286 template<class T, class U>
1287 typename boost::lazy_enable_if_c<
1288 // handle safe<T> << int, int << safe<U>, safe<T> << safe<U>
1289 // exclude std::ostream << ...
1290 (! std::is_base_of<std::ios_base, T>::value)
1291 && (is_safe<T>::value || is_safe<U>::value),
1292 left_shift_result<T, U>
1294 constexpr operator<<(const T & t, const U & u){
1296 // C++ standards document N4618 & 5.8.2
1298 std::numeric_limits<T>::is_integer, "shifted value must be an integer"
1301 std::numeric_limits<U>::is_integer, "shift amount must be an integer"
1303 return left_shift_result<T, U>::return_value(t, u);
1306 template<class T, class U>
1307 typename std::enable_if<
1308 is_safe<T>::value || is_safe<U>::value,
1311 constexpr operator<<=(T & t, const U & u){
1312 t = static_cast<T>(t << u);
1317 template<class T, class U>
1318 struct right_shift_result {
1319 using promotion_policy = typename common_promotion_policy<T, U>::type;
1320 using result_base_type =
1321 typename promotion_policy::template right_shift_result<T, U>::type;
1323 // if exception not possible
1324 constexpr static result_base_type
1325 return_value(const T & t, const U & u, std::false_type){
1327 static_cast<result_base_type>(base_value(t))
1328 >> static_cast<result_base_type>(base_value(u));
1331 // exception possible
1332 using exception_policy = typename common_exception_policy<T, U>::type;
1334 using r_type = checked_result<result_base_type>;
1336 constexpr static result_base_type
1337 return_value(const T & t, const U & u, std::true_type){
1338 const std::pair<result_base_type, result_base_type> r = casting_helper<
1343 const r_type rx = checked_operation<
1345 dispatch_and_return<exception_policy, result_base_type>
1346 >::right_shift(r.first, r.second);
1350 ? r.first >> r.second
1354 using r_type_interval_t = interval<r_type>;
1356 constexpr static r_type_interval_t t_interval(){
1357 return r_type_interval_t(
1358 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
1359 checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
1363 constexpr static r_type_interval_t u_interval(){
1364 return r_type_interval_t(
1365 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
1366 checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
1369 constexpr static r_type_interval_t get_r_type_interval(){;
1370 return (t_interval() >> u_interval());
1373 static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
1375 constexpr static const interval<result_base_type> return_interval{
1376 r_type_interval.l.exception()
1377 ? std::numeric_limits<result_base_type>::min()
1378 : static_cast<result_base_type>(r_type_interval.l),
1379 r_type_interval.u.exception()
1380 ? std::numeric_limits<result_base_type>::max()
1381 : static_cast<result_base_type>(r_type_interval.u)
1384 constexpr static bool exception_possible(){
1385 constexpr const r_type_interval_t ri = r_type_interval;
1386 constexpr const r_type_interval_t ti = t_interval();
1387 constexpr const r_type_interval_t ui = u_interval();
1388 return static_cast<bool>(
1389 // note undesirable coupling with checked::shift right here !
1390 ui.u > checked_result<result_base_type>(
1391 std::numeric_limits<result_base_type>::digits
1393 || ti.l < checked_result<result_base_type>(0)
1394 || ui.l < checked_result<result_base_type>(0)
1400 constexpr static auto rl = return_interval.l;
1401 constexpr static auto ru = return_interval.u;
1413 constexpr static type return_value(const T & t, const U & u){
1418 std::integral_constant<bool, exception_possible()>()
1420 typename type::skip_validation()
1425 template<class T, class U>
1426 typename boost::lazy_enable_if_c<
1427 (! std::is_base_of<std::ios_base, T>::value)
1428 && (is_safe<T>::value || is_safe<U>::value),
1429 right_shift_result<T, U>
1431 constexpr operator>>(const T & t, const U & u){
1434 std::numeric_limits<T>::is_integer, "shifted value must be an integer"
1437 std::numeric_limits<U>::is_integer, "shift amount must be an integer"
1439 return right_shift_result<T, U>::return_value(t, u);
1442 template<class T, class U>
1443 typename std::enable_if<
1444 is_safe<T>::value || is_safe<U>::value,
1447 constexpr operator>>=(T & t, const U & u){
1448 t = static_cast<T>(t >> u);
1452 /////////////////////////////////////////////////////////////////
1453 // bitwise operators
1456 template<class T, class U>
1457 struct bitwise_or_result {
1459 using promotion_policy = typename common_promotion_policy<T, U>::type;
1460 using result_base_type =
1461 typename promotion_policy::template bitwise_or_result<T, U>::type;
1463 // according to the C++ standard, the bitwise operators are executed as if
1464 // the operands are consider a logical array of bits. That is, there is no
1465 // sense that these are signed numbers.
1467 using r_type = typename std::make_unsigned<result_base_type>::type;
1468 using r_type_interval_t = interval<r_type>;
1471 // breaks compilation for earlier versions of clant
1472 constexpr static const r_type_interval_t r_interval{
1476 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1477 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1483 using exception_policy = typename common_exception_policy<T, U>::type;
1486 // lazy_enable_if_c depends on this
1487 using type = safe_base<
1494 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1495 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1502 constexpr static type return_value(const T & t, const U & u){
1504 static_cast<result_base_type>(base_value(t))
1505 | static_cast<result_base_type>(base_value(u)),
1506 typename type::skip_validation()
1511 template<class T, class U>
1512 typename boost::lazy_enable_if_c<
1513 is_safe<T>::value || is_safe<U>::value,
1514 bitwise_or_result<T, U>
1516 constexpr operator|(const T & t, const U & u){
1517 return bitwise_or_result<T, U>::return_value(t, u);
1520 template<class T, class U>
1521 typename std::enable_if<
1522 is_safe<T>::value || is_safe<U>::value,
1525 constexpr operator|=(T & t, const U & u){
1526 t = static_cast<T>(t | u);
1531 template<class T, class U>
1532 struct bitwise_and_result {
1534 using promotion_policy = typename common_promotion_policy<T, U>::type;
1535 using result_base_type =
1536 typename promotion_policy::template bitwise_and_result<T, U>::type;
1538 // according to the C++ standard, the bitwise operators are executed as if
1539 // the operands are consider a logical array of bits. That is, there is no
1540 // sense that these are signed numbers.
1542 using r_type = typename std::make_unsigned<result_base_type>::type;
1543 using r_type_interval_t = interval<r_type>;
1546 // breaks compilation for earlier versions of clant
1547 constexpr static const r_type_interval_t r_interval{
1551 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1552 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1557 using exception_policy = typename common_exception_policy<T, U>::type;
1560 // lazy_enable_if_c depends on this
1561 using type = safe_base<
1568 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1569 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1576 constexpr static type return_value(const T & t, const U & u){
1578 static_cast<result_base_type>(base_value(t))
1579 & static_cast<result_base_type>(base_value(u)),
1580 typename type::skip_validation()
1585 template<class T, class U>
1586 typename boost::lazy_enable_if_c<
1587 is_safe<T>::value || is_safe<U>::value,
1588 bitwise_and_result<T, U>
1590 constexpr operator&(const T & t, const U & u){
1591 return bitwise_and_result<T, U>::return_value(t, u);
1594 template<class T, class U>
1595 typename std::enable_if<
1596 is_safe<T>::value || is_safe<U>::value,
1599 constexpr operator&=(T & t, const U & u){
1600 t = static_cast<T>(t & u);
1605 template<class T, class U>
1606 struct bitwise_xor_result {
1607 using promotion_policy = typename common_promotion_policy<T, U>::type;
1608 using result_base_type =
1609 typename promotion_policy::template bitwise_xor_result<T, U>::type;
1611 // according to the C++ standard, the bitwise operators are executed as if
1612 // the operands are consider a logical array of bits. That is, there is no
1613 // sense that these are signed numbers.
1615 using r_type = typename std::make_unsigned<result_base_type>::type;
1616 using r_type_interval_t = interval<r_type>;
1619 // breaks compilation for earlier versions of clant
1620 constexpr static const r_type_interval_t r_interval{
1624 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1625 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1631 using exception_policy = typename common_exception_policy<T, U>::type;
1634 // lazy_enable_if_c depends on this
1635 using type = safe_base<
1642 static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
1643 static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
1650 constexpr static type return_value(const T & t, const U & u){
1652 static_cast<result_base_type>(base_value(t))
1653 ^ static_cast<result_base_type>(base_value(u)),
1654 typename type::skip_validation()
1659 template<class T, class U>
1660 typename boost::lazy_enable_if_c<
1661 is_safe<T>::value || is_safe<U>::value,
1662 bitwise_xor_result<T, U>
1664 constexpr operator^(const T & t, const U & u){
1665 return bitwise_xor_result<T, U>::return_value(t, u);
1668 template<class T, class U>
1669 typename std::enable_if<
1670 is_safe<T>::value || is_safe<U>::value,
1673 constexpr operator^=(T & t, const U & u){
1674 t = static_cast<T>(t ^ u);
1678 /////////////////////////////////////////////////////////////////
1685 class P, // promotion polic
1686 class E // exception policy
1692 void safe_base<T, Min, Max, P, E>::output(
1693 std::basic_ostream<CharT, Traits> & os
1696 (std::is_same<T, signed char>::value
1697 || std::is_same<T, unsigned char>::value
1698 || std::is_same<T, wchar_t>::value
1700 static_cast<int>(m_t)
1710 class P, // promotion polic
1711 class E // exception policy
1717 void safe_base<T, Min, Max, P, E>::input(
1718 std::basic_istream<CharT, Traits> & is
1720 if(std::is_same<T, signed char>::value
1721 || std::is_same<T, unsigned char>::value
1722 || std::is_same<T, wchar_t>::value
1726 m_t = validated_cast(x);
1730 validated_cast(m_t);
1733 boost::safe_numerics::dispatch<
1735 boost::safe_numerics::safe_numerics_error::domain_error
1737 "error in file input"
1745 #endif // BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP