mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-09 23:32:37 +00:00
More carefully defined the concepts. That is the concept of the library is now clear: Trap at either compile or runtime integer operations which yield a result which differs from the normal arithmetic result. Pending on this check in: a) only addition is fixed up so far b) uses BOOST_TYPEOF... rather than decltype(... - final decision sill pending. c) comments out some compile time checks which should be re-instated. d) fixed tests so that they actually work!
363 lines
9.7 KiB
C++
363 lines
9.7 KiB
C++
#ifndef BOOST_NUMERIC_NUMERIC_HPP
|
|
#define BOOST_NUMERIC_NUMERIC_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 <boost/config.hpp>
|
|
#include <boost/limits.hpp>
|
|
#include <boost/integer.hpp>
|
|
#include <boost/mpl/integral_c.hpp>
|
|
#include <boost/mpl/plus.hpp>
|
|
#include <boost/mpl/min_max.hpp>
|
|
#include <boost/mpl/or.hpp>
|
|
#include <boost/mpl/if.hpp>
|
|
#include <boost/mpl/eval_if.hpp>
|
|
#include <boost/mpl/identity.hpp>
|
|
|
|
#include "concept/numeric.hpp"
|
|
#include "boost/concept/assert.hpp"
|
|
|
|
namespace boost {
|
|
namespace numeric {
|
|
|
|
namespace detail {
|
|
template<boost::intmax_t MAX, int BASE>
|
|
struct log;
|
|
|
|
template<int BASE>
|
|
struct log<0, BASE> : public
|
|
boost::mpl::integral_c<
|
|
boost::intmax_t ,
|
|
0
|
|
>
|
|
{};
|
|
template<int BASE>
|
|
struct log<-1, BASE> : public
|
|
boost::mpl::integral_c<
|
|
boost::intmax_t ,
|
|
0
|
|
>
|
|
{};
|
|
|
|
template<boost::intmax_t MAX, int BASE>
|
|
struct log : public
|
|
boost::mpl::integral_c<
|
|
boost::intmax_t ,
|
|
(1 + log<MAX / BASE, BASE>::value )
|
|
>
|
|
{};
|
|
|
|
template<boost::uintmax_t MAX, int BASE>
|
|
struct ulog;
|
|
|
|
template<int BASE>
|
|
struct ulog<0, BASE> : public
|
|
boost::mpl::integral_c<
|
|
boost::uintmax_t ,
|
|
0
|
|
>
|
|
{};
|
|
template<boost::uintmax_t MAX, int BASE>
|
|
struct ulog : public
|
|
boost::mpl::integral_c<
|
|
boost::uintmax_t ,
|
|
(1 + ulog<MAX / BASE, BASE>::value)
|
|
>
|
|
{};
|
|
|
|
} //detail
|
|
|
|
template<boost::intmax_t MIN, boost::intmax_t MAX>
|
|
class safe_signed_range;
|
|
template<boost::uintmax_t MIN, boost::uintmax_t MAX>
|
|
class safe_unsigned_range;
|
|
template<class Stored, class Derived>
|
|
class safe_range_base;
|
|
|
|
} // numeric
|
|
} // boost
|
|
|
|
namespace std {
|
|
|
|
template<boost::intmax_t MIN, boost::intmax_t MAX>
|
|
class numeric_limits< boost::numeric::safe_signed_range<MIN, MAX> > : public
|
|
numeric_limits<int>
|
|
{
|
|
typedef boost::numeric::safe_signed_range<MIN, MAX> T;
|
|
public:
|
|
BOOST_STATIC_CONSTEXPR T min() BOOST_NOEXCEPT { return T(MIN); }
|
|
BOOST_STATIC_CONSTEXPR T max() BOOST_NOEXCEPT { return T(MAX); }
|
|
BOOST_STATIC_CONSTEXPR T lowest() BOOST_NOEXCEPT { return T(MIN); }
|
|
|
|
BOOST_STATIC_CONSTANT(int,digits = (boost::numeric::detail::log<MAX, 2>::value)); // in base 2
|
|
BOOST_STATIC_CONSTANT(int,digits10 = (boost::numeric::detail::log<MAX, 10>::value)); // in base 10
|
|
BOOST_STATIC_CONSTANT(int,max_digits10 = digits10);
|
|
};
|
|
|
|
template<boost::uintmax_t MIN, boost::uintmax_t MAX>
|
|
class numeric_limits< boost::numeric::safe_unsigned_range<MIN, MAX> > : public
|
|
numeric_limits<unsigned int>
|
|
{
|
|
typedef boost::numeric::safe_unsigned_range<MIN, MAX> T;
|
|
public:
|
|
BOOST_STATIC_CONSTEXPR T min() BOOST_NOEXCEPT { return T(MIN); }
|
|
BOOST_STATIC_CONSTEXPR T max() BOOST_NOEXCEPT { return T(MAX); }
|
|
BOOST_STATIC_CONSTEXPR T lowest() BOOST_NOEXCEPT { return T(MIN); }
|
|
|
|
BOOST_STATIC_CONSTEXPR int digits = boost::numeric::detail::ulog<MAX, 2>::value; // in base 2
|
|
BOOST_STATIC_CONSTEXPR int digits10 = boost::numeric::detail::ulog<MAX, 10>::value; // in base 10
|
|
BOOST_STATIC_CONSTEXPR int max_digits10 = digits10;
|
|
};
|
|
|
|
template<class Stored, class Derived>
|
|
class numeric_limits< boost::numeric::safe_range_base<Stored, Derived> > : public
|
|
numeric_limits<Stored>
|
|
{};
|
|
|
|
} // std
|
|
|
|
namespace boost {
|
|
namespace numeric {
|
|
|
|
// can't use is_signed type traits as these are defined ONLY for C++
|
|
// primitive types. They are are not (by design) implemented in terms
|
|
// of numeric_limits so they aren't helpful to us. We leave then in the
|
|
// boost/numeric namespace to distinguish them form the "official" type
|
|
// traits !
|
|
template<class T>
|
|
struct is_signed : public
|
|
boost::mpl::integral_c<
|
|
bool,
|
|
std::numeric_limits<T>::is_signed
|
|
>
|
|
{
|
|
BOOST_CONCEPT_ASSERT((Numeric<T>));
|
|
};
|
|
template<class T>
|
|
struct is_unsigned : public
|
|
boost::mpl::integral_c<
|
|
bool,
|
|
! std::numeric_limits<T>::is_signed
|
|
>
|
|
{
|
|
BOOST_CONCEPT_ASSERT((Numeric<T>));
|
|
};
|
|
|
|
// return the number of bits in a type excluding any sign
|
|
template<class T>
|
|
struct digits : public
|
|
boost::mpl::integral_c<int, std::numeric_limits<T>::digits>
|
|
{
|
|
BOOST_CONCEPT_ASSERT((Numeric<T>));
|
|
};
|
|
|
|
// return maximum bits in types T and U
|
|
template<class T, class U>
|
|
struct max_digits : public
|
|
boost::mpl::max<
|
|
digits<T>,
|
|
digits<U>
|
|
>::type
|
|
{};
|
|
|
|
// return the number of bits in a type
|
|
template<class T>
|
|
struct bits : public
|
|
boost::mpl::plus<
|
|
typename boost::mpl::integral_c<int, std::numeric_limits<T>::digits>,
|
|
typename boost::mpl::integral_c<int, std::numeric_limits<T>::is_signed>
|
|
>
|
|
{};
|
|
|
|
// return maximum bits in types T and U
|
|
template<class T, class U>
|
|
struct max_bits : public
|
|
boost::mpl::max<
|
|
bits<T>,
|
|
bits<U>
|
|
>::type
|
|
{};
|
|
|
|
|
|
// return # of bit in the result of an addition of two types
|
|
template<class T, class U>
|
|
struct addition_result_bits : public
|
|
boost::mpl::plus<
|
|
max_digits<T, U>,
|
|
// if either is signed
|
|
typename boost::mpl::eval_if<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
// add one guard bit and one sign bit
|
|
boost::mpl::integral_c<int, 2>,
|
|
// add one guard bit to detect overflow
|
|
boost::mpl::integral_c<int, 1>
|
|
>::type
|
|
>
|
|
{};
|
|
|
|
// return smallest type that can hold the sum of types T and U
|
|
template<class T, class U>
|
|
struct addition_result_type {
|
|
typedef typename boost::mpl::if_<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
typename boost::int_t<
|
|
boost::mpl::min<
|
|
bits<boost::intmax_t>,
|
|
addition_result_bits<T, U>
|
|
>::type::value
|
|
>::least,
|
|
typename boost::uint_t<
|
|
boost::mpl::min<
|
|
bits<boost::uintmax_t>,
|
|
addition_result_bits<T, U>
|
|
>::type::value
|
|
>::least
|
|
>::type type;
|
|
};
|
|
|
|
// return # of bit in the result of an subtraction of two types
|
|
template<class T, class U>
|
|
struct subtraction_result_bits : public
|
|
boost::mpl::plus<
|
|
max_digits<T, U>,
|
|
// add one guard bit and one sign bit
|
|
boost::mpl::integral_c<int, 2>
|
|
>
|
|
{};
|
|
|
|
// return smallest type that can hold the difference of types T and U
|
|
template<class T, class U>
|
|
struct subtraction_result_type {
|
|
typedef typename boost::int_t<
|
|
boost::mpl::min<
|
|
bits<boost::intmax_t>,
|
|
subtraction_result_bits<T, U>
|
|
>::type::value
|
|
>::least type;
|
|
};
|
|
|
|
// return # of bits in the result of an product of two types
|
|
template<class T, class U>
|
|
struct multiply_result_bits : public
|
|
boost::mpl::plus<
|
|
digits<T>,
|
|
digits<U>,
|
|
// if either is signed
|
|
typename boost::mpl::eval_if<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
// add one sign bit
|
|
boost::mpl::integral_c<int, 1>,
|
|
boost::mpl::integral_c<int, 0>
|
|
>::type
|
|
>
|
|
{};
|
|
|
|
// return smallest type that can hold the product of types T and U
|
|
template<class T, class U>
|
|
struct multiply_result_type {
|
|
typedef typename boost::mpl::eval_if<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
typename boost::mpl::identity<
|
|
typename boost::int_t<
|
|
boost::mpl::min<
|
|
bits<boost::intmax_t>,
|
|
multiply_result_bits<T, U>
|
|
>::type::value
|
|
>::least
|
|
>,
|
|
typename boost::mpl::identity<
|
|
typename boost::uint_t<
|
|
boost::mpl::min<
|
|
bits<boost::uintmax_t>,
|
|
multiply_result_bits<T, U>
|
|
>::type::value
|
|
>::least
|
|
>
|
|
>::type type;
|
|
};
|
|
|
|
// return # of bits in the result of an quotient of two types
|
|
template<class T, class U>
|
|
struct division_result_bits : public
|
|
boost::mpl::plus<
|
|
digits<T>,
|
|
// if either is signed
|
|
typename boost::mpl::eval_if<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
// add one sign bit
|
|
boost::mpl::integral_c<int, 1>,
|
|
boost::mpl::integral_c<int, 0>
|
|
>::type
|
|
>
|
|
{};
|
|
|
|
// return smallest type that can hold the quotient of types T and U
|
|
template<class T, class U>
|
|
struct division_result_type {
|
|
typedef typename boost::mpl::if_<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
typename boost::int_t<
|
|
boost::mpl::min<
|
|
bits<boost::intmax_t>,
|
|
division_result_bits<T, U>
|
|
>::type::value
|
|
>::least,
|
|
typename boost::uint_t<
|
|
boost::mpl::min<
|
|
bits<boost::uintmax_t>,
|
|
division_result_bits<T, U>
|
|
>::type::value
|
|
>::least
|
|
>::type type;
|
|
};
|
|
|
|
// return the type which results from usage of one the
|
|
// operators &, |, ^, <<, >>
|
|
template<class T, class U>
|
|
struct logical_result_type {
|
|
typedef typename boost::mpl::if_<
|
|
typename boost::mpl::or_<
|
|
is_signed<T>,
|
|
is_signed<U>
|
|
>,
|
|
typename boost::int_t<
|
|
max_bits<T, U>::value
|
|
>::least,
|
|
typename boost::uint_t<
|
|
max_bits<T, U>::value
|
|
>::least
|
|
>::type type;
|
|
};
|
|
|
|
} // numeric
|
|
} // boost
|
|
|
|
#endif // BOOST_NUMERIC_NUMERIC_HPP
|