#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, is_same #include #include "safe_common.hpp" #include "checked_result.hpp" #include "interval.hpp" #include "safe_range.hpp" namespace boost { namespace numeric { struct automatic { // 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 the 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 checked_result> r = add(t, u); SAFE_NUMERIC_CONSTEXPR static const interval< max_t> default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< max_t, result_interval.l, result_interval.u, P, E >::type type; }; /////////////////////////////////////////////////////////////////////// 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 checked_result> r = subtract(t, u); SAFE_NUMERIC_CONSTEXPR static const interval< max_t> default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< max_t, result_interval.l, result_interval.u, 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; // typedef print p_max_t; SAFE_NUMERIC_CONSTEXPR static const checked_result> r {multiply(t, u)}; SAFE_NUMERIC_CONSTEXPR static const interval default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< max_t, result_interval.l, result_interval.u, P, E >::type type; }; /////////////////////////////////////////////////////////////////////// template constexpr static int bits(){ // figure number of bits in quotient return std::min( std::numeric_limits::digits + 1 // one guard bit to cover u == -1 & t = numeric_limits::min() + 1 // one sign bit , std::numeric_limits::digits + 1 // one sign bit ); } template struct division_result { typedef typename base_type::type base_type_t; static_assert( std::is_literal_type< interval >::value, "interval is not literal type" ); typedef typename base_type::type base_type_u; static_assert( std::is_literal_type< interval >::value, "interval is not tliteral type" ); constexpr static interval t { interval( base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) ) }; constexpr static interval u { interval( base_value(std::numeric_limits::min()), base_value(std::numeric_limits::max()) ) }; using base_type_r = typename boost::mpl::if_c< std::numeric_limits::is_signed || std::numeric_limits::is_signed, std::intmax_t, std::uintmax_t >::type; SAFE_NUMERIC_CONSTEXPR static checked_result> r { divide_nz(t, u) }; SAFE_NUMERIC_CONSTEXPR static const interval default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval { r.no_exception() ? static_cast>(r) : default_interval }; typedef typename safe_range< base_type_r, result_interval.l, result_interval.u, P, E >::type type; }; // forward to correct divide implementation template checked_result static SAFE_NUMERIC_CONSTEXPR divide( const T & t, const U & u ){ return checked::divide_automatic(t, u); } /////////////////////////////////////////////////////////////////////// template struct modulus_result { typedef typename base_type::type base_type_t; static_assert( std::is_literal_type< interval >::value, "interval is not literal type" ); typedef typename base_type::type base_type_u; static_assert( std::is_literal_type< interval >::value, "interval is not tliteral 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()) }; using base_type_r = std::make_unsigned_t; SAFE_NUMERIC_CONSTEXPR static const checked_result> r { modulus_nz(t, u) }; SAFE_NUMERIC_CONSTEXPR static const interval default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< base_type_r, result_interval.l, result_interval.u, P, E >::type type; }; // forward to correct modulus implementation template checked_result static SAFE_NUMERIC_CONSTEXPR modulus( const T & t, const U & u ){ return checked::modulus(t, u); } /////////////////////////////////////////////////////////////////////// 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 calculate_max_t max_t; SAFE_NUMERIC_CONSTEXPR static const checked_result> r = left_shift(t, u); SAFE_NUMERIC_CONSTEXPR static const interval< max_t> default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< max_t, result_interval.l, result_interval.u, P, E >::type 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 calculate_max_t max_t; SAFE_NUMERIC_CONSTEXPR static const checked_result> r = right_shift(t, u); SAFE_NUMERIC_CONSTEXPR static const interval< max_t> default_interval{}; SAFE_NUMERIC_CONSTEXPR static const interval result_interval = r.no_exception() ? static_cast>(r) : default_interval ; typedef typename safe_range< max_t, result_interval.l, result_interval.u, P, E >::type type; }; }; } // numeric } // boost #endif // BOOST_NUMERIC_AUTOMATIC_HPP