diff options
Diffstat (limited to 'boost/safe_numerics')
25 files changed, 751 insertions, 641 deletions
diff --git a/boost/safe_numerics/automatic.hpp b/boost/safe_numerics/automatic.hpp index ee19c97e0a..df63bf8d90 100644 --- a/boost/safe_numerics/automatic.hpp +++ b/boost/safe_numerics/automatic.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_AUTOMATIC_HPP #define BOOST_NUMERIC_AUTOMATIC_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -83,14 +78,17 @@ public: constexpr static const r_interval_type r_interval = t_interval + u_interval; + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -115,14 +113,17 @@ public: constexpr static const r_interval_type r_interval = t_interval - u_interval; + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -154,14 +155,17 @@ public: constexpr static const r_interval_type r_interval = t_interval * u_interval; + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -192,33 +196,36 @@ public: }; constexpr static const r_interval_type rx(){ - if(u_interval.u < r_type(0) - || u_interval.l > r_type(0)) - return t_interval / u_interval; - return utility::minmax( - std::initializer_list<r_type> { - t_interval.l / u_interval.l, - t_interval.l / r_type(-1), - t_interval.l / r_type(1), - t_interval.l / u_interval.u, - t_interval.u / u_interval.l, - t_interval.u / r_type(-1), - t_interval.u / r_type(1), - t_interval.u / u_interval.u, - } - ); + if(u_interval.u < r_type(0) + || u_interval.l > r_type(0)) + return t_interval / u_interval; + return utility::minmax( + std::initializer_list<r_type> { + t_interval.l / u_interval.l, + t_interval.l / r_type(-1), + t_interval.l / r_type(1), + t_interval.l / u_interval.u, + t_interval.u / u_interval.l, + t_interval.u / r_type(-1), + t_interval.u / r_type(1), + t_interval.u / u_interval.u, + } + ); } constexpr static const r_interval_type r_interval = rx(); + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -268,14 +275,17 @@ public: constexpr static const r_interval_type r_interval = rx(); + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -308,6 +318,8 @@ public: checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max())) }; + // workaround some microsoft problem + #if 0 constexpr static r_type min(const r_type & t, const r_type & u){ // assert(! u.exception()); // assert(! t.exception()); @@ -319,6 +331,7 @@ public: // assert(! t.exception()); return static_cast<bool>(t < u) ? u : t; } + #endif // union of two intervals // note: we can't use t_interval | u_interval because it @@ -328,22 +341,27 @@ public: const r_interval_type & t, const r_interval_type & u ){ - const r_type & rl = min(t.l, u.l); - const r_type & ru = max(t.u, u.u); - return r_interval_type(rl, ru); + //const r_type & rl = min(t.l, u.l); + const r_type & rmin = static_cast<bool>(t.l < u.l) ? t.l : u.l; + //const r_type & ru = max(t.u, u.u); + const r_type & rmax = static_cast<bool>(t.u < u.u) ? u.u : t.u; + return r_interval_type(rmin, rmax); } constexpr static const r_interval_type r_interval = union_interval(t_interval, u_interval); + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -373,14 +391,17 @@ public: constexpr static const r_interval_type r_interval = t_interval << u_interval; + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; @@ -413,14 +434,17 @@ public: constexpr static const r_interval_type r_interval = t_interval >> u_interval; + constexpr static auto rl = r_interval.l; + constexpr static auto ru = r_interval.u; + using type = typename result_type< temp_base_type, - r_interval.l.exception() + rl.exception() ? std::numeric_limits<temp_base_type>::min() - : static_cast<temp_base_type>(r_interval.l), - r_interval.u.exception() + : static_cast<temp_base_type>(rl), + ru.exception() ? std::numeric_limits<temp_base_type>::max() - : static_cast<temp_base_type>(r_interval.u) + : static_cast<temp_base_type>(ru) >::type; }; diff --git a/boost/safe_numerics/checked_default.hpp b/boost/safe_numerics/checked_default.hpp index 5a5bb44d24..07699c4fca 100644 --- a/boost/safe_numerics/checked_default.hpp +++ b/boost/safe_numerics/checked_default.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CHECKED_DEFAULT_HPP #define BOOST_NUMERIC_CHECKED_DEFAULT_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2017 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -49,14 +44,27 @@ namespace safe_numerics { // it should trap with a static_assert. This occurs at compile time while // calculating result interval. This needs more investigation. -template<typename R, typename T = void, class Default = void> -struct checked_operation{ +template< + typename R, + typename T, + class F = make_checked_result<R>, + class Default = void +> +struct heterogeneous_checked_operation { constexpr static checked_result<R> cast(const T & t) /* noexcept */ { return static_cast<R>(t); } - constexpr static checked_result<T> - minus(const T & t) noexcept { +}; + +template< + typename R, + class F = make_checked_result<R>, + class Default = void +> +struct checked_operation{ + constexpr static checked_result<R> + minus(const R & t) noexcept { return - t; } constexpr static checked_result<R> @@ -124,7 +132,7 @@ namespace checked { template<typename R, typename T> constexpr checked_result<R> cast(const T & t) /* noexcept */ { - return checked_operation<R, T>::cast(t); + return heterogeneous_checked_operation<R, T>::cast(t); } template<typename R> constexpr checked_result<R> minus(const R & t) noexcept { @@ -184,7 +192,7 @@ constexpr checked_result<R> bitwise_or(const R & t, const R & u) noexcept { } template<typename R> constexpr checked_result<R> bitwise_xor(const R & t, const R & u) noexcept { - return checked_operation<R>::bitwise_or(t, u); + return checked_operation<R>::bitwise_xor(t, u); } template<typename R> constexpr checked_result<R> bitwise_and(const R & t, const R & u) noexcept { @@ -200,4 +208,3 @@ constexpr checked_result<R> bitwise_not(const R & t) noexcept { } // boost #endif // BOOST_NUMERIC_CHECKED_DEFAULT_HPP - diff --git a/boost/safe_numerics/checked_float.hpp b/boost/safe_numerics/checked_float.hpp index a382e9889e..696c14c52b 100644 --- a/boost/safe_numerics/checked_float.hpp +++ b/boost/safe_numerics/checked_float.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CHECKED_FLOAT_HPP #define BOOST_NUMERIC_CHECKED_FLOAT_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2017 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -27,7 +22,7 @@ namespace checked { // layer 0 - implement safe operations for floating template<typename R, typename T> -struct checked_unary_operation<R, T, +struct heterogeneous_checked_operation<R, T, F, typename std::enable_if< std::is_floating_point<R>::value && std::is_floating_point<T>::value @@ -40,7 +35,7 @@ struct checked_unary_operation<R, T, }; // checked_unary_operation template<typename R, typename T, typename U> -struct checked_binary_operation<R, T, U, +struct checked_operation<R, T, U, F, typename std::enable_if< std::is_floating_point<R>::value >::type diff --git a/boost/safe_numerics/checked_integer.hpp b/boost/safe_numerics/checked_integer.hpp index e86b3994dd..7e7bef357a 100644 --- a/boost/safe_numerics/checked_integer.hpp +++ b/boost/safe_numerics/checked_integer.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP #define BOOST_NUMERIC_CHECKED_INTEGER_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -38,8 +33,12 @@ using bool_type = typename std::conditional<tf, std::true_type, std::false_type> // Note presumption of twos complement integer arithmetic // convert an integral value to some other integral type -template<typename R, typename T> -struct checked_operation<R, T, +template< + typename R, + typename T, + class F +> +struct heterogeneous_checked_operation<R, T, F, typename std::enable_if< std::is_integral<R>::value && std::is_integral<T>::value @@ -54,7 +53,7 @@ struct checked_operation<R, T, const T & t, std::true_type, // R is signed std::true_type // T is signed - ) noexcept { + ){ // INT32-C Ensure that operations on signed // integers do not overflow return @@ -62,8 +61,7 @@ struct checked_operation<R, T, t, std::numeric_limits<R>::max() ) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "converted signed value too large" ) : @@ -71,8 +69,7 @@ struct checked_operation<R, T, t, std::numeric_limits<R>::min() ) ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "converted signed value too small" ) : @@ -84,7 +81,7 @@ struct checked_operation<R, T, const T & t, std::true_type, // R is signed std::false_type // T is unsigned - ) noexcept { + ){ // INT30-C Ensure that unsigned integer operations // do not wrap return @@ -92,8 +89,7 @@ struct checked_operation<R, T, t, std::numeric_limits<R>::max() ) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "converted unsigned value too large" ) : @@ -105,7 +101,7 @@ struct checked_operation<R, T, const T & t, std::false_type, // R is unsigned std::false_type // T is unsigned - ) noexcept { + ){ // INT32-C Ensure that operations on unsigned // integers do not overflow return @@ -113,8 +109,7 @@ struct checked_operation<R, T, t, std::numeric_limits<R>::max() ) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "converted unsigned value too large" ) : @@ -126,11 +121,10 @@ struct checked_operation<R, T, const T & t, std::false_type, // R is unsigned std::true_type // T is signed - ) noexcept { + ){ return boost::safe_numerics::safe_compare::less_than(t, 0) ? - checked_result<R>( - safe_numerics_error::domain_error, + F::template invoke<safe_numerics_error::domain_error>( "converted negative value to unsigned" ) : @@ -138,8 +132,7 @@ struct checked_operation<R, T, t, std::numeric_limits<R>::max() ) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "converted signed value too large" ) : @@ -149,7 +142,7 @@ struct checked_operation<R, T, }; // cast_impl_detail constexpr static checked_result<R> - cast(const T & t) noexcept { + cast(const T & t){ return cast_impl_detail::cast_impl( t, @@ -160,15 +153,19 @@ struct checked_operation<R, T, }; // converting floating point value to integral type -template<typename R, typename T> -struct checked_operation<R, T, +template< + typename R, + typename T, + class F +> +struct heterogeneous_checked_operation<R, T, F, typename std::enable_if< std::is_integral<R>::value && std::is_floating_point<T>::value >::type >{ constexpr static checked_result<R> - cast(const T & t) noexcept { + cast(const T & t){ return static_cast<R>(t); } }; @@ -176,29 +173,38 @@ struct checked_operation<R, T, // converting integral value to floating point type // INT35-C. Use correct integer precisions -template<typename R, typename T> -struct checked_operation<R, T, +template< + typename R, + typename T, + class F +> +struct heterogeneous_checked_operation<R, T, F, typename std::enable_if< std::is_floating_point<R>::value && std::is_integral<T>::value >::type >{ constexpr static checked_result<R> - cast(const T & t) noexcept { + cast(const T & t){ if(std::numeric_limits<R>::digits < std::numeric_limits<T>::digits){ if(utility::significant_bits(t) > std::numeric_limits<R>::digits){ - return { + return F::invoke( safe_numerics_error::precision_overflow_error, "keep precision" - }; + ); } } return t; } }; -template<typename R> -struct checked_operation<R, +// binary operations on primitive integer types + +template< + typename R, + class F +> +struct checked_operation<R, F, typename std::enable_if< std::is_integral<R>::value >::type @@ -212,12 +218,11 @@ struct checked_operation<R, const R t, const R u, std::false_type // R unsigned - ) noexcept { + ){ return // INT30-C. Ensure that unsigned integer operations do not wrap std::numeric_limits<R>::max() - u < t ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "addition result too large" ) : @@ -230,18 +235,17 @@ struct checked_operation<R, const R t, const R u, std::true_type // R signed - ) noexcept { + ){ + // INT32-C. Ensure that operations on signed integers do not result in overflow return // INT32-C. Ensure that operations on signed integers do not result in overflow ((u > 0) && (t > (std::numeric_limits<R>::max() - u))) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "addition result too large" ) : ((u < 0) && (t < (std::numeric_limits<R>::min() - u))) ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "addition result too low" ) : @@ -251,7 +255,7 @@ struct checked_operation<R, }; // add_impl_detail constexpr static checked_result<R> - add(const R & t, const R & u) noexcept { + add(const R & t, const R & u){ return add_impl_detail::add(t, u, std::is_signed<R>()); } @@ -264,12 +268,11 @@ struct checked_operation<R, const R t, const R u, std::false_type // R is unsigned - ) noexcept { + ){ // INT30-C. Ensure that unsigned integer operations do not wrap return t < u ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "subtraction result cannot be negative" ) : @@ -282,18 +285,16 @@ struct checked_operation<R, const R t, const R u, std::true_type // R is signed - ) noexcept { // INT32-C + ){ // INT32-C return // INT32-C. Ensure that operations on signed integers do not result in overflow ((u > 0) && (t < (std::numeric_limits<R>::min() + u))) ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "subtraction result overflows result type" ) : ((u < 0) && (t > (std::numeric_limits<R>::max() + u))) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "subtraction result overflows result type" ) : @@ -303,7 +304,7 @@ struct checked_operation<R, }; // subtract_impl_detail - constexpr static checked_result<R> subtract(const R & t, const R & u) noexcept { + constexpr static checked_result<R> subtract(const R & t, const R & u){ return subtract_impl_detail::subtract(t, u, std::is_signed<R>()); } @@ -315,10 +316,9 @@ struct checked_operation<R, constexpr static checked_result<R> minus( const R t, std::false_type // R is unsigned - ) noexcept { + ){ return t > 0 ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "minus unsigned would be negative" ) : @@ -331,10 +331,9 @@ struct checked_operation<R, constexpr static checked_result<R> minus( const R t, std::true_type // R is signed - ) noexcept { // INT32-C + ){ // INT32-C return t == std::numeric_limits<R>::min() ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "subtraction result overflows result type" ) : @@ -344,7 +343,7 @@ struct checked_operation<R, }; // minus_impl_detail - constexpr static checked_result<R> minus(const R & t) noexcept { + constexpr static checked_result<R> minus(const R & t){ return minus_impl_detail::minus(t, std::is_signed<R>()); } @@ -358,9 +357,9 @@ struct checked_operation<R, const R t, const R u, std::false_type, // R is unsigned - std::false_type // !(sizeof(R) > sizeof(std::uintmax_t) / 2) + std::false_type // !(sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2) - ) noexcept { + ){ // INT30-C // fast method using intermediate result guaranteed not to overflow // todo - replace std::uintmax_t with a size double the size of R @@ -368,8 +367,7 @@ struct checked_operation<R, return static_cast<i_type>(t) * static_cast<i_type>(u) > std::numeric_limits<R>::max() ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "multiplication overflow" ) : @@ -380,14 +378,13 @@ struct checked_operation<R, const R t, const R u, std::false_type, // R is unsigned - std::true_type // (sizeof(R) > sizeof(std::uintmax_t) / 2) + std::true_type // (sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2) - ) noexcept { + ){ // INT30-C return u > 0 && t > std::numeric_limits<R>::max() / u ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "multiplication overflow" ) : @@ -400,9 +397,9 @@ struct checked_operation<R, const R t, const R u, std::true_type, // R is signed - std::false_type // ! (sizeof(R) > (sizeof(std::intmax_t) / 2)) + std::false_type // ! (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2)) - ) noexcept { + ){ // INT30-C // fast method using intermediate result guaranteed not to overflow // todo - replace std::intmax_t with a size double the size of R @@ -412,8 +409,7 @@ struct checked_operation<R, static_cast<i_type>(t) * static_cast<i_type>(u) > static_cast<i_type>(std::numeric_limits<R>::max()) ) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "multiplication overflow" ) : @@ -421,8 +417,7 @@ struct checked_operation<R, static_cast<i_type>(t) * static_cast<i_type>(u) < static_cast<i_type>(std::numeric_limits<R>::min()) ) ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "multiplication overflow" ) : @@ -433,21 +428,19 @@ struct checked_operation<R, const R t, const R u, std::true_type, // R is signed - std::true_type // (sizeof(R) > (sizeof(std::intmax_t) / 2)) - ) noexcept { // INT32-C + std::true_type // (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2)) + ){ // INT32-C return t > 0 ? u > 0 ? t > std::numeric_limits<R>::max() / u ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "multiplication overflow" ) : checked_result<R>(t * u) : // u <= 0 u < std::numeric_limits<R>::min() / t ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "multiplication overflow" ) : @@ -455,16 +448,14 @@ struct checked_operation<R, : // t <= 0 u > 0 ? t < std::numeric_limits<R>::min() / u ? - checked_result<R>( - safe_numerics_error::negative_overflow_error, + F::template invoke<safe_numerics_error::negative_overflow_error>( "multiplication overflow" ) : checked_result<R>(t * u) : // u <= 0 t != 0 && u < std::numeric_limits<R>::max() / t ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "multiplication overflow" ) : @@ -473,7 +464,7 @@ struct checked_operation<R, } }; // multiply_impl_detail - constexpr static checked_result<R> multiply(const R & t, const R & u) noexcept { + constexpr static checked_result<R> multiply(const R & t, const R & u){ return multiply_impl_detail::multiply( t, u, @@ -493,7 +484,7 @@ struct checked_operation<R, const R & t, const R & u, std::false_type // R is unsigned - ) noexcept { + ){ return t / u; } @@ -501,11 +492,10 @@ struct checked_operation<R, const R & t, const R & u, std::true_type // R is signed - ) noexcept { + ){ return (u == -1 && t == std::numeric_limits<R>::min()) ? - checked_result<R>( - safe_numerics_error::positive_overflow_error, + F::template invoke<safe_numerics_error::positive_overflow_error>( "result cannot be represented" ) : @@ -515,10 +505,9 @@ struct checked_operation<R, }; // divide_impl_detail // note that we presume that the size of R >= size of T - constexpr static checked_result<R> divide(const R & t, const R & u) noexcept { + constexpr static checked_result<R> divide(const R & t, const R & u){ if(u == 0){ - return checked_result<R>( - safe_numerics_error::domain_error, + return F::template invoke<safe_numerics_error::domain_error>( "divide by zero" ); } @@ -533,7 +522,7 @@ struct checked_operation<R, const R & t, const R & u, std::false_type // R is unsigned - ) noexcept { + ){ return t % u; } @@ -541,7 +530,7 @@ struct checked_operation<R, const R & t, const R & u, std::true_type // R is signed - ) noexcept { + ){ if(u >= 0) return t % u; checked_result<R> ux = checked::minus(u); @@ -551,10 +540,9 @@ struct checked_operation<R, } }; // modulus_impl_detail - constexpr static checked_result<R> modulus(const R & t, const R & u) noexcept { + constexpr static checked_result<R> modulus(const R & t, const R & u){ if(0 == u) - return checked_result<R>( - safe_numerics_error::domain_error, + return F::template invoke<safe_numerics_error::domain_error>( "denominator is zero" ); @@ -605,7 +593,7 @@ struct checked_operation<R, const R & t, const R & u, std::false_type // R is unsigned - ) noexcept { + ){ // the value of the result is E1 x 2^E2, reduced modulo one more than // the maximum value representable in the result type. @@ -619,8 +607,7 @@ struct checked_operation<R, ) ){ // behavior is undefined - return checked_result<R>( - safe_numerics_error::shift_too_large, + return F::template invoke<safe_numerics_error::shift_too_large>( "shifting left more bits than available is undefined behavior" ); } @@ -631,7 +618,7 @@ struct checked_operation<R, const R & t, const R & u, std::true_type // R is signed - ) noexcept { + ){ // and [E1] has a non-negative value if(t >= 0){ // and E1 x 2^E2 is representable in the corresponding @@ -647,8 +634,7 @@ struct checked_operation<R, ) ){ // behavior is undefined - return checked_result<R>( - safe_numerics_error::shift_too_large, + return F::template invoke<safe_numerics_error::shift_too_large>( "shifting left more bits than available" ); } @@ -657,8 +643,7 @@ struct checked_operation<R, } } // otherwise, the behavior is undefined. - return checked_result<R>( - safe_numerics_error::negative_shift, + return F::template invoke<safe_numerics_error::negative_shift>( "shifting a negative value" ); } @@ -668,7 +653,7 @@ struct checked_operation<R, constexpr static checked_result<R> left_shift( const R & t, const R & u - ) noexcept { + ){ // INT34-C - Do not shift an expression by a negative number of bits // standard paragraph 5.8 & 1 @@ -677,15 +662,13 @@ struct checked_operation<R, return t; } if(u < 0){ - return checked_result<R>( - safe_numerics_error::negative_shift, + return F::template invoke<safe_numerics_error::negative_shift>( "shifting negative amount" ); } if(u > std::numeric_limits<R>::digits){ // behavior is undefined - return checked_result<R>( - safe_numerics_error::shift_too_large, + return F::template invoke<safe_numerics_error::shift_too_large>( "shifting more bits than available" ); } @@ -705,7 +688,7 @@ struct checked_operation<R, const R & t, const R & u, std::false_type // T is unsigned - ) noexcept { + ){ // the value of the result is the integral part of the // quotient of E1/2E2 return t >> u; @@ -715,12 +698,11 @@ struct checked_operation<R, const R & t, const R & u, std::true_type // T is signed; - ) noexcept { + ){ if(t < 0){ // note that the C++ standard considers this case is "implemenation // defined" rather than "undefined". - return checked_result<R>( - safe_numerics_error::negative_value_shift, + return F::template invoke<safe_numerics_error::negative_value_shift>( "shifting a negative value" ); } @@ -733,21 +715,19 @@ struct checked_operation<R, constexpr static checked_result<R> right_shift( const R & t, const R & u -) noexcept { +){ // INT34-C - Do not shift an expression by a negative number of bits // standard paragraph 5.8 & 1 // if the right operand is negative if(u < 0){ - return checked_result<R>( - safe_numerics_error::negative_shift, + return F::template invoke<safe_numerics_error::negative_shift>( "shifting negative amount" ); } if(u > std::numeric_limits<R>::digits){ // behavior is undefined - return checked_result<R>( - safe_numerics_error::shift_too_large, + return F::template invoke<safe_numerics_error::shift_too_large>( "shifting more bits than available" ); } @@ -761,56 +741,52 @@ constexpr static checked_result<R> right_shift( // as it would break too many programs. Specifically, we permit signed // integer operands. -constexpr static checked_result<R> bitwise_or(const R & t, const R & u) noexcept { +constexpr static checked_result<R> bitwise_or(const R & t, const R & u){ using namespace boost::safe_numerics::utility; const unsigned int result_size = std::max(significant_bits(t), significant_bits(u)); if(result_size > bits_type<R>::value){ - return checked_result<R>{ - safe_numerics_error::positive_overflow_error, + return F::template invoke<safe_numerics_error::positive_overflow_error>( "result type too small to hold bitwise or" - }; + ); } return t | u; } -constexpr static checked_result<R> bitwise_xor(const R & t, const R & u) noexcept { +constexpr static checked_result<R> bitwise_xor(const R & t, const R & u){ using namespace boost::safe_numerics::utility; const unsigned int result_size = std::max(significant_bits(t), significant_bits(u)); if(result_size > bits_type<R>::value){ - return checked_result<R>{ - safe_numerics_error::positive_overflow_error, + return F::template invoke<safe_numerics_error::positive_overflow_error>( "result type too small to hold bitwise or" - }; + ); } return t ^ u; } -constexpr static checked_result<R> bitwise_and(const R & t, const R & u) noexcept { +constexpr static checked_result<R> bitwise_and(const R & t, const R & u){ using namespace boost::safe_numerics::utility; const unsigned int result_size = std::min(significant_bits(t), significant_bits(u)); if(result_size > bits_type<R>::value){ - return checked_result<R>{ - safe_numerics_error::positive_overflow_error, + return F::template invoke<safe_numerics_error::positive_overflow_error>( "result type too small to hold bitwise and" - }; + ); } return t & u; } -constexpr static checked_result<R> bitwise_not(const R & t) noexcept { +constexpr static checked_result<R> bitwise_not(const R & t){ using namespace boost::safe_numerics::utility; if(significant_bits(t) > bits_type<R>::value){ - return checked_result<R>{ - safe_numerics_error::positive_overflow_error, + return F::template invoke<safe_numerics_error::positive_overflow_error>( "result type too small to hold bitwise inverse" - }; + ); } return ~t; } diff --git a/boost/safe_numerics/checked_result.hpp b/boost/safe_numerics/checked_result.hpp index 55efca082a..10bd7a65c8 100644 --- a/boost/safe_numerics/checked_result.hpp +++ b/boost/safe_numerics/checked_result.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CHECKED_RESULT #define BOOST_NUMERIC_CHECKED_RESULT -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -32,21 +27,54 @@ struct checked_result { // don't permit construction without initial value; checked_result() = delete; + // note: I implemented the following non-default copy and move + // constructors because I thought I needed to do this in order + // to make them constexpr. Turns out though that doing this creates + // a syntax error because the assignment results in error due + // to assignment "outside of object lifetime". I think this could + // be addressed by replacing the anonymous union above with a + // named union. This would create some syntax changes which would + // ripple through some parts of th program. So for now, we'll just + // rely on the default copy and move constructors. + #if 0 + // copy constructor + constexpr /*explicit*/ checked_result(const checked_result & r) noexpect : + m_e(r.m_e) + { + if(safe_numerics_error::success == r.m_e) + m_r = r.m_r; + else + m_msg = r.m_msg; + } + + // move constructor + constexpr /*explicit*/ checked_result(checked_result && r) noexcept : + m_e(r.m_e) + { + if(safe_numerics_error::success == r.m_e) + m_r = r.m_r; + else + m_msg = r.m_msg; + } + #endif + checked_result(const checked_result & r) = default; + checked_result(checked_result && r) = default; + constexpr /*explicit*/ checked_result(const R & r) : m_e(safe_numerics_error::success), m_r(r) {} #if 0 template<typename T> - constexpr /*explicit*/ checked_result(const T & t) : + constexpr /*explicit*/ checked_result(const T & t) noexcept : m_e(safe_numerics_error::success), m_r(t) {} #endif constexpr /*explicit*/ checked_result( - safe_numerics_error e, + const safe_numerics_error & e, const char * msg = "" - ) : + ) noexcept : m_e(e), m_msg(msg) { @@ -54,7 +82,7 @@ struct checked_result { } // permit construct from another checked result type template<typename T> - constexpr /*explicit*/ checked_result(const checked_result<T> & t) : + constexpr /*explicit*/ checked_result(const checked_result<T> & t) noexcept : m_e(t.m_e) { static_assert( @@ -71,18 +99,18 @@ struct checked_result { } // accesors - constexpr operator R() const { + constexpr operator R() const noexcept{ // don't assert here. Let the library catch these errors assert(! exception()); return m_r; } - constexpr operator safe_numerics_error () const { + constexpr operator safe_numerics_error () const noexcept{ // note that this is a legitimate operation even when // the operation was successful - it will return success return m_e; } - constexpr operator const char *() const { + constexpr operator const char *() const noexcept{ assert(exception()); return m_msg; } @@ -91,6 +119,27 @@ struct checked_result { checked_result & operator=(const checked_result &) = delete; }; +#if 0 +template<typename R> +constexpr checked_result<R> make_checked_result( + const safe_numerics_error & e, + char const * const & m +) noexcept { + return checked_result<R>(e, m); +} +#endif + +template <class R> +class make_checked_result { +public: + template<safe_numerics_error E> + constexpr static checked_result<R> invoke( + char const * const & m + ) noexcept { + return checked_result<R>(E, m); + } +}; + } // safe_numerics } // boost diff --git a/boost/safe_numerics/checked_result_operations.hpp b/boost/safe_numerics/checked_result_operations.hpp index c1af3167e5..0492cab432 100644 --- a/boost/safe_numerics/checked_result_operations.hpp +++ b/boost/safe_numerics/checked_result_operations.hpp @@ -1,11 +1,6 @@ - #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS +#ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -13,12 +8,12 @@ // http://www.boost.org/LICENSE_1_0.txt) // Implemenation of arithmetic on "extended" integers. -// extended integers are +// Extended integers are defined in terms of C++ primitive integers as // a) an interger range // b) extra elements +inf, -inf, indeterminate // -// arithmetic operations are closed on the set of extended integers -// but operations are not associative when they result in the +// Integer operations are closed on the set of extended integers +// but operations are not necessarily associative when they result in the // extensions +inf, -inf, and indeterminate // // in this code, the type "checked_result<T>" where T is some @@ -38,6 +33,34 @@ namespace boost { namespace safe_numerics { +template<typename T> +constexpr void display(const boost::safe_numerics::checked_result<T> & c){ + switch(c.m_e){ + case safe_numerics_error::success: + std::terminate(); + case safe_numerics_error::positive_overflow_error: // result is above representational maximum + std::terminate(); + case safe_numerics_error::negative_overflow_error: // result is below representational minimum + std::terminate(); + case safe_numerics_error::domain_error: // one operand is out of valid range + std::terminate(); + case safe_numerics_error::range_error: // result cannot be produced for this operation + std::terminate(); + case safe_numerics_error::precision_overflow_error: // result lost precision + std::terminate(); + case safe_numerics_error::underflow_error: // result is too small to be represented + std::terminate(); + case safe_numerics_error::negative_value_shift: // negative value in shift operator + std::terminate(); + case safe_numerics_error::negative_shift: // shift a negative value + std::terminate(); + case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size + std::terminate(); + case safe_numerics_error::uninitialized_value: // creating of uninitialized value + std::terminate(); + } +} + ////////////////////////////////////////////////////////////////////////// // implement C++ operators for check_result<T> @@ -85,13 +108,13 @@ constexpr inline operator+( const checked_result<T> & u ){ using value_type = sum_value_type; - constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count); + const std::uint8_t order = static_cast<std::uint8_t>(value_type::count); // note major pain. Clang constexpr multi-dimensional array is fine. // but gcc doesn't permit a multi-dimensional array to be be constexpr. // so we need to some ugly gymnastics to make our system work for all // all systems. - constexpr const enum safe_numerics_error result[order * order] = { + const enum safe_numerics_error result[order * order] = { // t == known_value //{ // u == ... @@ -135,6 +158,18 @@ constexpr inline operator+( return checked_result<T>(e, "addition result"); } +// unary + +template<class T> +typename std::enable_if< + std::is_integral<T>::value, + checked_result<T> +>::type +constexpr inline operator+( + const checked_result<T> & t +){ + return t; +} + // integers subtraction template<class T> typename std::enable_if< @@ -192,6 +227,19 @@ constexpr inline operator-( return checked_result<T>(e, "subtraction result"); } +// unary - +template<class T> +typename std::enable_if< + std::is_integral<T>::value, + checked_result<T> +>::type +constexpr inline operator-( + const checked_result<T> & t +){ +// assert(false); + return checked_result<T>(0) - t; +} + struct product_value_type { // characterization of various values const enum flag { @@ -201,8 +249,12 @@ struct product_value_type { greater_than_zero, greater_than_max, indeterminate, + // count of number of cases for values count, - t_value + // temporary values for special cases + t_value, + u_value, + z_value } m_flag; template<class T> constexpr flag to_flag(const checked_result<T> & t) const { @@ -440,20 +492,20 @@ constexpr inline operator%( //{ // u == ... value_type::indeterminate, // less_than_min, - value_type::indeterminate, // less_than_zero, + value_type::z_value, // less_than_zero, value_type::indeterminate, // zero, - value_type::indeterminate, // greater_than_zero, + value_type::z_value, // greater_than_zero, value_type::indeterminate, // greater than max, value_type::indeterminate, // indeterminate, //}, // t == less_than_zero, //{ // u == ... - value_type::t_value, // less_than_min, + value_type::t_value, // less_than_min, value_type::greater_than_zero, // less_than_zero, value_type::indeterminate, // zero, value_type::less_than_zero, // greater_than_zero, - value_type::t_value, // greater than max, + value_type::t_value, // greater than max, value_type::indeterminate, // indeterminate, //}, // t == zero, @@ -479,9 +531,9 @@ constexpr inline operator%( // t == greater_than_max //{ value_type::indeterminate, // less_than_min, - value_type::indeterminate, // less_than_zero, + value_type::u_value, // less_than_zero, value_type::indeterminate, // zero, - value_type::indeterminate, // greater_than_zero, + value_type::u_value, // greater_than_zero, value_type::indeterminate, // greater than max, value_type::indeterminate, // indeterminate, //}, @@ -509,6 +561,10 @@ constexpr inline operator%( return safe_numerics_error::range_error; case value_type::t_value: return t; + case value_type::u_value: + return checked::subtract<T>(u, 1); + case value_type::z_value: + return checked::subtract<T>(1, u); case value_type::greater_than_max: case value_type::less_than_min: default: @@ -536,9 +592,8 @@ constexpr boost::logic::tribool operator<( // // b) return false because the two values are "equal" // - // for our purposes, b) is the better interpretation as it better - // models our view that the < operation referes to the place holders - // rather than some underlying value. + // for our purposes, a) seems the better interpretation. + enum class result_type : std::uint8_t { runtime, false_value, @@ -558,7 +613,7 @@ constexpr boost::logic::tribool operator<( //{ // u == ... result_type::true_value, // known_value, - result_type::false_value, // less_than_min, see above argument + result_type::indeterminate, // less_than_min, see above argument result_type::true_value, // greater_than_max, result_type::indeterminate, // indeterminate, //}, @@ -567,7 +622,7 @@ constexpr boost::logic::tribool operator<( // u == ... result_type::false_value, // known_value, result_type::false_value, // less_than_min, - result_type::false_value, // greater_than_max, see above argument + result_type::indeterminate, // greater_than_max, see above argument result_type::indeterminate, // indeterminate, //}, // t == indeterminate @@ -719,18 +774,6 @@ typename std::enable_if< std::is_integral<T>::value, checked_result<T> >::type -constexpr inline operator-( - const checked_result<T> & t -){ -// assert(false); - return checked_result<T>(0) - t; -} - -template<class T> -typename std::enable_if< - std::is_integral<T>::value, - checked_result<T> ->::type constexpr inline operator~( const checked_result<T> & t ){ @@ -750,7 +793,7 @@ constexpr inline operator<<( using value_type = product_value_type; const std::uint8_t order = static_cast<std::uint8_t>(value_type::count); - const std::uint8_t result[order * order] = { + constexpr const std::uint8_t result[order * order] = { // t == less_than_min //{ // u == ... diff --git a/boost/safe_numerics/concept/exception_policy.hpp b/boost/safe_numerics/concept/exception_policy.hpp index f0b98fcea9..134ed25807 100644 --- a/boost/safe_numerics/concept/exception_policy.hpp +++ b/boost/safe_numerics/concept/exception_policy.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP #define BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/concept/integer.hpp b/boost/safe_numerics/concept/integer.hpp index 80defa4575..79d0791c7f 100644 --- a/boost/safe_numerics/concept/integer.hpp +++ b/boost/safe_numerics/concept/integer.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CONCEPT_INTEGER_HPP #define BOOST_NUMERIC_CONCEPT_INTEGER_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/concept/numeric.hpp b/boost/safe_numerics/concept/numeric.hpp index 0885a5511f..d7f0f34709 100644 --- a/boost/safe_numerics/concept/numeric.hpp +++ b/boost/safe_numerics/concept/numeric.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CONCEPT_NUMERIC_HPP #define BOOST_NUMERIC_CONCEPT_NUMERIC_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/concept/promotion_policy.hpp b/boost/safe_numerics/concept/promotion_policy.hpp index b71ed91192..14bbb3cb89 100644 --- a/boost/safe_numerics/concept/promotion_policy.hpp +++ b/boost/safe_numerics/concept/promotion_policy.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CONCEPT_PROMOTION_POLICY_HPP #define BOOST_NUMERIC_CONCEPT_PROMOTION_POLICY_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/concept/safe_numeric.hpp b/boost/safe_numerics/concept/safe_numeric.hpp index 00481a02c6..0b6ac12803 100644 --- a/boost/safe_numerics/concept/safe_numeric.hpp +++ b/boost/safe_numerics/concept/safe_numeric.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CONCEPT_SAFE_NUMERIC_HPP #define BOOST_NUMERIC_CONCEPT_SAFE_NUMERIC_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/cpp.hpp b/boost/safe_numerics/cpp.hpp index 9d42c2f981..456fae58b8 100755 --- a/boost/safe_numerics/cpp.hpp +++ b/boost/safe_numerics/cpp.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_CPP_HPP
#define BOOST_NUMERIC_CPP_HPP
-// MS compatible compilers support #pragma once
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
// Copyright (c) 2012 Robert Ramey
//
// Distributed under the Boost Software License, Version 1.0. (See
diff --git a/boost/safe_numerics/exception.hpp b/boost/safe_numerics/exception.hpp index b67f74fb97..284b801d09 100644 --- a/boost/safe_numerics/exception.hpp +++ b/boost/safe_numerics/exception.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_EXCEPTION #define BOOST_NUMERIC_EXCEPTION -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -47,7 +42,7 @@ enum class safe_numerics_error : std::uint8_t { negative_value_shift, // negative value in shift operator negative_shift, // shift a negative value shift_too_large, // l/r shift exceeds variable size - uninitialized_value // l/r shift exceeds variable size + uninitialized_value // creating of uninitialized value }; const std::uint8_t safe_numerics_casting_error_count = @@ -63,7 +58,7 @@ namespace std { template <> struct is_error_code_enum<boost::safe_numerics::safe_numerics_error> : public true_type {}; -}; +} // std namespace boost { namespace safe_numerics { @@ -100,10 +95,10 @@ public: } return ""; // suppress bogus warning } -} safe_numerics_error_category ; +} safe_numerics_error_category {}; // constexpr - damn, can't use constexpr due to std::error_code -std::error_code make_error_code(safe_numerics_error e){ +std::error_code make_error_code(const safe_numerics_error & e){ return std::error_code(static_cast<int>(e), safe_numerics_error_category); } @@ -126,7 +121,7 @@ namespace std { template <> struct is_error_condition_enum<boost::safe_numerics::safe_numerics_actions> : public true_type {}; -}; +} // std namespace boost { namespace safe_numerics { @@ -172,14 +167,20 @@ public: // suppress bogus warning return false; } -} safe_numerics_actions_category ; - -std::error_condition make_error_condition(safe_numerics_error e) { +} safe_numerics_actions_category {}; + +// the following function is used to "finish" implementation of conversion +// of safe_numerics_error to std::error_condition. At least for now, this +// isn't being used and defining here it can lead duplicate symbol errors +// depending on the compiler. So suppress it until further notice +#if 0 +std::error_condition make_error_condition(const safe_numerics_error & e) { return std::error_condition( static_cast<int>(e), safe_numerics_error_category ); } +#endif } // safe_numerics } // boost diff --git a/boost/safe_numerics/exception_policies.hpp b/boost/safe_numerics/exception_policies.hpp index efa4cbe055..8a106974e5 100644 --- a/boost/safe_numerics/exception_policies.hpp +++ b/boost/safe_numerics/exception_policies.hpp @@ -1,18 +1,13 @@ #ifndef BOOST_NUMERIC_EXCEPTION_POLICIES_HPP #define BOOST_NUMERIC_EXCEPTION_POLICIES_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include <type_traits> // is_convertible +#include <boost/mp11.hpp> #include "exception.hpp" @@ -57,7 +52,7 @@ struct exception_policy { // ignore any error and just return. struct ignore_exception { - constexpr ignore_exception(const safe_numerics_error &, const char *){} + constexpr ignore_exception(const safe_numerics_error &, const char * ){} }; // If an exceptional condition is detected at runtime throw the exception. @@ -89,8 +84,8 @@ make_safe_numerics_action(const safe_numerics_error & e){ case safe_numerics_error::shift_too_large: return safe_numerics_actions::implementation_defined_behavior; -// case safe_numerics_error::uninitialized_value: -// return safe_numerics_actions::uninitialized_value; + case safe_numerics_error::uninitialized_value: + return safe_numerics_actions::uninitialized_value; case safe_numerics_error::success: return safe_numerics_actions::no_action; @@ -102,32 +97,69 @@ make_safe_numerics_action(const safe_numerics_error & e){ return safe_numerics_actions::no_action; } -template<class EP> +//////////////////////////////////////////////////////////////////////////////// +// compile time error dispatcher + +// note slightly baroque implementation of a compile time switch statement +// which instatiates oonly those cases which are actually invoked. This is +// motivated to implement the "trap" functionality which will generate a syntax +// error if and only a function which might fail is called. + +namespace dispatch_switch { + + template<class EP, safe_numerics_actions> + struct dispatch_case {}; + + template<class EP> + struct dispatch_case<EP, safe_numerics_actions::uninitialized_value> { + constexpr static void invoke(const safe_numerics_error & e, const char * msg){ + EP::on_uninitialized_value(e, msg); + } + }; + template<class EP> + struct dispatch_case<EP, safe_numerics_actions::arithmetic_error> { + constexpr static void invoke(const safe_numerics_error & e, const char * msg){ + EP::on_arithmetic_error(e, msg); + } + }; + template<class EP> + struct dispatch_case<EP, safe_numerics_actions::implementation_defined_behavior> { + constexpr static void invoke(const safe_numerics_error & e, const char * msg){ + EP::on_implementation_defined_behavior(e, msg); + } + }; + template<class EP> + struct dispatch_case<EP, safe_numerics_actions::undefined_behavior> { + constexpr static void invoke(const safe_numerics_error & e, const char * msg){ + EP::on_undefined_behavior(e, msg); + } + }; + +} // dispatch_switch + +template<class EP, safe_numerics_error E> constexpr void -dispatch(const safe_numerics_error & e, char const * const & msg){ - const safe_numerics_actions a = make_safe_numerics_action(e); - switch(a){ - case safe_numerics_actions::uninitialized_value: - EP::on_uninitialized_value(e, msg); - break; - case safe_numerics_actions::arithmetic_error: - EP::on_arithmetic_error(e, msg); - break; - case safe_numerics_actions::implementation_defined_behavior: - EP::on_implementation_defined_behavior(e, msg); - break; - case safe_numerics_actions::undefined_behavior: - EP::on_undefined_behavior(e, msg); - break; - default: - assert(false); - } +dispatch(const char * msg){ + constexpr safe_numerics_actions a = make_safe_numerics_action(E); + dispatch_switch::dispatch_case<EP, a>::invoke(E, msg); } +template<class EP, class R> +class dispatch_and_return { +public: + template<safe_numerics_error E> + constexpr static checked_result<R> invoke( + char const * const & msg + ) { + dispatch<EP, E>(msg); + return checked_result<R>(E, msg); + } +}; + //////////////////////////////////////////////////////////////////////////////// // pre-made error policy classes -// loose policy +// loose exception // - throw on arithmetic errors // - ignore other errors. // Some applications ignore these issues and still work and we don't @@ -136,7 +168,7 @@ using loose_exception_policy = exception_policy< throw_exception, // arithmetic error ignore_exception, // implementation defined behavior ignore_exception, // undefined behavior - ignore_exception // uninitialized value + ignore_exception // uninitialized value >; // loose trap @@ -146,20 +178,12 @@ using loose_exception_policy = exception_policy< // bit manipulation operations to work. using loose_trap_policy = exception_policy< trap_exception, // arithmetic error - ignore_exception, // implementation defined behavior - ignore_exception, // undefined behavior - ignore_exception // uninitialized value + ignore_exception, // implementation defined behavior + ignore_exception, // undefined behavior + ignore_exception // uninitialized value >; -#if 0 -template<> -constexpr void -dispatch<loose_trap_policy>(const safe_numerics_error &, char const * const &){// strict exception policy - static_assert(false, "trap"); -} -#endif - -// - permit just about anything +// strict exception // - throw at runtime on any kind of error // recommended for new code. Check everything at compile time // if possible and runtime if necessary. Trap or Throw as @@ -169,7 +193,7 @@ using strict_exception_policy = exception_policy< throw_exception, throw_exception, throw_exception, - throw_exception + ignore_exception >; // strict trap diff --git a/boost/safe_numerics/interval.hpp b/boost/safe_numerics/interval.hpp index 9292d7f4ac..2d85aee689 100644 --- a/boost/safe_numerics/interval.hpp +++ b/boost/safe_numerics/interval.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_INTERVAL_HPP #define BOOST_NUMERIC_INTERVAL_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/native.hpp b/boost/safe_numerics/native.hpp index f948badd1a..78d34fd1ad 100644 --- a/boost/safe_numerics/native.hpp +++ b/boost/safe_numerics/native.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_NATIVE_HPP #define BOOST_NUMERIC_NATIVE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/range_value.hpp b/boost/safe_numerics/range_value.hpp index a441809d13..ceef19e898 100644 --- a/boost/safe_numerics/range_value.hpp +++ b/boost/safe_numerics/range_value.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_RANGE_VALUE_HPP #define BOOST_RANGE_VALUE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -44,9 +39,9 @@ std::basic_ostream<CharT, Traits> & operator<<( const range_value<T> & t ){ return os - << boost::safe_numerics::make_interval(t.m_t) + << boost::safe_numerics::make_interval<T>() << t.m_t; -}; +} template<typename T> struct result_display { diff --git a/boost/safe_numerics/safe_base.hpp b/boost/safe_numerics/safe_base.hpp index 7d56b8421f..55508d0d5e 100644 --- a/boost/safe_numerics/safe_base.hpp +++ b/boost/safe_numerics/safe_base.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_BASE_HPP #define BOOST_NUMERIC_SAFE_BASE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -14,10 +9,7 @@ #include <limits> #include <type_traits> // is_integral, enable_if, conditional - -#include <boost/mpl/eval_if.hpp> -#include <boost/mpl/identity.hpp> - +#include <boost/config.hpp> // BOOST_CLANG #include "concept/exception_policy.hpp" #include "concept/promotion_policy.hpp" @@ -106,6 +98,12 @@ template< > class safe_literal_impl; +// works for both GCC and clang +#if BOOST_CLANG==1 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmismatched-tags" +#endif + ///////////////////////////////////////////////////////////////// // Main implementation @@ -183,37 +181,9 @@ public: struct skip_validation{}; - constexpr explicit safe_base(const Stored & rhs, skip_validation) : - m_t(rhs) - {} - - // default constructor - /* - constexpr explicit safe_base() { - // this permits creating of invalid instances. This is inline - // with C++ built-in but violates the premises of the whole library - // choice are: - // do nothing - violates premise of he library that all safe objects - // are valid - // initialize to valid value - violates C++ behavior of types. - // add "initialized" flag. Preserves fixes the above, but doubles - // "overhead" - // still pending on this. - } - */ - constexpr safe_base() = default; + constexpr explicit safe_base(const Stored & rhs, skip_validation); - // note: Rule of Five. Supply all or none of the following - // a) user-defined destructor - ~safe_base() = default; - // b) copy-constructor - constexpr safe_base(const safe_base &) = default; - // c) copy-assignment - constexpr safe_base & operator=(const safe_base &) = default; - // d) move constructor - constexpr safe_base(safe_base &&) = default; - // e) move assignment operator - constexpr safe_base & operator=(safe_base &&) = default; + constexpr safe_base(); // construct an instance of a safe type // from an instance of a convertible underlying type. @@ -225,9 +195,7 @@ public: is_safe<T>::value, bool >::type = true - ) : - m_t(validated_cast(t)) - {} + ); template<class T> constexpr /*explicit*/ safe_base( @@ -236,9 +204,24 @@ public: std::is_integral<T>::value, bool >::type = true - ) : - m_t(validated_cast(t)) - {} + ); + + template<class T, T value> + constexpr /*explicit*/ safe_base( + const std::integral_constant<T, value> & + ); + + // note: Rule of Five. Supply all or none of the following + // a) user-defined destructor + ~safe_base() = default; + // b) copy-constructor + constexpr safe_base(const safe_base &) = default; + // c) copy-assignment + constexpr safe_base & operator=(const safe_base &) = default; + // d) move constructor + constexpr safe_base(safe_base &&) = default; + // e) move assignment operator + constexpr safe_base & operator=(safe_base &&) = default; ///////////////////////////////////////////////////////////////// // casting operators for intrinsic integers @@ -359,4 +342,8 @@ public: } // std +#if BOOST_CLANG==1 +#pragma GCC diagnostic pop +#endif + #endif // BOOST_NUMERIC_SAFE_BASE_HPP diff --git a/boost/safe_numerics/safe_base_operations.hpp b/boost/safe_numerics/safe_base_operations.hpp index ea69c95f76..982358208a 100644 --- a/boost/safe_numerics/safe_base_operations.hpp +++ b/boost/safe_numerics/safe_base_operations.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP #define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -18,7 +13,6 @@ #include <cassert> #include <boost/config.hpp> -#include <boost/mpl/eval_if.hpp> #include <boost/core/enable_if.hpp> // lazy_enable_if #include <boost/integer.hpp> @@ -35,17 +29,6 @@ namespace boost { namespace safe_numerics { -// invoke error handling -template<class EP, typename R> -constexpr void -dispatch(const checked_result<R> & cr){ - // if the result contains an error condition - if(cr.exception()) - // dispatch to the appropriate function - dispatch<EP>(cr.m_e, cr.m_msg); - // otherwise just do a simple return -} - ///////////////////////////////////////////////////////////////// // validation @@ -58,11 +41,15 @@ struct validate_detail { const T & t ){ // INT08-C - const r_type r = checked::cast<R>(t); - if(r.exception()){ - dispatch<E>(r); - } - return base_value(r); + const r_type rx = heterogeneous_checked_operation< + R, + typename base_type<T>::type, + dispatch_and_return<E, R> + >::cast(t); + const R r = rx.exception() + ? static_cast<R>(t) + : rx.m_r; + return r; } }; struct exception_not_possible { @@ -116,6 +103,59 @@ validated_cast(const safe_literal_impl<T, N, P1, E1> &) const { } ///////////////////////////////////////////////////////////////// +// constructors + +template<class Stored, Stored Min, Stored Max, class P, class E> + constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base( + const Stored & rhs, + skip_validation +) : + m_t(rhs) +{} + +template<class Stored, Stored Min, Stored Max, class P, class E> +constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){ + dispatch<E, safe_numerics_error::uninitialized_value>( + "safe values must be initialized" + ); +} + +// construct an instance of a safe type +// from an instance of a convertible underlying type. +template<class Stored, Stored Min, Stored Max, class P, class E> +template<class T> +constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base( + const T & t, + typename std::enable_if< + is_safe<T>::value, + bool + >::type +) : + m_t(validated_cast(t)) +{} + +template<class Stored, Stored Min, Stored Max, class P, class E> +template<class T> +constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base( + const T & t, + typename std::enable_if< + std::is_integral<T>::value, + bool + >::type +) : + m_t(validated_cast(t)) +{} + +template<class Stored, Stored Min, Stored Max, class P, class E> +template<class T, T value> +constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base( + + const std::integral_constant<T, value> & +) : + m_t(validated_cast(value)) +{} + +///////////////////////////////////////////////////////////////// // casting operators // cast to a builtin type from a safe type @@ -242,6 +282,33 @@ struct common_promotion_policy { // all other safe types including float and user defined ones. // +// helper - cast arguments to binary operators to a specified +// result type + +template<class EP, class R, class T, class U> +std::pair<R, R> +constexpr static casting_helper(const T & t, const U & u){ + using r_type = checked_result<R>; + const r_type tx = heterogeneous_checked_operation< + R, + typename base_type<T>::type, + dispatch_and_return<EP, R> + >::cast(base_value(t)); + const R tr = tx.exception() + ? static_cast<R>(t) + : tx.m_r; + + const r_type ux = heterogeneous_checked_operation< + R, + typename base_type<U>::type, + dispatch_and_return<EP, R> + >::cast(base_value(u)); + const R ur = ux.exception() + ? static_cast<R>(u) + : ux.m_r; + return std::pair<R, R>(tr, ur); +} + // Note: the following global operators will be found via // argument dependent lookup. @@ -266,32 +333,29 @@ private: // if exception possible using exception_policy = typename common_exception_policy<T, U>::type; + using r_type = checked_result<result_base_type>; + constexpr static result_base_type return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - // the following will use checked arithmetic - const r_type r = (tx + ux); - if(!r.exception()){ - return static_cast<result_base_type>(r); - } - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + const r_type rx = checked_operation< + result_base_type, + dispatch_and_return<exception_policy, result_base_type> + >::add(r.first, r.second); + return - static_cast<result_base_type>(tx) - + static_cast<result_base_type>(ux); + rx.exception() + ? r.first + r.second + : rx.m_r; } - using r_type = checked_result<result_base_type>; using r_type_interval_t = interval<r_type>; - constexpr static r_type_interval_t get_r_type_interval(){ + constexpr static const r_type_interval_t get_r_type_interval(){ constexpr const r_type_interval_t t_interval{ checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())), checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max())) @@ -302,11 +366,9 @@ private: }; return t_interval + u_interval; } + constexpr static const r_type_interval_t r_type_interval = get_r_type_interval(); - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - using return_interval_t = interval<result_base_type>; - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -325,12 +387,15 @@ private: return false; } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -391,27 +456,24 @@ private: constexpr static result_base_type return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - // the following will use checked arithmetic - r_type r = (tx - ux); - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + const r_type rx = checked_operation< + result_base_type, + dispatch_and_return<exception_policy, result_base_type> + >::subtract(r.first, r.second); + return - static_cast<result_base_type>(tx) - - static_cast<result_base_type>(ux); + rx.exception() + ? r.first + r.second + : rx.m_r; } using r_type_interval_t = interval<r_type>; - constexpr static r_type_interval_t get_r_type_interval(){ + constexpr static const r_type_interval_t get_r_type_interval(){ constexpr const r_type_interval_t t_interval{ checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())), checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max())) @@ -424,11 +486,9 @@ private: return t_interval - u_interval; } - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -448,11 +508,14 @@ private: } public: + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -513,23 +576,22 @@ private: constexpr static result_base_type return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - r_type r = (tx * ux); - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + const r_type rx = checked_operation< + result_base_type, + dispatch_and_return<exception_policy, result_base_type> + >::multiply(r.first, r.second); + return - static_cast<result_base_type>(tx) - * static_cast<result_base_type>(ux); + rx.exception() + ? r.first * r.second + : rx.m_r; } + using r_type_interval_t = interval<r_type>; constexpr static r_type_interval_t get_r_type_interval(){ @@ -548,8 +610,7 @@ private: static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -568,12 +629,15 @@ private: return false; } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -652,23 +716,20 @@ private: >::type; using t_type = checked_result<temp_base>; - const t_type tx = checked::cast<temp_base>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const t_type ux = checked::cast<temp_base>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - const t_type r = (tx / ux); - - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way + const std::pair<t_type, t_type> r = casting_helper< + exception_policy, + temp_base + >(t, u); + + const t_type rx = checked_operation< + temp_base, + dispatch_and_return<exception_policy, temp_base> + >::divide(r.first, r.second); + return - static_cast<result_base_type>(tx) - / static_cast<result_base_type>(ux); + rx.exception() + ? r.first / r.second + : rx; } using r_type_interval_t = interval<r_type>; @@ -708,9 +769,7 @@ private: static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -722,19 +781,21 @@ private: constexpr static bool exception_possible(){ constexpr const r_type_interval_t ri = get_r_type_interval(); constexpr const r_type_interval_t ui = u_interval(); - return static_cast<bool>(ui.includes(r_type(0))) || ri.l.exception() || ri.u.exception(); } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -810,23 +871,20 @@ private: >::type; using t_type = checked_result<temp_base>; - const t_type tx = checked::cast<temp_base>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const t_type ux = checked::cast<temp_base>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - t_type r = (tx % ux); - - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way + const std::pair<t_type, t_type> r = casting_helper< + exception_policy, + temp_base + >(t, u); + + const t_type rx = checked_operation< + temp_base, + dispatch_and_return<exception_policy, temp_base> + >::modulus(r.first, r.second); + return - static_cast<result_base_type>(tx) - % static_cast<result_base_type>(ux); + rx.exception() + ? r.first % r.second + : rx; } using r_type_interval_t = interval<r_type>; @@ -868,8 +926,7 @@ private: static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -881,19 +938,21 @@ private: constexpr static bool exception_possible(){ constexpr const r_type_interval_t ri = get_r_type_interval(); constexpr const r_type_interval_t ui = u_interval(); - return static_cast<bool>(ui.includes(r_type(0))) || ri.l.exception() || ri.u.exception(); } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -958,19 +1017,12 @@ private: // if exception possible constexpr static bool return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - const boost::logic::tribool r = (tx < ux); - if(r || !r) // answer is not indeterminate - return static_cast<bool>(r); - dispatch<exception_policy>( - checked_result<bool>(safe_numerics_error::domain_error) - ); - return safe_compare::less_than(base_value(t), base_value(u)); + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + return safe_compare::less_than(r.first, r.second); } using r_type_interval_t = interval<r_type>; @@ -1068,19 +1120,12 @@ private: // exception possible constexpr static bool return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - const boost::logic::tribool r = (tx == ux); - if(! boost::logic::indeterminate(r)) - return static_cast<bool>(r); - dispatch<exception_policy>( - checked_result<bool>(safe_numerics_error::domain_error) - ); - return safe_compare::equal(base_value(t), base_value(u)); + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + return safe_compare::equal(r.first, r.second); } using r_type_interval = interval<r_type>; @@ -1160,20 +1205,20 @@ private: constexpr static result_base_type return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - const r_type r = checked::left_shift(tx.m_r, ux.m_r); - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way - return t << u; + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + const r_type rx = checked_operation< + result_base_type, + dispatch_and_return<exception_policy, result_base_type> + >::left_shift(r.first, r.second); + + return + rx.exception() + ? r.first << r.second + : rx.m_r; } using r_type_interval_t = interval<r_type>; @@ -1193,8 +1238,7 @@ private: static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -1213,12 +1257,15 @@ private: return false; } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -1287,20 +1334,20 @@ struct right_shift_result { constexpr static result_base_type return_value(const T & t, const U & u, std::true_type){ - const r_type tx = checked::cast<result_base_type>(base_value(t)); - if(tx.exception()) - dispatch<exception_policy>(tx); - const r_type ux = checked::cast<result_base_type>(base_value(u)); - if(ux.exception()) - dispatch<exception_policy>(ux); - const r_type r = checked::right_shift(tx.m_r, ux.m_r); - if(!r.exception()) - return static_cast<result_base_type>(r); - // handle error condition - dispatch<exception_policy>(r); - // if we get here, the error has been ignored - // just get the result the old fashioned way - return t >> u; + const std::pair<result_base_type, result_base_type> r = casting_helper< + exception_policy, + result_base_type + >(t, u); + + const r_type rx = checked_operation< + result_base_type, + dispatch_and_return<exception_policy, result_base_type> + >::right_shift(r.first, r.second); + + return + rx.exception() + ? r.first >> r.second + : rx.m_r; } using r_type_interval_t = interval<r_type>; @@ -1324,9 +1371,7 @@ struct right_shift_result { static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - using return_interval_t = interval<result_base_type>; - - constexpr static return_interval_t return_interval{ + constexpr static const interval<result_base_type> return_interval{ r_type_interval.l.exception() ? std::numeric_limits<result_base_type>::min() : static_cast<result_base_type>(r_type_interval.l), @@ -1351,12 +1396,15 @@ struct right_shift_result { ); } + constexpr static auto rl = return_interval.l; + constexpr static auto ru = return_interval.u; + public: using type = safe_base< result_base_type, - return_interval.l, - return_interval.u, + rl, + ru, promotion_policy, exception_policy >; @@ -1418,6 +1466,8 @@ private: using r_type = typename std::make_unsigned<result_base_type>::type; using r_type_interval_t = interval<r_type>; + #if 0 + // breaks compilation for earlier versions of clant constexpr static const r_type_interval_t r_interval{ r_type(0), utility::round_out( @@ -1427,6 +1477,7 @@ private: ) ) }; + #endif using exception_policy = typename common_exception_policy<T, U>::type; @@ -1434,8 +1485,15 @@ public: // lazy_enable_if_c depends on this using type = safe_base< result_base_type, - r_interval.l, - r_interval.u, + //r_interval.l, + r_type(0), + //r_interval.u, + utility::round_out( + std::max( + static_cast<r_type>(base_value(std::numeric_limits<T>::max())), + static_cast<r_type>(base_value(std::numeric_limits<U>::max())) + ) + ), promotion_policy, exception_policy >; @@ -1483,6 +1541,8 @@ private: using r_type = typename std::make_unsigned<result_base_type>::type; using r_type_interval_t = interval<r_type>; + #if 0 + // breaks compilation for earlier versions of clant constexpr static const r_type_interval_t r_interval{ r_type(0), utility::round_out( @@ -1492,15 +1552,22 @@ private: ) ) }; - + #endif using exception_policy = typename common_exception_policy<T, U>::type; public: // lazy_enable_if_c depends on this using type = safe_base< result_base_type, - r_interval.l, - r_interval.u, + //r_interval.l, + r_type(0), + //r_interval.u, + utility::round_out( + std::min( + static_cast<r_type>(base_value(std::numeric_limits<T>::max())), + static_cast<r_type>(base_value(std::numeric_limits<U>::max())) + ) + ), promotion_policy, exception_policy >; @@ -1547,6 +1614,8 @@ struct bitwise_xor_result { using r_type = typename std::make_unsigned<result_base_type>::type; using r_type_interval_t = interval<r_type>; + #if 0 + // breaks compilation for earlier versions of clant constexpr static const r_type_interval_t r_interval{ r_type(0), utility::round_out( @@ -1556,6 +1625,7 @@ struct bitwise_xor_result { ) ) }; + #endif using exception_policy = typename common_exception_policy<T, U>::type; @@ -1563,8 +1633,15 @@ public: // lazy_enable_if_c depends on this using type = safe_base< result_base_type, - r_interval.l, - r_interval.u, + //r_interval.l, + r_type(0), + //r_interval.u, + utility::round_out( + std::max( + static_cast<r_type>(base_value(std::numeric_limits<T>::max())), + static_cast<r_type>(base_value(std::numeric_limits<U>::max())) + ) + ), promotion_policy, exception_policy >; @@ -1652,8 +1729,10 @@ void safe_base<T, Min, Max, P, E>::input( validated_cast(m_t); } if(is.fail()){ - boost::safe_numerics::dispatch<E>( - boost::safe_numerics::safe_numerics_error::domain_error, + boost::safe_numerics::dispatch< + E, + boost::safe_numerics::safe_numerics_error::domain_error + >( "error in file input" ); } diff --git a/boost/safe_numerics/safe_common.hpp b/boost/safe_numerics/safe_common.hpp index 3e53e36e16..71a00ade7a 100644 --- a/boost/safe_numerics/safe_common.hpp +++ b/boost/safe_numerics/safe_common.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_COMMON_HPP #define BOOST_NUMERIC_SAFE_COMMON_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/safe_compare.hpp b/boost/safe_numerics/safe_compare.hpp index 0c53c82245..2b52c2dfe5 100644 --- a/boost/safe_numerics/safe_compare.hpp +++ b/boost/safe_numerics/safe_compare.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_COMPARE_HPP #define BOOST_NUMERIC_SAFE_COMPARE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/safe_integer.hpp b/boost/safe_numerics/safe_integer.hpp index 0daa84d154..56281f36cf 100644 --- a/boost/safe_numerics/safe_integer.hpp +++ b/boost/safe_numerics/safe_integer.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_INTEGER_HPP #define BOOST_NUMERIC_SAFE_INTEGER_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/safe_integer_literal.hpp b/boost/safe_numerics/safe_integer_literal.hpp index 2e6c1099e4..8def6d1ee6 100644 --- a/boost/safe_numerics/safe_integer_literal.hpp +++ b/boost/safe_numerics/safe_integer_literal.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP #define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/safe_integer_range.hpp b/boost/safe_numerics/safe_integer_range.hpp index 7c059cbfbc..e9fce8447c 100644 --- a/boost/safe_numerics/safe_integer_range.hpp +++ b/boost/safe_numerics/safe_integer_range.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_SAFE_INTEGER_RANGE_HPP #define BOOST_NUMERIC_SAFE_INTEGER_RANGE_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2012 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See diff --git a/boost/safe_numerics/utility.hpp b/boost/safe_numerics/utility.hpp index 02dfdf99c2..79a439acc9 100644 --- a/boost/safe_numerics/utility.hpp +++ b/boost/safe_numerics/utility.hpp @@ -1,11 +1,6 @@ #ifndef BOOST_NUMERIC_UTILITY_HPP #define BOOST_NUMERIC_UTILITY_HPP -// MS compatible compilers support #pragma once -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - // Copyright (c) 2015 Robert Ramey // // Distributed under the Boost Software License, Version 1.0. (See @@ -103,7 +98,7 @@ namespace ilog2_detail { constexpr static unsigned int ilog2(const boost::uint_t<8>::exact & t){ #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n const char LogTable256[256] = { - -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + static_cast<const char>(-1), 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) }; @@ -128,7 +123,7 @@ namespace ilog2_detail { : 32 + ilog2(upper_half); } -}; // ilog2_detail +} // ilog2_detail template<typename T> constexpr unsigned int ilog2(const T & t){ @@ -241,13 +236,13 @@ constexpr T round_out(const T & t){ if(t >= 0){ const std::uint8_t sb = utility::significant_bits(t); return (sb < sizeof(T) * 8) - ? (1ul << sb) - 1 + ? ((T)1 << sb) - 1 : std::numeric_limits<T>::max(); } else{ const std::uint8_t sb = utility::significant_bits(~t); return (sb < sizeof(T) * 8) - ? ~((1ul << sb) - 1) + ? ~(((T)1 << sb) - 1) : std::numeric_limits<T>::min(); } } |