#ifndef BOOST_NUMERIC_AUTOMATIC_HPP #define BOOST_NUMERIC_AUTOMATIC_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) // policy which creates results types equal to that of C++ promotions. // Using the policy will permit the program to build and run in release // mode which is identical to that in debug mode except for the fact // that errors aren't trapped. #include #include // (u)intmax_t, #include // true_type, false_type #include #include #include #include "safe_common.hpp" #include "interval.hpp" #include "safe_range.hpp" namespace boost { namespace numeric { struct automatic { template using calculate_max_t2 = typename boost::mpl::if_c< std::numeric_limits::is_signed || std::numeric_limits::is_signed, std::intmax_t, std::uintmax_t >::type; // section 4.13 integer conversion rank template using rank = typename boost::mpl::if_c< sizeof(char) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(short) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(int) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(long) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(long long) == sizeof(T), std::integral_constant, void >::type >::type >::type >::type >::type; // note presumption that T & U don't have he same sign // if that's not true, these won't work template using select_signed = typename boost::mpl::if_c< std::numeric_limits::is_signed, T, U >::type; template using select_unsigned = typename boost::mpl::if_c< std::numeric_limits::is_signed, U, T >::type; template using calculate_max_t = typename boost::mpl::if_c< // clause 1 - if both operands have the same sign std::numeric_limits::is_signed == std::numeric_limits::is_signed, // use that sign typename boost::mpl::if_c< std::numeric_limits::is_signed, std::intmax_t, std::uintmax_t >::type, // clause 2 - otherwise if the rank of he unsigned type exceeds // the rank of the of the maximum signed type typename boost::mpl::if_c< (rank< select_unsigned>::value > rank< std::intmax_t >::value), // use unsigned type std::uintmax_t, // clause 3 - otherwise if the type of the signed integer type can // represent all the values of the unsigned type typename boost::mpl::if_c< std::numeric_limits< std::intmax_t >::digits >= std::numeric_limits< select_unsigned >::digits, // use signed type std::intmax_t, // clause 4 - otherwise use unsigned version of the signed type std::uintmax_t >::type >::type >::type; template struct defer_signed_lazily { using type = boost::numeric::safe_signed_range; }; template struct defer_unsigned_lazily { using type = boost::numeric::safe_unsigned_range; }; template using safe_range = typename boost::mpl::if_< std::is_signed, defer_signed_lazily, defer_unsigned_lazily >::type; template struct addition_result { typedef typename base_type::type base_type_t; typedef typename base_type::type base_type_u; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef calculate_max_t max_t; SAFE_NUMERIC_CONSTEXPR static const interval< max_t> r = operator+(t, u); SAFE_NUMERIC_CONSTEXPR static const max_t newmin = r.l.is_valid() ? static_cast(r.l) : std::numeric_limits::min() ; SAFE_NUMERIC_CONSTEXPR static const max_t newmax = r.u.is_valid() ? static_cast(r.u) : std::numeric_limits::max() ; //typedef typename print::type p_max_t; //typedef typename print>::type p_newmin; //typedef typename print>::type p_newmax; static_assert( newmin < newmax, "new minimumum must be less than new maximum" ); static_assert( std::numeric_limits::min() >= 0 || std::is_signed::value, "newmin < 0 and unsigned can't happen" ); typedef typename safe_range< max_t, newmin, newmax, P, E >::type type; /* typedef typename print< typename safe_range< max_t, newmin, newmax, P, E >::type >::type p_safe_range; */ }; template struct subtraction_result { typedef typename base_type::type base_type_t; typedef typename base_type::type base_type_u; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef calculate_max_t max_t; SAFE_NUMERIC_CONSTEXPR static const interval< max_t> r = operator-(t, u); SAFE_NUMERIC_CONSTEXPR static const max_t newmin = r.l.is_valid() ? static_cast(r.l) : std::numeric_limits::min() ; SAFE_NUMERIC_CONSTEXPR static const max_t newmax = r.u.is_valid() ? static_cast(r.u) : std::numeric_limits::max() ; // typedef typename print::type p_max_t; // typedef typename print>::type p_newmin; // typedef typename print>::type p_newmax; static_assert( newmin < newmax, "new minimumum must be less than new maximum" ); static_assert( std::numeric_limits::min() >= 0 || std::is_signed::value, "newmin < 0 and unsigned can't happen" ); typedef typename safe_range< max_t, newmin, newmax, P, E >::type type; }; template struct multiplication_result { typedef typename base_type::type base_type_t; typedef typename base_type::type base_type_u; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef calculate_max_t max_t; SAFE_NUMERIC_CONSTEXPR static const interval< max_t> r = operator*(t, u); SAFE_NUMERIC_CONSTEXPR static const max_t newmin = r.l.is_valid() ? static_cast(r.l) : std::numeric_limits::min() ; SAFE_NUMERIC_CONSTEXPR static const max_t newmax = r.u.is_valid() ? static_cast(r.u) : std::numeric_limits::max() ; // typedef typename print::type p_max_t; // typedef typename print>::type p_newmin; // typedef typename print>::type p_newmax; static_assert( newmin < newmax, "new minimumum must be less than new maximum" ); static_assert( std::numeric_limits::min() >= 0 || std::is_signed::value, "newmin < 0 and unsigned can't happen" ); typedef typename safe_range< max_t, newmin, newmax, P, E >::type type; }; template struct division_result { typedef typename base_type::type t_base_type; typedef typename base_type::type u_base_type; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef decltype(t_base_type() / u_base_type()) r_base_type; SAFE_NUMERIC_CONSTEXPR static const interval r = operator/(t, u); typedef safe_base type; }; template struct modulus_result { typedef typename base_type::type t_base_type; typedef typename base_type::type u_base_type; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef decltype(t_base_type() % u_base_type()) r_base_type; SAFE_NUMERIC_CONSTEXPR static const interval r = operator%(t, u); typedef safe_base type; }; template struct left_shift_result { typedef typename base_type::type t_base_type; typedef typename base_type::type u_base_type; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef decltype(t_base_type() << u_base_type()) r_base_type; SAFE_NUMERIC_CONSTEXPR static const interval r = operator<<(t, u); typedef safe_base type; }; template struct right_shift_result { typedef typename base_type::type t_base_type; typedef typename base_type::type u_base_type; SAFE_NUMERIC_CONSTEXPR static const interval t = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; SAFE_NUMERIC_CONSTEXPR static const interval u = { base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) }; typedef decltype(t_base_type() >> u_base_type()) r_base_type; SAFE_NUMERIC_CONSTEXPR static const interval r = operator>>(t, u); typedef safe_base type; }; }; } // numeric } // boost #endif // BOOST_NUMERIC_AUTOMATIC_HPP