safe_numerics/test/test_z.cpp

759 lines
19 KiB
C++

#if 0
auto val()
{
return -0xFFFFFFFF;
}
#include <stdexcept>
#include <iostream>
#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/safe_integer_literal.hpp>
void val0(){
const boost::safe_numerics::safe<unsigned int> 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<unsigned int> val1()
{
constexpr boost::safe_numerics::safe<unsigned int> x = 0xFFFFFFFF;
return -x;
}
constexpr boost::safe_numerics::safe<unsigned int> val2()
{
boost::safe_numerics::safe<unsigned int> x = - boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>();
return x;
}
constexpr boost::safe_numerics::safe<unsigned int> 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 <boost/safe_numerics/utility.hpp>
int main(){
using namespace boost::safe_numerics;
using x = unsigned_stored_type<0, 42>;
print_type<x> p1;
return 0;
}
// test automatic type promotion
#include <boost/safe_numerics/automatic.hpp>
#include <boost/safe_numerics/safe_integer.hpp>
#include <type_traits>
#include <cstdint>
#include <iostream>
int main(){
using namespace boost::safe_numerics;
using ar = automatic::addition_result<std::uint8_t, std::uint8_t>;
static_assert(
std::is_same<ar::type, std::uint16_t>::value,
"sum of two 8 bit unsigned integers should fit in on 16 bit unsigned integer"
);
return 0;
}
// test automatic type promotion
#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/safe_integer_range.hpp>
#include <boost/safe_numerics/safe_integer_literal.hpp>
#include <boost/safe_numerics/automatic.hpp>
#include <type_traits>
#include <cstdint>
#include <iostream>
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<int> j = 0;
constexpr safe<int> k = 3;
constexpr safe<int> l = j + k; // compile error
}
void f2(){
using namespace boost::safe_numerics;
constexpr safe<int> j = boost::safe_numerics::safe_signed_literal<0>();
constexpr safe<int> k = boost::safe_numerics::safe_signed_literal<3>();
constexpr safe<int> 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<int> 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<int> l2 = j + k;
}
#include <boost/safe_numerics/interval.hpp>
int main(){
return 0;
}
#include <boost/safe_numerics/utility.hpp>
#include <boost/safe_numerics/cpp.hpp>
#include <boost/safe_numerics/safe_common.hpp>
using pic16_promotion = boost::safe_numerics::cpp<
8, // char
8, // short
8, // int
16, // long
32 // long long
>;
#include <type_traits>
#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/range_value.hpp>
#include <iostream>
int main(){
using namespace boost::safe_numerics;
static_assert(
std::is_literal_type<safe<int>>::value,
"safe type is a literal type"
);
static_assert(
std::is_literal_type<interval<int>>::value,
"interval type is a literal type"
);
static_assert(
std::is_literal_type<interval<
safe<int>
>>::value,
"interval of safe types is a literal type"
);
static_assert(
std::is_literal_type<range_value<
safe<int>
>>::value,
"range_value of safe types is a literal type"
);
safe<int> x = 42;
std::cout << make_range_value(x);
return 0;
}
auto val()
{
return -0xFFFFFFFF;
}
#include <stdexcept>
#include <iostream>
#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/safe_integer_literal.hpp>
void val0(){
const boost::safe_numerics::safe<unsigned int> 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<unsigned int> val1(){
constexpr boost::safe_numerics::safe<unsigned int> x = 0xFFFFFFFF;
return -x;
}
constexpr boost::safe_numerics::safe<unsigned int> val2(){
const boost::safe_numerics::safe<unsigned int> x
= -boost::safe_numerics::safe_unsigned_literal<0xFFFFFFFF>();
return x;
}
constexpr boost::safe_numerics::safe<unsigned int> 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 <boost/logic/tribool.hpp>
#include <boost/safe_integer/checked_integer.hpp>
#include <boost/safe_integer/checked_result.hpp>
#include <boost/safe_integer/checked_result_operations.hpp>
#include <boost/safe_integer/interval.hpp>
namespace boost {
namespace safe_numerics {
template<class EP, typename R>
constexpr void
dispatch(const checked_result<R> & cr){
}
template<class T>
constexpr T base_value(const T & t){
return t;
}
template<typename R, R Min, R Max, typename T, typename E>
struct validate_detail {
constexpr static const interval<checked_result<R>> t_interval{
checked::cast<R>(base_value(std::numeric_limits<T>::min())),
checked::cast<R>(base_value(std::numeric_limits<T>::max()))
};
constexpr static const interval<checked_result<R>> r_interval{Min, Max};
/*
static_assert(
! static_cast<bool>(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<bool>(r_interval.includes(t_interval)),
"exeption not possible"
);
// INT08-C
const checked_result<R> r = checked::cast<R>(t);
dispatch<E>(r);
return base_value(r);
}
};
struct exception_not_possible {
constexpr static R return_value(
const T & t
){
static_assert(
static_cast<bool>(r_interval.includes(t_interval)),
"exeption not possible"
);
return static_cast<R>(t);
}
};
static R return_value(const T & t){
return std::conditional<
static_cast<bool>(r_interval.includes(t_interval)),
exception_not_possible,
exception_possible
>::type::return_value(t);
}
};
template<typename R, R Min, R Max, typename T>
bool test1(const T & t){
const interval<checked_result<R>> t_interval{
checked::cast<R>(base_value(std::numeric_limits<T>::min())),
checked::cast<R>(base_value(std::numeric_limits<T>::max()))
};
const interval<checked_result<R>> r_interval{Min, Max};
/*
static_assert(
! static_cast<bool>(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<typename R>
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<class T>
constexpr inline checked_result<T> operator+(
const checked_result<T> & t,
const checked_result<T> & 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<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
;
return
safe_numerics_error::success == e
? t.m_r + u.m_r
: checked_result<T>(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<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
? t.m_r + u.m_r
: checked_result<T>(x
[static_cast<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
)
;
#endif
}
int main(){
constexpr const checked_result<unsigned> i = 0;
constexpr const checked_result<unsigned> j = 0;
constexpr const checked_result<unsigned> k = i + j;
// return k.m_r;
constexpr const checked_result<unsigned> i2 = safe_numerics_error::failure;
constexpr const checked_result<unsigned> j2 = 0;
constexpr const checked_result<unsigned> 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<typename R>
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<class T>
constexpr inline checked_result<T> operator+(
const checked_result<T> & t,
const checked_result<T> & 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<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
;
return
(safe_numerics_error::success == e)
? t.m_r + u.m_r
: checked_result<T>(e)
;
#else // works as expected
return
safe_numerics_error::success == x
[static_cast<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
? t.m_r + u.m_r
: checked_result<T>(x
[static_cast<uint8_t>(t.m_e)]
[static_cast<uint8_t>(u.m_e)]
)
;
#endif
}
int main(){
constexpr const checked_result<unsigned> i = 0;
constexpr const checked_result<unsigned> j = 0;
//constexpr const checked_result<unsigned> k = i + j;
// return k.m_r;
constexpr const checked_result<unsigned> i2 = safe_numerics_error::failure;
constexpr const checked_result<unsigned> j2 = 0;
constexpr const checked_result<unsigned> k2 = i2 + j2;
return 0;
}
#endif
#if 0
//#include "safe_common.hpp>
//#include "checked_result.hpp>
//#include "checked_default.hpp>
#include <cassert>
#include <boost/logic/tribool.hpp>
#include <iostream>
// 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<typename R>
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<T>.
// but the results might surprising. For example
constexpr signed int test_constexpr(
const checked_result<signed int> & t,
const checked_result<signed int> & 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<signed int> po = safe_numerics_error::positive_overflow_error;
constexpr const checked_result<signed int> 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<signed int> re = safe_numerics_error::range_error;
const boost::logic::tribool tb2 = no < re;
const checked_result<signed int> 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 <boost/logic/tribool.hpp>
#include <cassert>
int main(){
constexpr const boost::tribool tb_t{true};
static_assert(tb_t, "tb_t");
assert(static_cast<bool>(tb_t));
constexpr boost::tribool tb_f{false};
static_assert(! tb_f, "tb_f");
assert(! static_cast<bool>(tb_f));
return 0;
}
#endif
#if 0
#include <boost/integer.hpp>
#include <boost/safe_numerics/utility.hpp>
// include headers to support safe integers
#include <boost/safe_numerics/cpp.hpp>
//#include <boost/safe_numerics/exception.hpp>
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<typename R, typename T, typename U>
struct test {
using ResultType = promotion_policy::result_type<T,U>;
//boost::safe_numerics::utility::print_type<ResultType> pt;
static_assert(
std::is_same<R, ResultType>::value,
"is_same<R, ResultType>"
);
};
test<std::uint16_t, std::uint8_t, std::uint8_t> t1;
int main(){
return 0;
}
#endif
#if 0
#include <string>
#include <unordered_map>
#include <boost/safe_numerics/safe_integer.hpp>
#include <functional> // hash
template<typename T>
struct safe_hash {
size_t operator()(boost::safe_numerics::safe<T> const& t) const {
return std::hash<T>()(t);
}
};
int main(){
auto foo = std::unordered_map<
boost::safe_numerics::safe<int>,
std::string,
safe_hash<int>
>{};
foo[boost::safe_numerics::safe<int>(42)] = "hello, world!";
foo[42] = "hello, world!";
}
#endif
#if 0
#include <string>
#include <unordered_map>
#include <boost/safe_numerics/safe_integer.hpp>
#include <functional> // hash
template<typename T>
struct safe_hash {
size_t operator()(boost::safe_numerics::safe<T> const& t) const {
return std::hash<T>()(t);
}
};
int main(){
auto foo = std::unordered_map<int, std::string>{};
foo[boost::safe_numerics::safe<int>(42)] = "hello, world!";
}
#endif
#if 0
#include <iostream>
#include <boost/safe_numerics/safe_integer.hpp>
#include <boost/safe_numerics/automatic.hpp>
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<decltype(j)>::value, "result is a safe type");
static_assert(
std::numeric_limits<decltype(i * i)>::max() >=
std::numeric_limits<safe_int>::max() * std::numeric_limits<safe_int>::max(),
"result can never overflow"
); // always true
return 0;
}
#endif
int main(){}