#if 0 auto val() { return -0xFFFFFFFF; } #include #include #include #include void val0(){ const boost::safe_numerics::safe x{0}; std::cout << x << std::endl; std::cout << -x << std::endl; auto y = -x; std::cout << y << std::endl; } constexpr boost::safe_numerics::safe val1() { constexpr boost::safe_numerics::safe x = 0xFFFFFFFF; return -x; } constexpr boost::safe_numerics::safe val2() { boost::safe_numerics::safe x = - boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>(); return x; } constexpr boost::safe_numerics::safe val3() { return - boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>(); } int main(){ val0(); std::cout << val1() << std::endl; std::cout << val2() << std::endl; std::cout << val3() << std::endl; return 0; } // test utility #include int main(){ using namespace boost::safe_numerics; using x = unsigned_stored_type<0, 42>; print_type p1; return 0; } // test automatic type promotion #include #include #include #include #include int main(){ using namespace boost::safe_numerics; using ar = automatic::addition_result; static_assert( std::is_same::value, "sum of two 8 bit unsigned integers should fit in on 16 bit unsigned integer" ); return 0; } // test automatic type promotion #include #include #include #include #include #include #include int main(){ using namespace boost::safe_numerics; unsigned char t1 = 1; constexpr const safe_unsigned_literal<42, automatic, default_exception_policy> v2; using result_type = decltype(t1 + v2); static_assert( std::is_same< result_type, safe_unsigned_range<42, 297, automatic, default_exception_policy> >::value, "result type should have a range 42-297" ); return 0; } void f1(){ using namespace boost::safe_numerics; constexpr safe j = 0; constexpr safe k = 3; constexpr safe l = j + k; // compile error } void f2(){ using namespace boost::safe_numerics; constexpr safe j = boost::safe_numerics::safe_signed_literal<0>(); constexpr safe k = boost::safe_numerics::safe_signed_literal<3>(); constexpr safe l = j + k; // compile error } void f3(){ using namespace boost::safe_numerics; constexpr auto j = safe_signed_literal<0, native, loose_trap_policy>(); constexpr auto k = safe_signed_literal<3>(); constexpr const safe l = j + k; } void f4(){ using namespace boost::safe_numerics; safe_signed_literal<0, native, loose_trap_policy> j; safe_signed_literal<3> k; constexpr auto l = safe_signed_literal<3>(); constexpr const safe l2 = j + k; } #include int main(){ return 0; } #include #include #include using pic16_promotion = boost::safe_numerics::cpp< 8, // char 8, // short 8, // int 16, // long 32 // long long >; #include #include #include #include int main(){ using namespace boost::safe_numerics; static_assert( std::is_literal_type>::value, "safe type is a literal type" ); static_assert( std::is_literal_type>::value, "interval type is a literal type" ); static_assert( std::is_literal_type >>::value, "interval of safe types is a literal type" ); static_assert( std::is_literal_type >>::value, "range_value of safe types is a literal type" ); safe x = 42; std::cout << make_range_value(x); return 0; } auto val() { return -0xFFFFFFFF; } #include #include #include #include void val0(){ const boost::safe_numerics::safe x{0}; std::cout << x << std::endl; std::cout << -x << std::endl; auto y = -x; std::cout << y << std::endl; } constexpr boost::safe_numerics::safe val1(){ constexpr boost::safe_numerics::safe x = 0xFFFFFFFF; return -x; } constexpr boost::safe_numerics::safe val2(){ const boost::safe_numerics::safe x = -boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>(); return x; } constexpr boost::safe_numerics::safe val3(){ return - boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>(); } int main(){ val0(); std::cout << val1() << std::endl; std::cout << val2() << std::endl; std::cout << val3() << std::endl; return 0; } #include #include #include #include #include namespace boost { namespace safe_numerics { template constexpr void dispatch(const checked_result & cr){ } template constexpr T base_value(const T & t){ return t; } template struct validate_detail { constexpr static const interval> t_interval{ checked::cast(base_value(std::numeric_limits::min())), checked::cast(base_value(std::numeric_limits::max())) }; constexpr static const interval> r_interval{Min, Max}; /* static_assert( ! static_cast(r_interval.excludes(t_interval)), "ranges don't overlap: can't cast" ); */ struct exception_possible { constexpr static R return_value( const T & t ){ static_assert( ! static_cast(r_interval.includes(t_interval)), "exeption not possible" ); // INT08-C const checked_result r = checked::cast(t); dispatch(r); return base_value(r); } }; struct exception_not_possible { constexpr static R return_value( const T & t ){ static_assert( static_cast(r_interval.includes(t_interval)), "exeption not possible" ); return static_cast(t); } }; static R return_value(const T & t){ return std::conditional< static_cast(r_interval.includes(t_interval)), exception_not_possible, exception_possible >::type::return_value(t); } }; template bool test1(const T & t){ const interval> t_interval{ checked::cast(base_value(std::numeric_limits::min())), checked::cast(base_value(std::numeric_limits::max())) }; const interval> r_interval{Min, Max}; /* static_assert( ! static_cast(r_interval.excludes(t_interval)), "ranges don't overlap: can't cast" ); */ const boost::logic::tribool tb1 = r_interval.includes(t_interval); const bool x1 = tb1; const boost::logic::tribool tb2 = r_interval.excludes(t_interval); const bool x2 = tb2; return x2; } } // safe_numerics } // boost int main(){ unsigned int x1 = boost::safe_numerics::test1< unsigned int, 0, 100, signed char >(-1); bool x2 = boost::safe_numerics::validate_detail< unsigned int, 0, 100, signed char, void >::return_value(-1); return 0; } using uint8_t = unsigned char; enum class safe_numerics_error : uint8_t { success = 0, failure, // result is above representational maximum error_count }; template struct checked_result { const safe_numerics_error m_e; const union { const R m_r; char const * const m_msg; }; constexpr /*explicit*/ checked_result(const R & r) : m_e(safe_numerics_error::success), m_r(r) {} constexpr /*explicit*/ checked_result(const safe_numerics_error & e) : m_e(e), m_msg("") {} }; // integers addition template constexpr inline checked_result operator+( const checked_result & t, const checked_result & u ){ #if 1 // compile fails constexpr const safe_numerics_error x[2][2]{ // t == success { // u == ... safe_numerics_error::success, safe_numerics_error::failure }, // t == positive_overflow_error, { // u == ... safe_numerics_error::success, safe_numerics_error::failure } }; // "Constexpr variable 'e' must be initialized by a constant expression" constexpr const safe_numerics_error e = x [static_cast(t.m_e)] [static_cast(u.m_e)] ; return safe_numerics_error::success == e ? t.m_r + u.m_r : checked_result(e) ; #else // works as expected constexpr const safe_numerics_error x[2][2]{ // t == success { // u == ... safe_numerics_error::success, safe_numerics_error::failure }, // t == failure, { // u == ... safe_numerics_error::failure, safe_numerics_error::failure } }; return safe_numerics_error::success == x [static_cast(t.m_e)] [static_cast(u.m_e)] ? t.m_r + u.m_r : checked_result(x [static_cast(t.m_e)] [static_cast(u.m_e)] ) ; #endif } int main(){ constexpr const checked_result i = 0; constexpr const checked_result j = 0; constexpr const checked_result k = i + j; // return k.m_r; constexpr const checked_result i2 = safe_numerics_error::failure; constexpr const checked_result j2 = 0; constexpr const checked_result k2 = i2 + j2; return k2.m_r; } #endif #if 0 using uint8_t = unsigned char; #if 1 enum class safe_numerics_error : uint8_t { success = 0, failure, // result is above representational maximum error_count }; #else // avoiding enum class fails to solve problem struct safe_numerics_error { const uint8_t m_t; constexpr const static uint8_t success = 0; constexpr const static uint8_t failure = 1; constexpr safe_numerics_error(uint8_t t) : m_t(t) {} constexpr operator uint8_t () const { return m_t; } }; #endif template struct checked_result { const safe_numerics_error m_e; const union { const R m_r; char const * const m_msg; }; constexpr /*explicit*/ checked_result(const R & r) : m_e(safe_numerics_error::success), m_r(r) {} constexpr /*explicit*/ checked_result(const safe_numerics_error & e) : m_e(e), m_msg("") {} }; // integers addition template constexpr inline checked_result operator+( const checked_result & t, const checked_result & u ){ // "Constexpr variable 'e' must be initialized by a constant expression" constexpr const safe_numerics_error x[2][2]{ // t == success { // u == ... safe_numerics_error::success, safe_numerics_error::failure }, // t == positive_overflow_error, { // u == ... safe_numerics_error::failure, safe_numerics_error::failure } }; #if 1 // compile fails const safe_numerics_error e = x [static_cast(t.m_e)] [static_cast(u.m_e)] ; return (safe_numerics_error::success == e) ? t.m_r + u.m_r : checked_result(e) ; #else // works as expected return safe_numerics_error::success == x [static_cast(t.m_e)] [static_cast(u.m_e)] ? t.m_r + u.m_r : checked_result(x [static_cast(t.m_e)] [static_cast(u.m_e)] ) ; #endif } int main(){ constexpr const checked_result i = 0; constexpr const checked_result j = 0; //constexpr const checked_result k = i + j; // return k.m_r; constexpr const checked_result i2 = safe_numerics_error::failure; constexpr const checked_result j2 = 0; constexpr const checked_result k2 = i2 + j2; return 0; } #endif #if 0 //#include "safe_common.hpp> //#include "checked_result.hpp> //#include "checked_default.hpp> #include #include #include // note: Don't reorder these. Code in the file checked_result_operations.hpp // depends upon this order !!! enum class safe_numerics_error : std::uint8_t { success = 0, positive_overflow_error, // result is above representational maximum negative_overflow_error, // result is below representational minimum domain_error, // one operand is out of valid range range_error, // result cannot be produced for this operation precision_overflow_error, // result lost precision underflow_error, // result is too small to be represented 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 }; // checked result is an "extended version" of the type R. That is it's domain is // the domain of R U possible other values which might result from arithmetic // operations. An example of such a value would be safe_error::positive_overflow_error. template struct checked_result { const safe_numerics_error m_e; const union { R m_r; char const * m_msg; }; constexpr /*explicit*/ checked_result(const R & r) : m_e(safe_numerics_error::success), m_r(r) {} constexpr /*explicit*/ checked_result( safe_numerics_error e, const char * msg = "" ) : m_e(e), m_msg(msg) { assert(m_e != safe_numerics_error::success); } constexpr bool exception() const { return m_e != safe_numerics_error::success; } // don't permit construction without initial value; checked_result() = delete; // disallow assignment checked_result & operator=(const checked_result &) = delete; }; // all arithmetic operations of type T are supported on checked_result. // but the results might surprising. For example constexpr signed int test_constexpr( const checked_result & t, const checked_result & u ){ const boost::logic::tribool tb2 = t < u; const signed int x = (tb2) ? 2 : 3; return x; } using namespace boost::safe_numerics; int main() { constexpr const checked_result po = safe_numerics_error::positive_overflow_error; constexpr const checked_result no = safe_numerics_error::negative_overflow_error; constexpr const boost::logic::tribool tb = no < po; const boost::logic::tribool tb1 = no > po; constexpr const checked_result re = safe_numerics_error::range_error; const boost::logic::tribool tb2 = no < re; const checked_result x = no < re ? no : re; static_assert(test_constexpr(no, re) == 3, "test_constexpr(no, re)"); static_assert(tb, "no < po"); signed int result; if(tb) result = 0; else result = 1; std::cout << result; return result; } #endif #if 0 #include #include int main(){ constexpr const boost::tribool tb_t{true}; static_assert(tb_t, "tb_t"); assert(static_cast(tb_t)); constexpr boost::tribool tb_f{false}; static_assert(! tb_f, "tb_f"); assert(! static_cast(tb_f)); return 0; } #endif #if 0 #include #include // include headers to support safe integers #include //#include using promotion_policy = boost::safe_numerics::cpp< 8, // char 8 bits 16, // short 16 bits 16, // int 16 bits 16, // long 32 bits 32 // long long 32 bits >; template struct test { using ResultType = promotion_policy::result_type; //boost::safe_numerics::utility::print_type pt; static_assert( std::is_same::value, "is_same" ); }; test t1; int main(){ return 0; } #endif #if 0 #include #include #include #include // hash template struct safe_hash { size_t operator()(boost::safe_numerics::safe const& t) const { return std::hash()(t); } }; int main(){ auto foo = std::unordered_map< boost::safe_numerics::safe, std::string, safe_hash >{}; foo[boost::safe_numerics::safe(42)] = "hello, world!"; foo[42] = "hello, world!"; } #endif #if 0 #include #include #include #include // hash template struct safe_hash { size_t operator()(boost::safe_numerics::safe const& t) const { return std::hash()(t); } }; int main(){ auto foo = std::unordered_map{}; foo[boost::safe_numerics::safe(42)] = "hello, world!"; } #endif #if 0 #include #include #include using namespace boost::safe_numerics; int main(){ using safe_int = safe< int, automatic, loose_trap_policy >; safe_int i; std::cin >> i; // might throw exception auto j = i * i; // won't ever trap // result type can hold the maximum value of i * i static_assert(is_safe::value, "result is a safe type"); static_assert( std::numeric_limits::max() >= std::numeric_limits::max() * std::numeric_limits::max(), "result can never overflow" ); // always true return 0; } #endif int main(){}