mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-27 17:22:13 +00:00
796 lines
24 KiB
C++
796 lines
24 KiB
C++
#ifndef BOOST_NUMERIC_SAFE_RANGE_HPP
|
|
#define BOOST_NUMERIC_SAFE_RANGE_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 <algorithm>
|
|
#include "numeric.hpp"
|
|
#include "safe_compare.hpp"
|
|
#include "safe_cast.hpp"
|
|
#include "overflow.hpp"
|
|
|
|
#include <boost/limits.hpp>
|
|
#include <boost/concept_check.hpp>
|
|
#include <boost/integer.hpp>
|
|
|
|
#include <boost/type_traits/is_convertible.hpp>
|
|
#include <boost/type_traits/is_same.hpp>
|
|
#include <boost/type_traits/is_integral.hpp>
|
|
|
|
#include <boost/utility/enable_if.hpp>
|
|
#include <boost/mpl/min_max.hpp>
|
|
#include <boost/mpl/less_equal.hpp>
|
|
#include <boost/mpl/greater.hpp>
|
|
#include <boost/mpl/integral_c.hpp>
|
|
|
|
#include <ostream>
|
|
#include <istream>
|
|
#include <stdexcept>
|
|
|
|
namespace boost {
|
|
namespace numeric {
|
|
|
|
namespace detail {
|
|
template<bool TS, bool US>
|
|
struct check_addition_overflow{};
|
|
|
|
// both arguments unsigned
|
|
template<>
|
|
struct check_addition_overflow<false, false> {
|
|
template<class T, class U>
|
|
static typename addition_result_type<T, U>::type
|
|
add(const T & t, const U & u){
|
|
typedef typename addition_result_type<T, U>::type result_type;
|
|
result_type tmp;
|
|
tmp = static_cast<result_type>(t) + static_cast<result_type>(u);
|
|
if(safe_compare::less_than(tmp, t))
|
|
overflow("safe range addition out of range");
|
|
return tmp;
|
|
}
|
|
};
|
|
// T unsigned, U signed
|
|
template<>
|
|
struct check_addition_overflow<false, true> {
|
|
template<class T, class U>
|
|
static typename addition_result_type<T, U>::type
|
|
add(const T & t, const U & u){
|
|
if(u > 0)
|
|
return check_addition_overflow<false, false>::add(t, u);
|
|
return t + u;
|
|
}
|
|
};
|
|
// T signed, U unsigned
|
|
template<>
|
|
struct check_addition_overflow<true, false> {
|
|
template<class T, class U>
|
|
static typename addition_result_type<T, U>::type
|
|
add(const T & t, const U & u){
|
|
if(t > 0)
|
|
return check_addition_overflow<false, false>::add(t, u);
|
|
return t + u;
|
|
}
|
|
};
|
|
// both arguments signed
|
|
template<>
|
|
struct check_addition_overflow<true, true> {
|
|
template<class T, class U>
|
|
static typename addition_result_type<T, U>::type
|
|
add(const T & t, const U & u){
|
|
if(t > 0)
|
|
check_addition_overflow<false, true>::add(t, u);
|
|
if(u < 0){
|
|
typedef typename addition_result_type<T, U>::type result_type;
|
|
result_type tmp;
|
|
tmp = static_cast<result_type>(t) + static_cast<result_type>(u);
|
|
if(safe_compare::greater_than(tmp, t))
|
|
overflow("safe range addition out of range");
|
|
return tmp;
|
|
}
|
|
return t + u;
|
|
}
|
|
};
|
|
|
|
template<bool TS, bool US>
|
|
struct check_multiplication_overflow;
|
|
|
|
// both arguments unsigned
|
|
template<>
|
|
struct check_multiplication_overflow<false, false> {
|
|
template<class T, class U>
|
|
static void invoke(const T & t, const U & u){
|
|
char const * const msg = "safe range multiplication out of range";
|
|
typedef boost::uintmax_t accumulator_type;
|
|
const int temp_bits = bits<accumulator_type>::value / 2;
|
|
typedef typename boost::uint_t<temp_bits>::least temp_type;
|
|
|
|
temp_type a = (static_cast<accumulator_type>(t) >> temp_bits);
|
|
temp_type c = (static_cast<accumulator_type>(u) >> temp_bits);
|
|
if(0 != a && 0 != c)
|
|
overflow(msg);
|
|
|
|
temp_type b = static_cast<temp_type>(t);
|
|
if((static_cast<accumulator_type>(b) * static_cast<accumulator_type>(c) >> temp_bits) > 0)
|
|
overflow(msg);
|
|
|
|
temp_type d = static_cast<const temp_type>(u);
|
|
if(0 != (static_cast<accumulator_type>(a) * static_cast<accumulator_type>(d) >> temp_bits))
|
|
overflow(msg);
|
|
}
|
|
};
|
|
// T unsigned, U signed
|
|
template<>
|
|
struct check_multiplication_overflow<false, true> {
|
|
template<class T, class U>
|
|
static void invoke(const T & t, const U & u){
|
|
check_multiplication_overflow<false, false>::invoke(
|
|
t,
|
|
u < 0 ? -u : u
|
|
);
|
|
}
|
|
};
|
|
// T signed, U unsigned
|
|
template<>
|
|
struct check_multiplication_overflow<true, false> {
|
|
template<class T, class U>
|
|
static void invoke(const T & t, const U & u){
|
|
check_multiplication_overflow<false, false>::invoke(
|
|
t < 0 ? -t : t,
|
|
u
|
|
);
|
|
}
|
|
};
|
|
// both arguments signed, signed
|
|
template<>
|
|
struct check_multiplication_overflow<true, true> {
|
|
template<class T, class U>
|
|
static void invoke(const T & t, const U & u){
|
|
check_multiplication_overflow<false, false>::invoke(
|
|
t < 0 ? -t : t,
|
|
u < 0 ? -u : u
|
|
);
|
|
}
|
|
};
|
|
} // detail
|
|
|
|
template<
|
|
class Stored,
|
|
class Derived
|
|
>
|
|
class safe_range_base {
|
|
Derived &
|
|
derived() {
|
|
return static_cast<Derived &>(*this);
|
|
}
|
|
const Derived &
|
|
derived() const {
|
|
return static_cast<const Derived &>(*this);
|
|
}
|
|
template<class T>
|
|
Stored validate(const T & t) const {
|
|
return derived().validate(t);
|
|
}
|
|
Stored m_t;
|
|
protected:
|
|
////////////////////////////////////////////////////////////
|
|
// constructors
|
|
// default constructor
|
|
safe_range_base() {}
|
|
|
|
// copy constructor
|
|
safe_range_base(const safe_range_base & t) :
|
|
m_t(t.m_t)
|
|
{}
|
|
template<class T>
|
|
safe_range_base(const T & t)
|
|
{
|
|
// verify that this is convertible to the storable type
|
|
BOOST_STATIC_ASSERT(( boost::is_convertible<T, Stored>::value ));
|
|
validate(t);
|
|
m_t = static_cast<const Stored &>(t);
|
|
}
|
|
typedef Stored stored_type;
|
|
public:
|
|
template<class T>
|
|
Derived & operator=(const T & rhs){
|
|
m_t = validate(rhs);
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator+=(const T & rhs){
|
|
*this = *this + rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator-=(const T & rhs){
|
|
*this = *this - rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator*=(const T & rhs){
|
|
*this = *this * rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator/=(const T & rhs){
|
|
*this = *this / rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator%=(const T & rhs){
|
|
*this = *this % rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator|=(const T & rhs){
|
|
*this = *this | rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator&=(const T & rhs){
|
|
*this = *this & rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator^=(const T & rhs){
|
|
*this = *this * rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator>>=(const T & rhs){
|
|
*this = *this >> rhs;
|
|
return derived();
|
|
}
|
|
template<class T>
|
|
Derived & operator<<=(const T & rhs){
|
|
*this = *this << rhs;
|
|
return derived();
|
|
}
|
|
Derived operator++(){
|
|
*this = *this + 1;
|
|
return derived();
|
|
}
|
|
Derived operator--(){
|
|
*this = *this - 1;
|
|
return derived();
|
|
}
|
|
Derived operator++(int){
|
|
Derived rvalue = *this;
|
|
m_t = validate(*this + 1);
|
|
return rvalue;
|
|
}
|
|
Derived & operator--(int){
|
|
Derived rvalue = *this;
|
|
m_t = validate(*this - 1);
|
|
return rvalue;
|
|
}
|
|
Derived operator-() const {
|
|
return validate(- m_t);
|
|
}
|
|
Derived operator~() const {
|
|
return validate(~m_t);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// comparison operators
|
|
template<class U>
|
|
bool operator<(const U & rhs) const {
|
|
return safe_compare::less_than(m_t, rhs);
|
|
}
|
|
template<class U>
|
|
bool operator>(const U & rhs) const {
|
|
return safe_compare::greater_than(m_t, rhs);
|
|
}
|
|
template<class U>
|
|
bool operator==(const U & rhs) const {
|
|
return safe_compare::equal(m_t, rhs);
|
|
}
|
|
template<class U>
|
|
bool inline operator!=(const U & rhs) const {
|
|
return ! safe_compare::equal(m_t,rhs);
|
|
}
|
|
template<class U>
|
|
bool inline operator>=(const U & rhs) const {
|
|
return ! safe_compare::less_than(m_t, rhs);
|
|
}
|
|
template<class U>
|
|
bool inline operator<=(const U & rhs) const {
|
|
return ! safe_compare::greater_than(m_t, rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// addition
|
|
// case 1 - no overflow possible
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::less_equal<
|
|
addition_result_bits<Stored, U>,
|
|
// note presumption that size(boost::uintmax) == size(boost::intmax)
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
typename addition_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator+(const U & rhs) const {
|
|
typedef typename addition_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) + static_cast<result_type>(rhs);
|
|
}
|
|
|
|
// case 2 - overflow possible - must be checked at run time
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::greater<
|
|
addition_result_bits<Stored, U>,
|
|
// note presumption that size(boost::uintmax) == size(boost::intmax)
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
typename addition_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator+(const U & rhs) const {
|
|
return detail::check_addition_overflow<
|
|
boost::numeric::is_signed<Stored>::value,
|
|
boost::numeric::is_signed<U>::value
|
|
>::add(m_t, rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// subtraction
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::less_equal<
|
|
subtraction_result_bits<Stored, U>,
|
|
bits<boost::intmax_t>
|
|
>,
|
|
typename subtraction_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator-(const U & rhs) const {
|
|
typedef typename subtraction_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) - static_cast<result_type>(rhs);
|
|
}
|
|
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::greater<
|
|
subtraction_result_bits<Stored, U>,
|
|
bits<boost::intmax_t>
|
|
>,
|
|
typename subtraction_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator-(const U & rhs) const {
|
|
typedef typename subtraction_result_type<Stored, U>::type result_type;
|
|
result_type tmp;
|
|
tmp = static_cast<result_type>(m_t) - static_cast<result_type>(rhs);
|
|
if(tmp > static_cast<result_type>(m_t))
|
|
overflow("safe range subtraction out of range");
|
|
return tmp;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// multiplication
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::less_equal<
|
|
multiply_result_bits<Stored, U>,
|
|
// note presumption that size(boost::uintmax) == size(boost::intmax)
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
typename multiply_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator*(const U & rhs) const {
|
|
typedef typename multiply_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) * static_cast<result_type>(rhs);
|
|
}
|
|
|
|
// implement multiply larger numbers. This is
|
|
// intended to function for all combinations of
|
|
// signed/unsigned types when the product exceeds
|
|
// the maximum integer size
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::greater<
|
|
multiply_result_bits<Stored, U>,
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
boost::uintmax_t
|
|
>::type
|
|
inline operator*(const U & rhs) const {
|
|
detail::check_multiplication_overflow<
|
|
boost::numeric::is_signed<Stored>::value,
|
|
boost::numeric::is_signed<U>::value
|
|
>::invoke(m_t, rhs);
|
|
|
|
return static_cast<boost::uintmax_t>(m_t) * static_cast<boost::uintmax_t>(rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// division
|
|
// simple case - default rules work
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::less_equal<
|
|
division_result_bits<Stored, U>,
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
typename division_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator/(const U & rhs) const {
|
|
if(0 == rhs)
|
|
throw std::domain_error("Divide by zero");
|
|
return safe_cast<typename division_result_type<Stored, U>::type>(m_t / rhs);
|
|
}
|
|
|
|
// special case - possible overflow
|
|
template<class U>
|
|
typename boost::enable_if<
|
|
typename boost::mpl::greater<
|
|
division_result_bits<Stored, U>,
|
|
bits<boost::uintmax_t>
|
|
>,
|
|
typename division_result_type<Stored, U>::type
|
|
>::type
|
|
inline operator/(const U & rhs) const {
|
|
if(0 == rhs)
|
|
throw std::domain_error("Divide by zero");
|
|
return safe_cast<typename division_result_type<Stored, U>::type>(m_t / rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// modulus
|
|
template<class U>
|
|
typename division_result_type<Stored, U>::type
|
|
inline operator%(const U & rhs) const {
|
|
if(0 == rhs)
|
|
throw std::domain_error("Divide by zero");
|
|
return safe_cast<typename division_result_type<Stored, U>::type>(m_t % rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// logical operators
|
|
template<class U>
|
|
typename logical_result_type<Stored, U>::type
|
|
inline operator|(const U & rhs) const {
|
|
typedef typename logical_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) | static_cast<result_type>(rhs);
|
|
}
|
|
template<class U>
|
|
typename logical_result_type<Stored, U>::type
|
|
inline operator&(const U & rhs) const {
|
|
typedef typename logical_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) & static_cast<result_type>(rhs);
|
|
}
|
|
template<class U>
|
|
typename logical_result_type<Stored, U>::type
|
|
inline operator^(const U & rhs) const {
|
|
typedef typename logical_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) ^ static_cast<result_type>(rhs);
|
|
}
|
|
template<class U>
|
|
Stored inline operator>>(const U & rhs) const {
|
|
typedef typename logical_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) >> static_cast<result_type>(rhs);
|
|
}
|
|
template<class U>
|
|
Stored inline operator<<(const U & rhs) const {
|
|
typedef typename logical_result_type<Stored, U>::type result_type;
|
|
return static_cast<result_type>(m_t) << static_cast<result_type>(rhs);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// casting operators for intrinsic integers
|
|
operator stored_type () const {
|
|
return m_t;
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// Note: the following global operators will be only found via
|
|
// argument dependent lookup. So they won't conflict any
|
|
// other global operators for types in namespaces other than
|
|
// boost::numeric
|
|
|
|
// These should catch things like U < safe_range_base<...> and implement them
|
|
// as safe_range_base<...> >= U which should be handled above.
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// binary operators
|
|
|
|
// comparison operators
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
operator<(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs > lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
inline operator>(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs < lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
inline operator==(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs == lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
inline operator!=(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs != rhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
inline operator>=(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs <= lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
bool
|
|
>::type
|
|
inline operator<=(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs >= lhs;
|
|
}
|
|
|
|
// addition
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename addition_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator+(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs + lhs;
|
|
}
|
|
|
|
// subtraction
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename subtraction_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator-(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
typename subtraction_result_type<T, Stored>::type tmp;
|
|
tmp = rhs - lhs;
|
|
return - tmp;
|
|
}
|
|
|
|
// multiplication
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename multiply_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator*(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs * lhs;
|
|
}
|
|
|
|
// division
|
|
// special case - possible overflow
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename division_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator/(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
if(safe_compare::equal(0, rhs))
|
|
throw std::domain_error("Divide by zero");
|
|
return static_cast<
|
|
typename division_result_type<T, Stored>::type
|
|
>(lhs / static_cast<const Stored &>(rhs));
|
|
}
|
|
|
|
// modulus
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename division_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator%(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
if(safe_compare::equal(0, rhs))
|
|
throw std::domain_error("Divide by zero");
|
|
return static_cast<
|
|
typename division_result_type<T, Stored>::type
|
|
>(lhs % static_cast<const Stored &>(rhs));
|
|
}
|
|
|
|
// logical operators
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename multiply_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator|(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs | lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename logical_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator&(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs & lhs;
|
|
}
|
|
template<class T, class Stored, class Derived>
|
|
typename boost::enable_if<
|
|
boost::is_integral<T>,
|
|
typename logical_result_type<T, Stored>::type
|
|
>::type
|
|
inline operator^(const T & lhs, const safe_range_base<Stored, Derived> & rhs) {
|
|
return rhs ^ lhs;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// higher level types implemented in terms of safe_range_base
|
|
|
|
namespace detail {
|
|
template<
|
|
boost::intmax_t MIN,
|
|
boost::intmax_t MAX
|
|
>
|
|
struct signed_stored_type {
|
|
// double check that MIN < MAX
|
|
typedef typename boost::int_t<
|
|
boost::mpl::max<
|
|
typename boost::numeric::detail::log<MIN, 2>,
|
|
typename boost::numeric::detail::log<MAX, 2>
|
|
>::type::value
|
|
>::least type;
|
|
};
|
|
template<
|
|
boost::uintmax_t MIN,
|
|
boost::uintmax_t MAX
|
|
>
|
|
struct unsigned_stored_type {
|
|
// calculate max(abs(MIN, MAX))
|
|
typedef typename boost::uint_t<
|
|
boost::mpl::max<
|
|
typename boost::numeric::detail::ulog<MIN, 2>,
|
|
typename boost::numeric::detail::ulog<MAX, 2>
|
|
>::type::value
|
|
>::least type;
|
|
};
|
|
} // detail
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// safe_signed_range
|
|
|
|
template<
|
|
boost::intmax_t MIN,
|
|
boost::intmax_t MAX
|
|
>
|
|
class safe_signed_range : public
|
|
safe_range_base<
|
|
typename detail::signed_stored_type<MIN, MAX>::type,
|
|
safe_signed_range<MIN, MAX>
|
|
>
|
|
{
|
|
BOOST_STATIC_ASSERT_MSG(
|
|
MIN < MAX,
|
|
"minimum must be less than maximum"
|
|
);
|
|
public:
|
|
typedef typename boost::numeric::safe_range_base<
|
|
typename detail::signed_stored_type<MIN, MAX>::type,
|
|
safe_signed_range<MIN, MAX>
|
|
> base;
|
|
|
|
typedef typename detail::signed_stored_type<MIN, MAX>::type stored_type;
|
|
template<class T>
|
|
stored_type validate(const T & t) const {
|
|
const boost::intmax_t tx = t;
|
|
if(MAX < tx
|
|
|| MIN > tx
|
|
)
|
|
overflow("safe range out of range");
|
|
return static_cast<stored_type>(t);
|
|
}
|
|
safe_signed_range(){}
|
|
|
|
template<class T>
|
|
safe_signed_range(const T & t) :
|
|
base(t)
|
|
{}
|
|
};
|
|
|
|
template<
|
|
boost::intmax_t MIN,
|
|
boost::intmax_t MAX
|
|
>
|
|
std::ostream & operator<<(std::ostream & os, const safe_signed_range<MIN, MAX> & t){
|
|
return os << static_cast<const typename safe_signed_range<MIN, MAX>::stored_type &>(t);
|
|
}
|
|
|
|
template<
|
|
boost::intmax_t MIN,
|
|
boost::intmax_t MAX
|
|
>
|
|
std::istream & operator>>(std::istream & is, safe_signed_range<MIN, MAX> & t){
|
|
typename safe_signed_range<MIN, MAX>::stored_type tx;
|
|
is >> tx;
|
|
t = tx;
|
|
return is;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// safe_unsigned_range
|
|
|
|
template<
|
|
boost::uintmax_t MIN,
|
|
boost::uintmax_t MAX
|
|
>
|
|
class safe_unsigned_range : public
|
|
safe_range_base<
|
|
typename detail::unsigned_stored_type<MIN, MAX>::type,
|
|
safe_unsigned_range<MIN, MAX>
|
|
>
|
|
{
|
|
BOOST_STATIC_ASSERT_MSG(
|
|
MIN < MAX,
|
|
"minimum must be less than maximum"
|
|
);
|
|
public:
|
|
typedef typename boost::numeric::safe_range_base<
|
|
typename detail::unsigned_stored_type<MIN, MAX>::type,
|
|
safe_unsigned_range<MIN, MAX>
|
|
> base;
|
|
typedef typename detail::unsigned_stored_type<MIN, MAX>::type stored_type;
|
|
template<class T>
|
|
stored_type validate(const T & t) const {
|
|
const boost::uintmax_t tx = t;
|
|
if(MAX < tx
|
|
|| MIN > tx
|
|
)
|
|
overflow("safe range out of range");
|
|
return static_cast<stored_type>(t);
|
|
}
|
|
safe_unsigned_range(){}
|
|
|
|
template<class T>
|
|
safe_unsigned_range(const T & t) :
|
|
base(t)
|
|
{}
|
|
};
|
|
|
|
template<
|
|
boost::uintmax_t MIN,
|
|
boost::uintmax_t MAX
|
|
>
|
|
std::ostream & operator<<(std::ostream & os, const safe_unsigned_range<MIN, MAX> & t){
|
|
return os << static_cast<const typename safe_unsigned_range<MIN, MAX>::stored_type &>(t);
|
|
}
|
|
|
|
template<
|
|
boost::uintmax_t MIN,
|
|
boost::uintmax_t MAX
|
|
>
|
|
std::istream & operator>>(std::istream & is, safe_unsigned_range<MIN, MAX> & t){
|
|
typename safe_unsigned_range<MIN, MAX>::stored_type tx;
|
|
is >> tx;
|
|
t = tx;
|
|
return is;
|
|
}
|
|
|
|
} // numeric
|
|
} // boost
|
|
|
|
#endif // BOOST_NUMERIC_SAFE_RANGE_HPP
|