diff --git a/include/checked.hpp b/include/checked.hpp index e5bac97..5cf1fa7 100644 --- a/include/checked.hpp +++ b/include/checked.hpp @@ -15,8 +15,9 @@ // contains operations for doing checked aritmetic on NATIVE // C++ types. +#include + #include -//#include //#include #include // make_unsigned @@ -111,7 +112,7 @@ namespace checked { "addition overflow" ) : - checked_result(t + u) + checked_result(static_cast(t) + static_cast(u)) ; } @@ -137,7 +138,7 @@ namespace checked { "addition overflow" ) : - checked_result(t + u) + checked_result(static_cast(t) + static_cast(u)) ; } diff --git a/include/safe_base.hpp b/include/safe_base.hpp index 30a449e..96fcbc4 100644 --- a/include/safe_base.hpp +++ b/include/safe_base.hpp @@ -19,6 +19,9 @@ #include #include +// don't use constexpr so we can debug +#define SAFE_NUMERIC_CONSTEXPR constexpr + #include "safe_compare.hpp" #include "policies.hpp" diff --git a/test/test_add.cpp b/test/test_add.cpp index 0cfca28..232a794 100644 --- a/test/test_add.cpp +++ b/test/test_add.cpp @@ -114,32 +114,34 @@ bool test_add( #include "test.hpp" #include "test_values.hpp" +// note: same test matrix as used in test_checked. Here we test all combinations +// safe and unsafe integers. in test_checked we test all combinations of +// integer primitives + const char *test_addition_result[VALUE_ARRAY_SIZE] = { -// 0 1 2 3 +// 0 0 0 0 // 01234567012345670123456701234567 -// 0 1 2 3 // 01234567890123456789012345678901 /* 0*/ ".........x...x.............x...x", /* 1*/ ".........x...x.............x...x", -/* 2*/ "..........x...x.........x...x...", -/* 3*/ "..........x...x.................", +/* 2*/ "..........x...x.........xxxxxxxx", +/* 3*/ "..........x...x.........xxxxxxxx", /* 4*/ ".........x...x.............x...x", /* 5*/ ".........x...x.............x...x", -/* 6*/ "..........x...x.........x...x...", -/* 7*/ "..........x...x.................", +/* 6*/ "..........x...x.........xxxxxxxx", +/* 7*/ "..........x...x.........xxxxxxxx", /* 8*/ ".........x...x.............x...x", /* 9*/ "xx..xx..xx...x..xxxxxxxx...x...x", -/*10*/ "..xx..xx..xx..x.........xx..x...", -/*11*/ "..........x...x.................", +/*10*/ "..xx..xx..xx..x.........xxxxxxxx", +/*11*/ "..........x...x.........xxxxxxxx", /*12*/ ".............x.................x", /*13*/ "xx..xx..xx..xx..xxxxxxxxxxxx...x", -/*14*/ "..xx..xx..xx..xx............xx..", -/*15*/ "..............x.................", +/*14*/ "..xx..xx..xx..xx............xxxx", +/*15*/ "..............x.............xxxx", -// 0 1 2 3 +// 0 0 0 0 // 01234567012345670123456701234567 -// 0 1 2 3 // 01234567890123456789012345678901 /*16*/ ".........x...x.............x...x", /*17*/ ".........x...x.............x...x", @@ -150,14 +152,14 @@ const char *test_addition_result[VALUE_ARRAY_SIZE] = { /*22*/ ".........x...x.............x...x", /*23*/ ".........x...x.............x...x", -/*24*/ "..x...x...x..x.............x...x", -/*25*/ "..........x..x.............x...x", -/*26*/ ".............x............xx...x", -/*27*/ "xx..xx..xx...x..xxxxxxxxxxxx...x", -/*28*/ "..x...x...x...x................x", -/*29*/ "..............x................x", -/*30*/ "..............................xx", -/*31*/ "xx..xx..xx..xx..xxxxxxxxxxxxxxxx" +/*24*/ "..xx..xx..xx.x.............x...x", +/*25*/ "..xx..xx..xx.x.............x...x", +/*26*/ "..xx..xx..xx.x............xx...x", +/*27*/ "xxxxxxxxxxxx.x..xxxxxxxxxxxx...x", +/*28*/ "..xx..xx..xx..xx...............x", +/*29*/ "..xx..xx..xx..xx...............x", +/*30*/ "..xx..xx..xx..xx..............xx", +/*31*/ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" }; #define TEST_IMPL(v1, v2, result) \ diff --git a/test/test_add.hpp b/test/test_add.hpp deleted file mode 100644 index baba6b1..0000000 --- a/test/test_add.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef TEST_ADD_HPP -#define TEST_ADD_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 -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include // max - -#include "../include/numeric.hpp" -#include "../include/safe_integer.hpp" - -#include "test.hpp" - -template -bool test_add( - T1 v1, - T2 v2, - const char *av1, - const char *av2, - char expected_result -){ - std::cout - << "testing " - << av1 << " + " << av2 - << std::endl; - - typename boost::numeric::addition_result_type::type result; - - try{ - boost::numeric::safe t1 = v1; - result = t1 + v2; - - if(expected_result == 'x'){ - std::cout - << "failed to detect error in addition " - << av1 << " + " << av2 - << std::endl; - result = t1 + v2; - return false; - } - } - catch(std::range_error){ - if(expected_result != 'x'){ - std::cout - << "erroneously detected error in addition " - << av1 << " + " << av2 - << std::endl; - return false; - } - } - - return true; // correct result -} - -#endif // TEST_ADD_HPP diff --git a/test/test_checked.cpp b/test/test_checked.cpp index 25ca3ba..afc1f3d 100644 --- a/test/test_checked.cpp +++ b/test/test_checked.cpp @@ -9,9 +9,6 @@ #include #include -// don't use constexpr so we can debug -#define SAFE_NUMERIC_CONSTEXPR constexpr - #include "../include/checked_result.hpp" #include "../include/checked.hpp" @@ -78,6 +75,10 @@ bool test_add( #include "test.hpp" #include "test_values.hpp" +// note: same test matrix as used in test_add. Here we test all combinations +// safe and unsafe integers. in test_checked we test all combinations of +// integer primitives + const char *test_addition_result[VALUE_ARRAY_SIZE] = { // 0 0 0 0 // 01234567012345670123456701234567 diff --git a/test/test_divide.hpp b/test/test_divide.hpp deleted file mode 100644 index 53a3c13..0000000 --- a/test/test_divide.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef TEST_DIVIDE_HPP -#define TEST_DIVIDE_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 -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include "../include/safe_integer.hpp" -#include "../include/safe_cast.hpp" -#include "../include/safe_compare.hpp" - -#include "test.hpp" - -template -bool test_divide( - V v1, - V v2, - const char *at1, - const char *at2, - const char *av1, - const char *av2 -){ - bool success; - - T1 t1; - try{ - t1 = boost::numeric::safe_cast(v1); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "constructed invalid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - } - else{ - if(! boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - && ! boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "failed to construct valid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - return true; - } - - T2 t2; - try{ - t2 = boost::numeric::safe_cast(v2); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "constructed invalid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(!boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - && !boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "failed to construct valid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - return true; - } - - V result; - try{ - result = t1 / t2; - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(result != v1/v2){ - std::cout - << "failed to detect error in division " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(boost::numeric::safe_compare::greater_than_equal( - boost::numeric::bits::value, - std::max(count_bits(v1),count_bits(v2)) - )){ - std::cout - << "erroneously detected error in division " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - return true; // correct result -} - -template -struct divide_result { - typedef typename boost::mpl::if_< - boost::mpl::or_< - boost::numeric::is_signed, - boost::numeric::is_signed - >, - boost::intmax_t, - boost::uintmax_t - >::type type; -}; - -#define TEST_IMPL(a, b, c, d) \ - rval &= test_divide( \ - (static_cast::type>(a)), \ - (static_cast::type>(b)), \ - BOOST_PP_STRINGIZE(d), \ - BOOST_PP_STRINGIZE(c), \ - BOOST_PP_STRINGIZE(b), \ - BOOST_PP_STRINGIZE(a) \ - ); \ -/**/ - -#endif // TEST_DIVIDE_HPP \ No newline at end of file diff --git a/test/test_modulus.hpp b/test/test_modulus.hpp deleted file mode 100644 index 33715bd..0000000 --- a/test/test_modulus.hpp +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef TEST_MODULUS_HPP -#define TEST_MODULUS_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 -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include "../include/safe_integer.hpp" -#include "../include/safe_cast.hpp" -#include "../include/safe_compare.hpp" - -#include "test.hpp" - -template -bool test_modulus( - V v1, - V v2, - const char *at1, - const char *at2, - const char *av1, - const char *av2 -){ - bool success; - - T1 t1; - try{ - t1 = boost::numeric::safe_cast(v1); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "constructed invalid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - } - else{ - if(! boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - && ! boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "failed to construct valid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - return true; - } - - T2 t2; - try{ - t2 = boost::numeric::safe_cast(v2); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "constructed invalid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(!boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - && !boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "failed to construct valid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - return true; - } - - V result; - try{ - result = t1 % t2; - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(result != v1 % v2){ - std::cout - << "failed to detect error in modulus " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(boost::numeric::safe_compare::greater_than_equal( - boost::numeric::bits::value, - std::max(count_bits(v1),count_bits(v2)) - )){ - std::cout - << "erroneously detected error in modulus " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - return true; // correct result -} - -template -struct modulus_result { - typedef typename boost::mpl::if_< - boost::mpl::or_< - boost::numeric::is_signed, - boost::numeric::is_signed - >, - boost::intmax_t, - boost::uintmax_t - >::type type; -}; - -#define TEST_IMPL(a, b, c, d) \ - rval &= test_modulus( \ - (static_cast::type>(a)), \ - (static_cast::type>(b)), \ - BOOST_PP_STRINGIZE(d), \ - BOOST_PP_STRINGIZE(c), \ - BOOST_PP_STRINGIZE(b), \ - BOOST_PP_STRINGIZE(a) \ - ); \ -/**/ - -#endif // TEST_MODULUS_HPP diff --git a/test/test_multiply.hpp b/test/test_multiply.hpp deleted file mode 100644 index 1c64912..0000000 --- a/test/test_multiply.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef TEST_MULTIPLY_HPP -#define TEST_MULTIPLY_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 -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include - -#include "../include/safe_integer.hpp" -#include "../include/safe_cast.hpp" -#include "../include/safe_compare.hpp" - -#include "test.hpp" - -template -bool test_multiply( - V v1, - V v2, - const char *at1, - const char *at2, - const char *av1, - const char *av2 -){ - bool success; - - T1 t1; - try{ - t1 = boost::numeric::safe_cast(v1); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "constructed invalid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - } - else{ - if(! boost::numeric::safe_compare::greater_than( - v1, - std::numeric_limits::max() - ) - && ! boost::numeric::safe_compare::less_than( - v1, - std::numeric_limits::min() - ) - ){ - std::cout - << "failed to construct valid value " - << at1 << ' ' << av1 - << std::endl; - return false; - } - return true; - } - - T2 t2; - try{ - t2 = boost::numeric::safe_cast(v2); - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - || boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "constructed invalid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(! boost::numeric::safe_compare::greater_than( - v2, - std::numeric_limits::max() - ) - && ! boost::numeric::safe_compare::less_than( - v2, - std::numeric_limits::min() - )){ - std::cout - << "failed to construct valid value " - << at2 << ' ' << av2 - << std::endl; - return false; - } - return true; - } - - V result; - try{ - result = t1 * t2; - success = true; - } - catch(std::range_error){ - success = false; - } - if(success){ - if(result != v1 * v2){ - std::cout - << "failed to detect error in multiplication " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - else{ - if(64 >= count_bits(v1) + count_bits(v2)){ - std::cout - << "erroneously detected error in multiplication " - << at1 << ' ' << at2 << ' ' << av1 << ' ' << av2 - << std::endl; - return false; - } - } - return true; // correct result -} - -template -struct multiply_result { - typedef typename boost::mpl::if_< - boost::mpl::or_< - boost::numeric::is_signed, - boost::numeric::is_signed - >, - boost::intmax_t, - boost::uintmax_t - >::type type; -}; - -#define TEST_IMPL(a, b, c, d) \ - rval &= test_multiply( \ - (static_cast::type>(a)), \ - (static_cast::type>(b)), \ - BOOST_PP_STRINGIZE(d), \ - BOOST_PP_STRINGIZE(c), \ - BOOST_PP_STRINGIZE(b), \ - BOOST_PP_STRINGIZE(a) \ - ); \ -/**/ - -#endif // TEST_MODULUS_HPP diff --git a/test/test_subtract.hpp b/test/test_subtract.hpp deleted file mode 100644 index 59eb077..0000000 --- a/test/test_subtract.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef TEST_SUBTRACT_HPP -#define TEST_SUBTRACT_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 -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include - -#include "../include/safe_integer.hpp" -#include "../include/safe_cast.hpp" -#include "../include/safe_compare.hpp" -#include "../include/numeric.hpp" - -#include "test.hpp" - -template -struct subtract_result { - typedef typename boost::mpl::if_< - boost::mpl::or_< - boost::numeric::is_signed, - boost::numeric::is_signed - >, - boost::intmax_t, - boost::uintmax_t - >::type type; -}; - -template -bool test_subtract( - T1 v1, - T2 v2, - const char *av1, - const char *av2 -){ - typename subtract_result::type result; - try{ - boost::numeric::safe t1 = v1; - - result = t1 - v2; - if(boost::numeric::safe_compare::less_than( - boost::numeric::bits::value, - std::max(count_bits(v1),count_bits(v2)) - )){ - std::cout - << "failed to detect error in subtraction " - << av1 << " - " << av2 - << std::endl; - return false; - } - } - catch(std::range_error){ - if(boost::numeric::safe_compare::greater_than_equal( - boost::numeric::bits::value, - std::max(count_bits(v1),count_bits(v2)) - )){ - std::cout - << "erroneously detected error in subtraction " - << av1 << " - " << av2 - << std::endl; - return false; - } - } - return true; // correct result -} - - -#endif // TEST_SUBTRACT_HPP