/usr/include/boost/safe_numerics
Edit: /usr/include/boost/safe_numerics/safe_base_operations.hpp (53080B)
#ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
#define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
// 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 // is_base_of, is_same, is_floating_point, conditional
#include // max
#include
#include
#include // lazy_enable_if
#include
#include
#include "checked_integer.hpp"
#include "checked_result.hpp"
#include "safe_base.hpp"
#include "interval.hpp"
#include "utility.hpp"
namespace boost {
namespace safe_numerics {
/////////////////////////////////////////////////////////////////
// validation
template
struct validate_detail {
using r_type = checked_result;
struct exception_possible {
template
constexpr static R return_value(
const T & t
){
// INT08-C
const r_type rx = heterogeneous_checked_operation<
R,
Min,
Max,
typename base_type::type,
dispatch_and_return
>::cast(t);
return rx;
}
};
struct exception_not_possible {
template
constexpr static R return_value(
const T & t
){
return static_cast(base_value(t));
}
};
template
constexpr static R return_value(const T & t){
constexpr const interval t_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
constexpr const interval r_interval{r_type(Min), r_type(Max)};
static_assert(
true != static_cast(r_interval.excludes(t_interval)),
"can't cast from ranges that don't overlap"
);
return std::conditional<
static_cast(r_interval.includes(t_interval)),
exception_not_possible,
exception_possible
>::type::return_value(t);
}
};
template
template
constexpr Stored safe_base::
validated_cast(const T & t) const {
return validate_detail::return_value(t);
}
template
template
constexpr Stored safe_base::
validated_cast(const safe_literal_impl &) const {
constexpr const interval this_interval{};
// if static values don't overlap, the program can never function
static_assert(
this_interval.includes(N),
"safe type cannot be constructed from this value"
);
return static_cast(N);
}
/////////////////////////////////////////////////////////////////
// constructors
template
constexpr /*explicit*/ safe_base::safe_base(
const Stored & rhs,
skip_validation
) :
m_t(rhs)
{}
template
constexpr /*explicit*/ safe_base::safe_base(){
dispatch(
"safe values must be initialized"
);
}
// construct an instance of a safe type
// from an instance of a convertible underlying type.
template
template
constexpr /*explicit*/ safe_base::safe_base(
const T & t,
typename std::enable_if<
is_safe::value,
bool
>::type
) :
m_t(validated_cast(t))
{}
template
template
constexpr /*explicit*/ safe_base::safe_base(
const T & t,
typename std::enable_if<
std::is_integral::value,
bool
>::type
) :
m_t(validated_cast(t))
{}
template
template
constexpr /*explicit*/ safe_base::safe_base(
const std::integral_constant &
) :
m_t(validated_cast(value))
{}
/////////////////////////////////////////////////////////////////
// casting operators
// cast to a builtin type from a safe type
template< class Stored, Stored Min, Stored Max, class P, class E>
template<
class R,
typename std::enable_if<
! boost::safe_numerics::is_safe::value,
int
>::type
>
constexpr safe_base::
operator R () const {
// if static values don't overlap, the program can never function
#if 1
constexpr const interval r_interval;
constexpr const interval this_interval(Min, Max);
static_assert(
! r_interval.excludes(this_interval),
"safe type cannot be constructed with this type"
);
#endif
return validate_detail<
R,
std::numeric_limits::min(),
std::numeric_limits::max(),
E
>::return_value(*this);
}
// cast to the underlying builtin type from a safe type
template
constexpr safe_base::
operator Stored () const {
return m_t;
}
/////////////////////////////////////////////////////////////////
// binary operators
template
struct common_exception_policy {
static_assert(is_safe::value || is_safe::value,
"at least one type must be a safe type"
);
using t_exception_policy = typename get_exception_policy::type;
using u_exception_policy = typename get_exception_policy::type;
static_assert(
std::is_same::value
|| std::is_same::value
|| std::is_same::value,
"if the exception policies are different, one must be void!"
);
static_assert(
! (std::is_same::value
&& std::is_same::value),
"at least one exception policy must not be void"
);
using type =
typename std::conditional<
!std::is_same::value,
u_exception_policy,
typename std::conditional<
!std::is_same::value,
t_exception_policy,
//
void
>::type >::type;
static_assert(
!std::is_same::value,
"exception_policy is void"
);
};
template
struct common_promotion_policy {
static_assert(is_safe::value || is_safe::value,
"at least one type must be a safe type"
);
using t_promotion_policy = typename get_promotion_policy::type;
using u_promotion_policy = typename get_promotion_policy::type;
static_assert(
std::is_same::value
||std::is_same::value
||std::is_same::value,
"if the promotion policies are different, one must be void!"
);
static_assert(
! (std::is_same::value
&& std::is_same::value),
"at least one promotion policy must not be void"
);
using type =
typename std::conditional<
! std::is_same::value,
u_promotion_policy,
typename std::conditional<
! std::is_same::value,
t_promotion_policy,
//
void
>::type >::type;
static_assert(
! std::is_same::value,
"promotion_policy is void"
);
};
// give the resultant base type, figure out what the final result
// type will be. Note we currently need this because we support
// return of only safe integer types. Someday ..., we'll support
// all other safe types including float and user defined ones.
// helper - cast arguments to binary operators to a specified
// result type
template
std::pair
constexpr static casting_helper(const T & t, const U & u){
using r_type = checked_result;
const r_type tx = heterogeneous_checked_operation<
R,
std::numeric_limits::min(),
std::numeric_limits::max(),
typename base_type::type,
dispatch_and_return
>::cast(base_value(t));
const R tr = tx.exception()
? static_cast(t)
: tx.m_r;
const r_type ux = heterogeneous_checked_operation<
R,
std::numeric_limits::min(),
std::numeric_limits::max(),
typename base_type::type,
dispatch_and_return
>::cast(base_value(u));
const R ur = ux.exception()
? static_cast(u)
: ux.m_r;
return std::pair(tr, ur);
}
// Note: the following global operators will be found via
// argument dependent lookup.
/////////////////////////////////////////////////////////////////
// addition
template
struct addition_result {
private:
using promotion_policy = typename common_promotion_policy::type;
using result_base_type =
typename promotion_policy::template addition_result::type;
// if exception not possible
constexpr static result_base_type
return_value(const T & t, const U & u, std::false_type){
return
static_cast(base_value(t))
+ static_cast(base_value(u));
}
// if exception possible
using exception_policy = typename common_exception_policy::type;
using r_type = checked_result;
constexpr static result_base_type
return_value(const T & t, const U & u, std::true_type){
const std::pair r = casting_helper<
exception_policy,
result_base_type
>(t, u);
const r_type rx = checked_operation<
result_base_type,
dispatch_and_return
>::add(r.first, r.second);
return
rx.exception()
? r.first + r.second
: rx.m_r;
}
using r_type_interval_t = interval;
constexpr static const r_type_interval_t get_r_type_interval(){
constexpr const r_type_interval_t t_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
constexpr const r_type_interval_t u_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
return t_interval + u_interval;
}
constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
constexpr static const interval return_interval{
r_type_interval.l.exception()
? std::numeric_limits::min()
: static_cast(r_type_interval.l),
r_type_interval.u.exception()
? std::numeric_limits::max()
: static_cast(r_type_interval.u)
};
constexpr static bool exception_possible(){
if(r_type_interval.l.exception())
return true;
if(r_type_interval.u.exception())
return true;
if(! return_interval.includes(r_type_interval))
return true;
return false;
}
constexpr static auto rl = return_interval.l;
constexpr static auto ru = return_interval.u;
public:
using type =
safe_base<
result_base_type,
rl,
ru,
promotion_policy,
exception_policy
>;
constexpr static type return_value(const T & t, const U & u){
return type(
return_value(
t,
u,
std::integral_constant()
),
typename type::skip_validation()
);
}
};
template
typename boost::lazy_enable_if_c<
is_safe::value || is_safe::value,
addition_result
>::type
constexpr operator+(const T & t, const U & u){
return addition_result::return_value(t, u);
}
template
typename std::enable_if<
is_safe::value || is_safe::value,
T
>::type
constexpr operator+=(T & t, const U & u){
t = static_cast(t + u);
return t;
}
/////////////////////////////////////////////////////////////////
// subtraction
template
struct subtraction_result {
private:
using promotion_policy = typename common_promotion_policy::type;
using result_base_type =
typename promotion_policy::template subtraction_result::type;
// if exception not possible
constexpr static result_base_type
return_value(const T & t, const U & u, std::false_type){
return
static_cast(base_value(t))
- static_cast(base_value(u));
}
// if exception possible
using exception_policy = typename common_exception_policy::type;
using r_type = checked_result;
constexpr static result_base_type
return_value(const T & t, const U & u, std::true_type){
const std::pair r = casting_helper<
exception_policy,
result_base_type
>(t, u);
const r_type rx = checked_operation<
result_base_type,
dispatch_and_return
>::subtract(r.first, r.second);
return
rx.exception()
? r.first + r.second
: rx.m_r;
}
using r_type_interval_t = interval;
constexpr static const r_type_interval_t get_r_type_interval(){
constexpr const r_type_interval_t t_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
constexpr const r_type_interval_t u_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
return t_interval - u_interval;
}
static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
constexpr static const interval return_interval{
r_type_interval.l.exception()
? std::numeric_limits::min()
: static_cast(r_type_interval.l),
r_type_interval.u.exception()
? std::numeric_limits::max()
: static_cast(r_type_interval.u)
};
constexpr static bool exception_possible(){
if(r_type_interval.l.exception())
return true;
if(r_type_interval.u.exception())
return true;
if(! return_interval.includes(r_type_interval))
return true;
return false;
}
public:
constexpr static auto rl = return_interval.l;
constexpr static auto ru = return_interval.u;
using type =
safe_base<
result_base_type,
rl,
ru,
promotion_policy,
exception_policy
>;
constexpr static type return_value(const T & t, const U & u){
return type(
return_value(
t,
u,
std::integral_constant()
),
typename type::skip_validation()
);
}
};
template
typename boost::lazy_enable_if_c<
is_safe::value || is_safe::value,
subtraction_result
>::type
constexpr operator-(const T & t, const U & u){
return subtraction_result::return_value(t, u);
}
template
typename std::enable_if<
is_safe::value || is_safe::value,
T
>::type
constexpr operator-=(T & t, const U & u){
t = static_cast(t - u);
return t;
}
/////////////////////////////////////////////////////////////////
// multiplication
template
struct multiplication_result {
private:
using promotion_policy = typename common_promotion_policy::type;
using result_base_type =
typename promotion_policy::template multiplication_result::type;
// if exception not possible
constexpr static result_base_type
return_value(const T & t, const U & u, std::false_type){
return
static_cast(base_value(t))
* static_cast(base_value(u));
}
// if exception possible
using exception_policy = typename common_exception_policy::type;
using r_type = checked_result;
constexpr static result_base_type
return_value(const T & t, const U & u, std::true_type){
const std::pair r = casting_helper<
exception_policy,
result_base_type
>(t, u);
const r_type rx = checked_operation<
result_base_type,
dispatch_and_return
>::multiply(r.first, r.second);
return
rx.exception()
? r.first * r.second
: rx.m_r;
}
using r_type_interval_t = interval;
constexpr static r_type_interval_t get_r_type_interval(){
constexpr const r_type_interval_t t_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
constexpr const r_type_interval_t u_interval{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
return t_interval * u_interval;
}
static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
constexpr static const interval return_interval{
r_type_interval.l.exception()
? std::numeric_limits::min()
: static_cast(r_type_interval.l),
r_type_interval.u.exception()
? std::numeric_limits::max()
: static_cast(r_type_interval.u)
};
constexpr static bool exception_possible(){
if(r_type_interval.l.exception())
return true;
if(r_type_interval.u.exception())
return true;
if(! return_interval.includes(r_type_interval))
return true;
return false;
}
constexpr static auto rl = return_interval.l;
constexpr static auto ru = return_interval.u;
public:
using type =
safe_base<
result_base_type,
rl,
ru,
promotion_policy,
exception_policy
>;
constexpr static type return_value(const T & t, const U & u){
return type(
return_value(
t,
u,
std::integral_constant()
),
typename type::skip_validation()
);
}
};
template
typename boost::lazy_enable_if_c<
is_safe::value || is_safe::value,
multiplication_result
>::type
constexpr operator*(const T & t, const U & u){
// argument dependent lookup should guarentee that we only get here
return multiplication_result::return_value(t, u);
}
template
typename std::enable_if<
is_safe::value || is_safe::value,
T
>::type
constexpr operator*=(T & t, const U & u){
t = static_cast(t * u);
return t;
}
/////////////////////////////////////////////////////////////////
// division
// key idea here - result will never be larger than T
template
struct division_result {
private:
using promotion_policy = typename common_promotion_policy::type;
using result_base_type =
typename promotion_policy::template division_result::type;
// if exception not possible
constexpr static result_base_type
return_value(const T & t, const U & u, std::false_type){
return
static_cast(base_value(t))
/ static_cast(base_value(u));
}
// if exception possible
using exception_policy = typename common_exception_policy::type;
constexpr static int bits = std::min(
std::numeric_limits::digits,
std::max(std::initializer_list{
std::numeric_limits::digits,
std::numeric_limits::type>::digits,
std::numeric_limits::type>::digits
}) + (std::numeric_limits::is_signed ? 1 : 0)
);
using r_type = checked_result;
constexpr static result_base_type
return_value(const T & t, const U & u, std::true_type){
using temp_base = typename std::conditional<
std::numeric_limits::is_signed,
typename boost::int_t::least,
typename boost::uint_t::least
>::type;
using t_type = checked_result;
const std::pair r = casting_helper<
exception_policy,
temp_base
>(t, u);
const t_type rx = checked_operation<
temp_base,
dispatch_and_return
>::divide(r.first, r.second);
return
rx.exception()
? r.first / r.second
: rx;
}
using r_type_interval_t = interval;
constexpr static r_type_interval_t t_interval(){
return r_type_interval_t{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
};
constexpr static r_type_interval_t u_interval(){
return r_type_interval_t{
checked::cast(base_value(std::numeric_limits::min())),
checked::cast(base_value(std::numeric_limits::max()))
};
};
constexpr static r_type_interval_t get_r_type_interval(){
constexpr const r_type_interval_t t = t_interval();
constexpr const r_type_interval_t u = u_interval();
if(u.u < r_type(0) || u.l > r_type(0))
return t / u;
return utility::minmax(
std::initializer_list {
t.l / u.l,
t.l / r_type(-1),
t.l / r_type(1),
t.l / u.u,
t.u / u.l,
t.u / r_type(-1),
t.u / r_type(1),
t.u / u.u,
}
);
}
static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
constexpr static const interval return_interval{
r_type_interval.l.exception()
? std::numeric_limits::min()
: static_cast(r_type_interval.l),
r_type_interval.u.exception()
? std::numeric_limits::max()
: static_cast(r_type_interval.u)
};
constexpr static bool exception_possible(){
constexpr const r_type_interval_t ri = get_r_type_interval();
constexpr const r_type_interval_t ui = u_interval();
return
static_cast(ui.includes(r_type(0)))
|| ri.l.exception()
|| ri.u.exception();
}
constexpr static auto rl = return_interval.l;
constexpr static auto ru = return_interval.u;
public:
using type =
safe_base<
result_base_type,
rl,
ru,
promotion_policy,
exception_policy
>;
constexpr static type return_value(const T & t, const U & u){
return type(
return_value(
t,
u,
std::integral_constant()
),
typename type::skip_validation()
);
}
};
template
typename boost::lazy_enable_if_c<
is_safe::value || is_safe::value,
division_result
>::type
constexpr operator/(const T & t, const U & u){
return division_result::return_value(t, u);
}
template
typename std::enable_if<
is_safe::value || is_safe::value,
T
>::type
constexpr operator/=(T & t, const U & u){
t = static_cast(t / u);
return t;
}
/////////////////////////////////////////////////////////////////
// modulus
template
struct modulus_result {
private:
using promotion_policy = typename common_promotion_policy::type;
using result_base_type = typename promotion_policy::template modulus_result::type;
// if exception not possible
constexpr static result_base_type
return_value(const T & t, const U & u, std::false_type){
return
static_cast(base_value(t))
% static_cast(base_value(u));
}
// if exception possible
using exception_policy = typename common_exception_policy::type;
constexpr static int bits = std::min(
std::numeric_limits::digits,
std::max(std::initializer_list{
std::numeric_limits::digits,
std::numeric_limits::type>::digits,
std::numeric_limits