diff --git a/include/checked.hpp b/include/checked.hpp index 9bb9ca9..12a99a1 100644 --- a/include/checked.hpp +++ b/include/checked.hpp @@ -160,6 +160,21 @@ namespace checked { ; } + template + SAFE_NUMERIC_CONSTEXPR checked_result add( + const T & t, + const U & u + ) { + return + add( + std::numeric_limits::min(), + std::numeric_limits::max(), + t, + u + ) + ; + } + //////////////////////////////////////////////////// // safe subtraction on primitive types namespace detail { @@ -231,6 +246,21 @@ namespace checked { detail::subtract(minr, maxr, t, u) ; } + + template + SAFE_NUMERIC_CONSTEXPR checked_result subtract( + const T & t, + const U & u + ) { + return + subtract( + std::numeric_limits::min(), + std::numeric_limits::max(), + t, + u + ) + ; + } //////////////////////////////////////////////////// // safe multiplication on unsafe types @@ -389,9 +419,9 @@ namespace checked { detail::cast(u) != checked_result::exception_type::no_exception ? detail::cast(u) : - //sizeof(R) >= sizeof(T) + sizeof(U) ? - // checked_result(static_cast(t) * static_cast(u)) - //: + sizeof(R) >= sizeof(T) + sizeof(U) ? + checked_result(static_cast(t) * static_cast(u)) + : detail::multiply(minr, maxr, t, u) ; } @@ -491,32 +521,89 @@ namespace checked { ) ; } - /* - template - decltype(T() / U()) - check_modulus_overflow(const T & t, const U & u){ - if(0 == u) - overflow("modulus divide by zero"); - if(boost::numeric::is_signed::value){ - // t unsigned, u signed - if(boost::numeric::is_unsigned::value){ - if(u < 0){ - overflow("conversion of negative value to unsigned"); - } - } - else{ - // both signed - // pathological case: change sign on negative number so it overflows - if(t == boost::integer_traits::const_min && u == -1) - overflow("overflow in result"); - } - } - // both unsigned - // t signed, u unsigned - return t % u; + //////////////////////////////// + // safe modulus on unsafe types + namespace detail { + + template + typename boost::enable_if_c< + std::is_unsigned::value, + checked_result + >::type + SAFE_NUMERIC_CONSTEXPR modulus( + const R & minr, + const R & maxr, + const R t, + const R u + ) { + return checked_result(t % u); } - */ + + template + typename boost::enable_if_c< + std::is_signed::value, + checked_result + >::type + SAFE_NUMERIC_CONSTEXPR modulus( + const R & minr, + const R & maxr, + const R t, + const R u + ){ + return + // note presumption of two's complement arithmetic + (u < 0 && t == std::numeric_limits::min()) ? + checked_result( + checked_result::exception_type::domain_error, + "divide by zero" + ) + : + checked_result(t % u) + ; + } + + } // namespace detail + + template + SAFE_NUMERIC_CONSTEXPR checked_result modulus( + const R & minr, + const R & maxr, + const T & t, + const U & u + ) { + static_assert(! is_safe::value, "should not be a base type here!"); + return + detail::cast(t) != checked_result::exception_type::no_exception ? + detail::cast(t) + : + detail::cast(u) != checked_result::exception_type::no_exception ? + detail::cast(u) + : + u == 0 ? + checked_result( + checked_result::exception_type::domain_error, + "divide by zero" + ) + : + detail::divide(minr, maxr, t, u) + ; + } + template + SAFE_NUMERIC_CONSTEXPR checked_result modulus( + const T & t, + const U & u + ) { + return + divide( + std::numeric_limits::min(), + std::numeric_limits::max(), + t, + u + ) + ; + } + } // checked } // numeric } // boost diff --git a/include/interval.hpp b/include/interval.hpp index f27894e..49e52d7 100644 --- a/include/interval.hpp +++ b/include/interval.hpp @@ -45,6 +45,24 @@ struct interval { } }; +template +SAFE_NUMERIC_CONSTEXPR interval operator+(const interval & t, const interval & u){ + // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic + return interval( + checked::add(t.l, u.l), + checked::add(t.u, u.u) + ); +} + +template +SAFE_NUMERIC_CONSTEXPR interval operator-(const interval & t, const interval & u){ + // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic + return interval( + checked::subtract(t.l, u.u), + checked::subtract(t.u, u.l) + ); +} + template SAFE_NUMERIC_CONSTEXPR interval operator*(const interval & t, const interval & u){ // the following is adapted from boost interval arith.hpp @@ -157,63 +175,43 @@ SAFE_NUMERIC_CONSTEXPR interval operator/(const interval & t, const interv ; } -/* template -SAFE_NUMERIC_CONSTEXPR interval operator/(const interval & t, const interval & u){ - // adapted from boost interval library +SAFE_NUMERIC_CONSTEXPR interval operator%(const interval & t, const interval & u){ + // adapted from / operator above return - (t.u < 0) ? - (u.u < 0) ? - interval( - checked_result(t.u, u.l), - checked_result(t.l, u.u) - ) - : - interval( - checked_result(t.l, u.l), - checked_result(t.u, u.u) + (u.l <= 0) ? + interval( + 0, + checked_result( + checked_result::exception_type::domain_error, + "interval divisor includes zero" ) + ) : - (t.l < 0) ? - (u.u < 0) ? - interval( - checked_result(t.u, u.u), - checked_result(t.l, u.u) + interval( + min( + min( + checked::modulus(t.l, u.l), + checked::modulus(t.l, u.u) + ), + min( + checked::modulus(t.u, u.l), + checked::modulus(t.u, u.u) + ) + ), + max( + max( + checked::modulus(t.l, u.l), + checked::modulus(t.l, u.u) + ), + max( + checked::modulus(t.u, u.l), + checked::modulus(t.u, u.u) + ) ) - : - interval( - checked_result(t.l, u.l), - checked_result(t.u, u.l) - ) - : - (u.u < 0) ? - interval( - checked_result(t.u, u.u), - checked_result(t.l, u.l) - ) - : - interval( - checked_result(t.l, u.u), - checked_result(t.u, u.l) - ) - ; + ) + ; } - if (::boost::numeric::interval_lib::user::is_neg(xu)) - if (::boost::numeric::interval_lib::user::is_neg(yu)) - return I(rnd.div_down(xu, yl), rnd.div_up(xl, yu), true); - else - return I(rnd.div_down(xl, yl), rnd.div_up(xu, yu), true); - else if (::boost::numeric::interval_lib::user::is_neg(xl)) - if (::boost::numeric::interval_lib::user::is_neg(yu)) - return I(rnd.div_down(xu, yu), rnd.div_up(xl, yu), true); - else - return I(rnd.div_down(xl, yl), rnd.div_up(xu, yl), true); - else - if (::boost::numeric::interval_lib::user::is_neg(yu)) - return I(rnd.div_down(xu, yu), rnd.div_up(xl, yl), true); - else - return I(rnd.div_down(xl, yu), rnd.div_up(xu, yl), true); -*/ } // numeric } // boost diff --git a/include/native.hpp b/include/native.hpp index 14db46d..b152578 100644 --- a/include/native.hpp +++ b/include/native.hpp @@ -32,7 +32,7 @@ struct safe; struct native { template struct addition_result { - typedef typename base_type::type base_type_t; + typedef typename ::boost::numeric::base_type::type base_type_t; typedef typename base_type::type base_type_u; typedef decltype(base_type_t() + base_type_u()) result_base_type; typedef safe type; @@ -58,6 +58,13 @@ struct native { typedef decltype(base_type_t() / base_type_u()) result_base_type; typedef safe type; }; + template + struct modulus_result { + typedef typename base_type::type base_type_t; + typedef typename base_type::type base_type_u; + typedef decltype(base_type_t() / base_type_u()) result_base_type; + typedef safe type; + }; }; } // numeric diff --git a/include/safe_base.hpp b/include/safe_base.hpp index c2ed0ff..45c2a8f 100644 --- a/include/safe_base.hpp +++ b/include/safe_base.hpp @@ -227,74 +227,6 @@ public: } /* - ///////////////////////////////////////////////////////////////// - // subtraction - template - struct no_subtraction_overflow_possible : public - boost::mpl::and_< - typename boost::mpl::greater< - typename boost::mpl::sizeof_< decltype(Stored() - U()) >, - typename boost::mpl::max< - boost::mpl::sizeof_, - boost::mpl::sizeof_ - >::type - >, - boost::numeric::is_signed - > - {}; - - template - struct no_subtraction_overflow_possible; - - // case 1 - no overflow possible - - template - typename boost::enable_if< - no_subtraction_overflow_possible, - decltype(Stored() - U()) - >::type - inline operator-(const U & rhs) const { - return m_t - rhs; - } - - template - typename boost::disable_if< - no_subtraction_overflow_possible, - decltype(Stored() - U()) - >::type - inline operator-(const U & rhs) const { - return detail::check_subtraction_overflow< - boost::numeric::is_signed::value, - boost::numeric::is_signed::value - >::subtract(m_t, boost::numeric::safe_cast(rhs)); - } - - ///////////////////////////////////////////////////////////////// - // multiplication - - template - decltype(U() * Stored()) - inline operator*(const U & rhs) const { - return detail::check_multiplication_overflow(m_t, rhs); - } - - ///////////////////////////////////////////////////////////////// - // division - template - decltype(U() / Stored()) - inline operator/(const U & rhs) const { - return detail::check_division_overflow(m_t, rhs); - } - - ///////////////////////////////////////////////////////////////// - // modulus - template - decltype(Stored() % U()) - inline operator%(const U & rhs) const { - if(0 == rhs) - throw std::domain_error("Divide by zero"); - return detail::check_modulus_overflow(m_t, rhs); - } ///////////////////////////////////////////////////////////////// // logical operators diff --git a/include/safe_base_operations.hpp b/include/safe_base_operations.hpp index 30afb0f..176c9a1 100644 --- a/include/safe_base_operations.hpp +++ b/include/safe_base_operations.hpp @@ -104,6 +104,40 @@ struct common_policies { // These should catch things like U < safe_base<...> and implement them // as safe_base<...> >= U which should be handled above. +///////////////////////////////////////////////////////////////// +// cast + +/* +template +T safe_cast(const U & u) { + + typedef typename base_type::type result_base_type; + + // filter out case were overflow cannot occur + SAFE_NUMERIC_CONSTEXPR const interval r_interval; + SAFE_NUMERIC_CONSTEXPR const interval u_interval( + base_value::min()>, + base_value::max()> + ); + + + = operator*( + interval::type>(), + interval::type>() + ); + + + if(std::numeric_limits::is_unsigned) + if(u < 0) + overflow("casting alters value"); + if(safe_compare::greater_than(u, std::numeric_limits::max())) + overflow("safe range overflow"); + if(safe_compare::less_than(u, std::numeric_limits::min())) + overflow("safe range underflow"); + return static_cast(u); +} +*/ + ///////////////////////////////////////////////////////////////// // addition @@ -137,29 +171,31 @@ inline operator+(const T & t, const U & u){ ); typedef typename base_type::type result_base_type; + typedef typename base_type::type t_base_type; + typedef typename base_type::type u_base_type; // filter out case were overflow cannot occur + // note: subtle trickery. Suppose is safe_range. Then + // std::numeric_limits::min() will be safe_range t_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; + SAFE_NUMERIC_CONSTEXPR const interval u_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; - SAFE_NUMERIC_CONSTEXPR checked_result maxx = checked::add( - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::max()) - ); - - SAFE_NUMERIC_CONSTEXPR checked_result minx = checked::add( - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::min()) - ); - - typedef typename checked_result::exception_type exception_type; + // when we add the temporary intervals above, we'll get a new interva + // with the correct range for the sum ! Same goes for all the operations + // defined below. + SAFE_NUMERIC_CONSTEXPR const interval r_interval + = operator+(t_interval, u_interval); // if no over/under flow possible - if(maxx == exception_type::no_exception - && minx == exception_type::no_exception) - // just do simple addition of base values + if(r_interval.no_exception()) return result_type(base_value(t) + base_value(u)); // otherwise do the addition checking for overflow @@ -207,29 +243,24 @@ inline operator-(const T & t, const U & u){ ); typedef typename base_type::type result_base_type; + typedef typename base_type::type t_base_type; + typedef typename base_type::type u_base_type; // filter out case were overflow cannot occur + SAFE_NUMERIC_CONSTEXPR const interval t_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; + SAFE_NUMERIC_CONSTEXPR const interval u_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; - SAFE_NUMERIC_CONSTEXPR checked_result maxx = checked::subtract( - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::min()) - ); - - SAFE_NUMERIC_CONSTEXPR checked_result minx = checked::subtract( - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()), - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) - ); - - typedef typename checked_result::exception_type exception_type; + SAFE_NUMERIC_CONSTEXPR const interval r_interval + = operator-(t_interval, u_interval); // if no over/under flow possible - if(maxx == exception_type::no_exception - && minx == exception_type::no_exception) - // just do simple subtraction of base values + if(r_interval.no_exception()) return result_type(base_value(t) - base_value(u)); // otherwise do the subtraction checking for overflow @@ -282,12 +313,12 @@ inline operator*(const T & t, const U & u){ // filter out case were overflow cannot occur SAFE_NUMERIC_CONSTEXPR const interval t_interval = { - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR const interval u_interval = { - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR const interval r_interval @@ -348,12 +379,12 @@ inline operator/(const T & t, const U & u){ // filter out case were overflow cannot occur SAFE_NUMERIC_CONSTEXPR const interval t_interval = { - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR const interval u_interval = { - base_value(std::numeric_limits::min()), - base_value(std::numeric_limits::max()) + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR const interval r_interval @@ -376,7 +407,87 @@ inline operator/(const T & t, const U & u){ return static_cast(r); } +///////////////////////////////////////////////////////////////// +// modulus + +template +struct modulus_result { + typedef common_policies P; + typedef typename P::promotion_policy::template modulus_result< + T, + U, + typename P::promotion_policy, + typename P::exception_policy + >::type type; +}; + +template +typename boost::lazy_enable_if< + boost::mpl::or_< + boost::numeric::is_safe, + boost::numeric::is_safe + >, + modulus_result +>::type +inline operator%(const T & t, const U & u){ + // argument dependent lookup should guarentee that we only get here + // only if one of the types is a safe type. Verify this here + typedef modulus_result ar; + typedef typename ar::type result_type; + static_assert( + boost::numeric::is_safe::value, + "Promotion failed to return safe type" + ); + + typedef typename base_type::type result_base_type; + typedef typename base_type::type t_base_type; + typedef typename base_type::type u_base_type; + + // filter out case were overflow cannot occur + SAFE_NUMERIC_CONSTEXPR const interval t_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; + SAFE_NUMERIC_CONSTEXPR const interval u_interval = { + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()) + }; + + SAFE_NUMERIC_CONSTEXPR const interval r_interval + = operator%(t_interval, u_interval); + + // if no over/under flow possible + if(r_interval.no_exception()) + return result_type(base_value(t) % base_value(u)); + + // otherwise do the multiplication checking for overflow + checked_result r = checked::modulus( + base_value(std::numeric_limits::min()), + base_value(std::numeric_limits::max()), + base_value(t), + base_value(u) + ); + + r.template dispatch(); + + return static_cast(r); +} + /* +// modulus +template +typename boost::enable_if< + boost::is_integral, + decltype(T() % Stored()) +>::type +inline operator%(const T & lhs, const safe_base & rhs) { + if(safe_compare::equal(0, rhs)) + throw std::domain_error("Divide by zero"); + return static_cast< + decltype(T() % Stored()) + >(lhs % static_cast(rhs)); +} + // comparison operators template @@ -428,45 +539,6 @@ inline operator<=(const T & lhs, const safe_base & rh return rhs >= lhs; } -// multiplication -template -typename boost::enable_if< - boost::is_integral, - decltype(T() * Stored()) ->::type -inline operator*(const T & lhs, const safe_base & rhs) { - return rhs * lhs; -} - -// division -// special case - possible overflow -template -typename boost::enable_if< - boost::is_integral, - decltype(T() / Stored()) ->::type -inline operator/(const T & lhs, const safe_base & rhs) { - if(safe_compare::equal(0, rhs)) - throw std::domain_error("Divide by zero"); - return static_cast< - decltype(T() / Stored()) - >(lhs / static_cast(rhs)); -} - -// modulus -template -typename boost::enable_if< - boost::is_integral, - decltype(T() % Stored()) ->::type -inline operator%(const T & lhs, const safe_base & rhs) { - if(safe_compare::equal(0, rhs)) - throw std::domain_error("Divide by zero"); - return static_cast< - decltype(T() % Stored()) - >(lhs % static_cast(rhs)); -} - // logical operators template typename boost::enable_if< diff --git a/include/safe_compare.hpp b/include/safe_compare.hpp index 9340981..ff15617 100644 --- a/include/safe_compare.hpp +++ b/include/safe_compare.hpp @@ -14,24 +14,20 @@ #include #include -#include +#include #include -//#include "numeric.hpp" -//#include "concept/numeric.hpp" -//#include "boost/concept/assert.hpp" - namespace boost { namespace numeric { namespace safe_compare { namespace detail { template struct make_unsigned { - typedef typename boost::mpl::if_< + typedef typename boost::mpl::eval_if< typename std::numeric_limits::is_signed, typename std::make_unsigned, typename boost::mpl::identity - >::type::type type; + >::type type; }; // both arguments unsigned or signed template diff --git a/include/safe_integer.hpp b/include/safe_integer.hpp index 55f5fd5..affa4b3 100644 --- a/include/safe_integer.hpp +++ b/include/safe_integer.hpp @@ -66,16 +66,16 @@ struct base_type > { typedef T type; }; -/* template< class T, class P, class E > -SAFE_NUMERIC_CONSTEXPR const T & base_value(const safe & t) { - return static_cast(t); +SAFE_NUMERIC_CONSTEXPR const T & base_value( + const safe & st +) { + return static_cast(st); } -*/ template< class T, diff --git a/test/test_cast.cpp b/test/test_cast.cpp index d1c289f..b62ac34 100644 --- a/test/test_cast.cpp +++ b/test/test_cast.cpp @@ -7,10 +7,6 @@ #include #include // EXIT_SUCCESS -#include -#include -#include -#include #include "../include/safe_cast.hpp" #include "../include/safe_compare.hpp" @@ -53,6 +49,9 @@ bool test_cast(T1 v1, const char *t2_name, const char *t1_name){ return true; // passed test } +#include "test.hpp" +#include "test_values.hpp" + #define TEST_CAST(T1, v) \ rval = rval && test_cast( \ v, \ diff --git a/test/test_compare.cpp b/test/test_compare.cpp index 7c26a3d..f47cc80 100644 --- a/test/test_compare.cpp +++ b/test/test_compare.cpp @@ -37,29 +37,34 @@ bool test_compare_detail( char expected_result ){ print_argument_types(v1, v2); - if('=' == expected_result){ + switch(expected_result){ + case '=': { if(! boost::numeric::safe_compare::equal(v1, v2)) return false; if(boost::numeric::safe_compare::less_than(v1, v2)) return false; if(boost::numeric::safe_compare::greater_than(v1, v2)) return false; + break; } - if('<' == expected_result){ + case '<': { if(! boost::numeric::safe_compare::less_than(v1, v2)) return false; if(boost::numeric::safe_compare::equal(v1, v2)) return false; if(boost::numeric::safe_compare::greater_than(v1, v2)) return false; + break; } - if('>' == expected_result){ + case '>':{ if(! boost::numeric::safe_compare::greater_than(v1, v2)) return false; if(boost::numeric::safe_compare::less_than(v1, v2)) return false; if(boost::numeric::safe_compare::equal(v1, v2)) return false; + break; + } } return true; } diff --git a/test/test_conversion.cpp b/test/test_conversion.cpp index 040456e..0462538 100644 --- a/test/test_conversion.cpp +++ b/test/test_conversion.cpp @@ -7,19 +7,11 @@ // test construction conversions #include -#include // EXIT_SUCCESS - -#include -#include -#include -#include +#include #include "../include/safe_compare.hpp" #include "../include/safe_integer.hpp" -#include "test_types.hpp" -#include "test_values.hpp" - // test conversion to T2 from different literal types template bool test_conversion(T1 v1, const char *t2_name, const char *t1_name){ @@ -39,7 +31,7 @@ bool test_conversion(T1 v1, const char *t2_name, const char *t1_name){ return false; } } - catch(std::range_error e){ + catch(std::exception & e){ if(boost::numeric::safe_compare::equal(t2, v1)){ std::cout << "failed to detect error in construction " @@ -67,7 +59,7 @@ bool test_conversion(T1 v1, const char *t2_name, const char *t1_name){ return false; } } - catch(std::range_error e){ + catch(std::exception & e){ if(boost::numeric::safe_compare::equal(t2, t1)){ std::cout << "failed to detect error in construction " @@ -83,6 +75,15 @@ bool test_conversion(T1 v1, const char *t2_name, const char *t1_name){ return true; // passed test } +#include "test.hpp" +#include "test_types.hpp" +#include "test_values.hpp" + +#include +#include +#include +#include + #define TEST_CONVERSION(T1, v) \ test_conversion( \ v, \ @@ -105,7 +106,6 @@ bool test_conversion(T1 v1, const char *t2_name, const char *t1_name){ type_index \ ) \ /**/ - int main(int argc, char *argv[]){ BOOST_PP_REPEAT( BOOST_PP_ARRAY_SIZE(TYPES), @@ -114,3 +114,4 @@ int main(int argc, char *argv[]){ ) return 0; } + diff --git a/test/test_divide.cpp b/test/test_divide.cpp index 5837984..fe92f9c 100644 --- a/test/test_divide.cpp +++ b/test/test_divide.cpp @@ -5,16 +5,9 @@ // http://www.boost.org/LICENSE_1_0.txt) #include -#include #include "../include/safe_integer.hpp" -// we could have used decltype and auto for C++11 but we've decided -// to use boost/typeof to be compatible with older compilers -#include - -#include "test.hpp" - template bool test_divide( T1 v1, @@ -182,7 +175,6 @@ const char *test_division_result[VALUE_ARRAY_SIZE] = { ) /**/ -#define COUNT sizeof(test_multiplication_result) int main(int argc, char * argv[]){ bool rval = true; TEST_EACH_VALUE_PAIR diff --git a/test/test_modulus.cpp b/test/test_modulus.cpp index 552bd22..916a231 100644 --- a/test/test_modulus.cpp +++ b/test/test_modulus.cpp @@ -9,12 +9,6 @@ #include "../include/safe_integer.hpp" -// we could have used decltype and auto for C++11 but we've decided -// to use boost/typeof to be compatible with older compilers -#include - -#include "test.hpp" - template bool test_modulus( T1 v1, @@ -27,73 +21,83 @@ bool test_modulus( << "testing " << av1 << " % " << av2 << std::endl; + { + boost::numeric::safe t1 = v1; + // presuming native policy + boost::numeric::safe result; - boost::numeric::safe t1 = v1; - BOOST_TYPEOF_TPL(T1() / T2()) result; + try{ + result = t1 % v2; - try{ - result = t1 % v2; - - if(expected_result != '.'){ - //if(expected_result == 'x'){ - std::cout - << "failed to detect error in division " - << std::hex << result << "(" << std::dec << result << ")" - << " ! = "<< av1 << " % " << av2 - << std::endl; - try{ - result = t1 % v2; + static_assert( + boost::numeric::is_safe::value, + "Expression failed to return safe type" + ); + + if(expected_result != '.'){ + std::cout + << "failed to detect error in division " + << std::hex << result << "(" << std::dec << result << ")" + << " ! = "<< av1 << " % " << av2 + << std::endl; + try{ + result = t1 % v2; + } + catch(...){} + return false; + } + } + catch(std::exception & e){ + if(expected_result != 'x'){ + std::cout + << "erroneously detected error in division " + << std::hex << result << "(" << std::dec << result << ")" + << " == "<< av1 << " % " << av2 + << std::endl; + try{ + t1 % v2; + } + catch(...){} + return false; } - catch(...){} - return false; } } - catch(std::range_error){ - if(expected_result != 'x'){ - //if(expected_result == '.'){ - std::cout - << "erroneously detected error in division " - << std::hex << result << "(" << std::dec << result << ")" - << " == "<< av1 << " % " << av2 - << std::endl; - try{ - result = t1 % v2; - } - catch(...){} - return false; - } - } - boost::numeric::safe t2 = v2; - try{ - result = t1 % t2; + { + boost::numeric::safe t1 = v1; + boost::numeric::safe t2 = v2; - if(expected_result != '.'){ - //if(expected_result == 'x'){ - std::cout - << "failed to detect error in division " - << std::hex << result << "(" << std::dec << result << ")" - << " ! = "<< av1 << " % " << av2 - << std::endl; - try{ - result = t1 % t2; + // presuming native policy + boost::numeric::safe result; + + try{ + result = t1 % t2; + + if(expected_result != '.'){ + std::cout + << "failed to detect error in division " + << std::hex << result << "(" << std::dec << result << ")" + << " ! = "<< av1 << " % " << av2 + << std::endl; + try{ + result = t1 % t2; + } + catch(...){} + return false; } - catch(...){} - return false; } - } - catch(std::range_error){ - if(expected_result != 'x'){ - //if(expected_result == '.'){ - std::cout - << "erroneously detected error in division " - << std::hex << result << "(" << std::dec << result << ")" - << " == "<< av1 << " % " << av2 - << std::endl; - try{ - result = t1 % t2; + catch(std::exception & e){ + if(expected_result != 'x'){ + std::cout + << "erroneously detected error in division " + << std::hex << result << "(" << std::dec << result << ")" + << " == "<< av1 << " % " << av2 + << std::endl; + try{ + t1 % t2; + } + catch(...){} + return false; } - catch(...){} - return false; } } return true; @@ -106,44 +110,44 @@ bool test_modulus( // This should be changed for a different architecture or better yet // be dynamically adjusted depending on the indicated architecture -const char *test_multiplication_result[VALUE_ARRAY_SIZE] = { +const char *test_modulus_result[VALUE_ARRAY_SIZE] = { // 0 0 0 0 // 01234567012345670123456701234567 // 01234567890123456789012345678901 /* 0*/ "................................", /* 1*/ "................................", -/* 2*/ "...x...x...x...x................", -/* 3*/ "................................", +/* 2*/ "........................xxxxxxxx", +/* 3*/ "........................xxxxxxxx", /* 4*/ ".................................", /* 5*/ "................................", -/* 6*/ "...x...x...x...x................", -/* 7*/ "................................", +/* 6*/ "........................xxxxxxxx", +/* 7*/ "........................xxxxxxxx", /* 8*/ "................................", /* 9*/ "................................", -/*10*/ "...x...x...x...x................", -/*11*/ "................................", +/*10*/ "..xx..xx..xx............xxxxxxxx", +/*11*/ "........................xxxxxxxx", /*12*/ "................................", /*13*/ "................................", -/*14*/ "...x...x...x...x................", -/*15*/ "................................", +/*14*/ "..xx..xx..xx..xx............xxxx", +/*15*/ "............................xxxx", // 0 0 0 0 // 01234567012345670123456701234567 // 01234567890123456789012345678901 -/*16*/ "..xx..xx..xx..xx................", -/*17*/ "..xx..xx..xx..xx................", -/*18*/ "..xx..xx..xx..xx................", -/*19*/ "..xx..xx..xx..xx................", -/*20*/ "..xx..xx..xx..xx................", -/*21*/ "..xx..xx..xx..xx................", -/*22*/ "..xx..xx..xx..xx................", -/*23*/ "..xx..xx..xx..xx................", +/*16*/ "................................", +/*17*/ "................................", +/*18*/ "................................", +/*19*/ "................................", +/*20*/ "................................", +/*21*/ "................................", +/*22*/ "................................", +/*23*/ "................................", -/*24*/ "..xx..xx..xx..xx................", -/*25*/ "..xx..xx..xx..xx................", -/*26*/ "..xx..xx..xx..xx................", -/*27*/ "..xx..xx..xx..xx................", +/*24*/ "..xx..xx..xx....................", +/*25*/ "..xx..xx..xx....................", +/*26*/ "..xx..xx..xx....................", +/*27*/ "..xx..xx..xx....................", /*28*/ "..xx..xx..xx..xx................", /*29*/ "..xx..xx..xx..xx................", /*30*/ "..xx..xx..xx..xx................", @@ -165,11 +169,11 @@ const char *test_multiplication_result[VALUE_ARRAY_SIZE] = { TEST_IMPL( \ BOOST_PP_ARRAY_ELEM(value_index1, VALUES), \ BOOST_PP_ARRAY_ELEM(value_index2, VALUES), \ - test_multiplication_result[value_index1][value_index2] \ + test_modulus_result[value_index1][value_index2] \ ) /**/ -#define COUNT sizeof(test_multiplication_result) +#define COUNT sizeof(test_modulus_result) int main(int argc, char * argv[]){ bool rval = true; TEST_EACH_VALUE_PAIR diff --git a/test/test_types.hpp b/test/test_types.hpp index 23cd730..47d1c60 100644 --- a/test/test_types.hpp +++ b/test/test_types.hpp @@ -8,15 +8,17 @@ #ifndef test_types_hpp #define test_types_hpp +#include + #define TYPES (8, ( \ - boost::int8_t, \ - boost::uint8_t, \ - boost::int16_t, \ - boost::uint16_t, \ - boost::int32_t, \ - boost::uint32_t, \ - boost::int64_t, \ - boost::uint64_t \ + std::int8_t, \ + std::uint8_t, \ + std::int16_t, \ + std::uint16_t, \ + std::int32_t, \ + std::uint32_t, \ + std::int64_t, \ + std::uint64_t \ )) #endif