899e5c1b48
removed last dependency on boost mpl
185 lines
6.1 KiB
C++
185 lines
6.1 KiB
C++
// 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 <iostream>
|
|
#include <limits>
|
|
#include <functional>
|
|
#include <array>
|
|
|
|
#include <boost/core/demangle.hpp>
|
|
#include <boost/safe_numerics/checked_result.hpp>
|
|
#include <boost/safe_numerics/checked_result_operations.hpp>
|
|
#include <boost/safe_numerics/interval.hpp>
|
|
|
|
template<typename T>
|
|
using fptr = T (*)(const T &, const T &);
|
|
template<typename T>
|
|
using fptr_interval = fptr<boost::safe_numerics::interval<T>>;
|
|
|
|
template<typename T>
|
|
struct op {
|
|
const fptr<T> m_f;
|
|
const fptr_interval<T> 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<T> & 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<T> p1(l1, u1);
|
|
for(const T & l2 : value)
|
|
for(const T & u2 : value){
|
|
if(l2 > u2) continue; // skip reverse range
|
|
const interval<T> 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<T> 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<T> 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<typename T>
|
|
const boost::safe_numerics::checked_result<T> value[8] = {
|
|
boost::safe_numerics::safe_numerics_error::negative_overflow_error,
|
|
std::numeric_limits<T>::lowest(),
|
|
T(-1),
|
|
T(0),
|
|
T(1),
|
|
std::numeric_limits<T>::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<typename T>
|
|
const boost::safe_numerics::checked_result<T> unsigned_value[6] = {
|
|
boost::safe_numerics::safe_numerics_error::negative_overflow_error,
|
|
T(0),
|
|
T(1),
|
|
std::numeric_limits<T>::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<typename T>
|
|
bool operator()(const T &){
|
|
using namespace boost::safe_numerics;
|
|
std::cout
|
|
<< "** testing "
|
|
<< boost::core::demangle(typeid(T).name())
|
|
<< std::endl;
|
|
|
|
using R = checked_result<T>;
|
|
// pointers to operands for types T
|
|
static const std::array<op<R>, 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<R>); ++i){
|
|
for(const op<R> & o : op_table){
|
|
if(std::is_signed<T>::value){
|
|
if(! test_type_operator(value<T>, o)){
|
|
++m_error_count;
|
|
return false;
|
|
}
|
|
}
|
|
else{
|
|
if(! test_type_operator(unsigned_value<T>, o)){
|
|
++m_error_count;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
#include <boost/mp11/list.hpp>
|
|
#include <boost/mp11/algorithm.hpp>
|
|
|
|
int main(int, char *[]){
|
|
using namespace boost::mp11;
|
|
// list of signed types
|
|
using signed_types = mp_list<std::int8_t, std::int16_t, std::int32_t, std::int64_t>;
|
|
// list of unsigned types
|
|
using unsigned_types = mp_list<std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>;
|
|
|
|
test_type t;
|
|
mp_for_each<unsigned_types>(t);
|
|
mp_for_each<signed_types>(t);
|
|
|
|
std::cout << (t.m_error_count == 0 ? "success!" : "failure") << std::endl;
|
|
return t.m_error_count ;
|
|
}
|