// Copyright (c) 2012 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 #include #include #include #include #include #include #include template using fptr = T (*)(const T &, const T &); template using fptr_interval = fptr>; template struct op { const fptr m_f; const fptr_interval m_finterval; const char * m_symbol; const bool skip_zeros; }; template< typename T, unsigned int N > bool test_type_operator( const T (&value)[N], const op & opi ){ using namespace boost::safe_numerics; // for each pair of values p1, p2 (100) for(const T & l1 : value) for(const T & u1 : value){ if(l1 > u1) continue; // skip reverse range const interval p1(l1, u1); for(const T & l2 : value) for(const T & u2 : value){ if(l2 > u2) continue; // skip reverse range const interval p2(l2, u2); // maybe skip intervals which include zero if(opi.skip_zeros){ if(l2 == safe_numerics_error::range_error || l2 == safe_numerics_error::domain_error || u2 == safe_numerics_error::range_error || u2 == safe_numerics_error::domain_error || p2.includes(T(0)) ) continue; } // create a new interval from the operation const interval result_interval = opi.m_finterval(p1, p2); std::cout << p1 << opi.m_symbol << p2 << " -> " << result_interval << std::endl; // if resulting interval is null if(result_interval.u < result_interval.l) continue; // for each pair test values for(const T r1 : value) for(const T r2 : value){ // calculate result of operation const T result = opi.m_f(r1, r2); if(result != safe_numerics_error::range_error && result != safe_numerics_error::domain_error ){ // note usage of tribool logic here !!! // includes returns indeterminate the conditional // returns false in both cases and this is what we want. // This is very subtle, don't skim over this. // if both r1 and r2 are within they're respective bounds if(p1.includes(r1) && p2.includes(r2) && ! result_interval.includes(result)){ #if 0 const boost::logic::tribool b1 = p1.includes(r1); const boost::logic::tribool b2 = p2.includes(r2); const boost::logic::tribool b3 = result_interval.includes(result); const interval result_intervalx = opi.m_finterval(p1, p2); const T resultx = opi.m_f(r1, r2); #endif return false; } } } } } return true; } // values // note: need to explicitly specify number of elements to avoid msvc failure template const boost::safe_numerics::checked_result value[8] = { boost::safe_numerics::safe_numerics_error::negative_overflow_error, std::numeric_limits::lowest(), T(-1), T(0), T(1), std::numeric_limits::max(), boost::safe_numerics::safe_numerics_error::positive_overflow_error, boost::safe_numerics::safe_numerics_error::domain_error }; // note: need to explicitly specify number of elements to avoid msvc failure template const boost::safe_numerics::checked_result unsigned_value[6] = { boost::safe_numerics::safe_numerics_error::negative_overflow_error, T(0), T(1), std::numeric_limits::max(), boost::safe_numerics::safe_numerics_error::positive_overflow_error, boost::safe_numerics::safe_numerics_error::domain_error }; // invoke for each type struct test_type { unsigned int m_error_count; test_type() : m_error_count(0) {} template bool operator()(const T &){ using namespace boost::safe_numerics; std::cout << "** testing " << boost::core::demangle(typeid(T).name()) << std::endl; using R = checked_result; // pointers to operands for types T static const std::array, 5> op_table{{ {operator+, operator+, "+", false}, {operator-, operator-, "-", false}, {operator*, operator*, "*", false}, {operator<<, operator<<, "<<", false}, {operator>>, operator>>, ">>", false}, }}; //for(unsigned int i = 0; i < sizeof(op_table)/sizeof(op) / sizeof(fptr); ++i){ for(const op & o : op_table){ if(std::is_signed::value){ if(! test_type_operator(value, o)){ ++m_error_count; return false; } } else{ if(! test_type_operator(unsigned_value, o)){ ++m_error_count; return false; } } } return true; } }; #include #include int main(int, char *[]){ using namespace boost::mp11; // list of signed types using signed_types = mp_list; // list of unsigned types using unsigned_types = mp_list; test_type t; mp_for_each(t); mp_for_each(t); std::cout << (t.m_error_count == 0 ? "success!" : "failure") << std::endl; return t.m_error_count ; }