#ifndef BOOST_NUMERIC_CPP_HPP #define BOOST_NUMERIC_CPP_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 // integral constant, remove_cv #include #include // integer type selection #include #include "safe_common.hpp" #include "checked.hpp" // forward declaration - safe type template< class Stored, Stored Min, Stored Max, class P, // promotion polic class E // exception policy > class safe_base; namespace boost { namespace numeric { // in C++ the following rules govern integer arithmetic // This policy is use to emulate another compiler/machine architecture // For example, a Z80 has 8 bit char, 16 bit short, 16 bit int, 32 bit long. So one // would use cpp<8, 16, 16, 32, 32> to test programs destined to run on a Z80 // Follow section 5 of the standard. template< int CharBits, int ShortBits, int IntBits, int LongBits, int LongLongBits > struct cpp { template using normalize = typename std::make_signed::type>::type; using local_char_type = typename boost::int_t::exact; using local_short_type = typename boost::int_t::exact; using local_int_type = typename boost::int_t::exact; using local_long_type = typename boost::int_t::exact; using local_long_long_type = typename boost::int_t::exact; // section 4.13 integer conversion rank template using rank = typename boost::mpl::if_< std::is_same >, std::integral_constant, typename boost::mpl::if_c< sizeof(local_char_type) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(local_short_type) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(local_int_type) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(local_long_type) == sizeof(T), std::integral_constant, typename boost::mpl::if_c< sizeof(local_long_long_type) == sizeof(T), std::integral_constant, void >::type >::type >::type >::type >::type >::type; // section 4.5 integral promotions template using integral_promotion = typename boost::mpl::if_c< rank::value < rank::value, local_int_type, T >::type; // convert smaller of two types to the size of the larger template using higher_ranked_type = typename boost::mpl::if_c< (rank::value < rank::value), U, T >::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; // section 5 - usual arithmetic conversions template using usual_arithmetic_conversions = // clause 0 - if both operands have the same type typename boost::mpl::if_c< std::is_same::value, // no further conversion is needed T, // clause 1 - otherwise if both operands have the same sign typename boost::mpl::if_c< std::numeric_limits::is_signed == std::numeric_limits::is_signed, // convert to the higher ranked type higher_ranked_type, // clause 2 - otherwise if the rank of he unsigned type exceeds // the rank of the of the signed type typename boost::mpl::if_c< rank< select_unsigned>::value >= rank< select_signed>::value, // use unsigned type select_unsigned, // 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< select_signed >::digits >= std::numeric_limits< select_unsigned >::digits, // use signed type select_signed, // clause 4 - otherwise use unsigned version of the signed type typename std::make_signed< select_signed > >::type >::type >::type >::type; template struct safe_type_promotion { using base_type_t = typename base_type::type; using base_type_u = typename base_type::type; using result_base_type = usual_arithmetic_conversions< integral_promotion, integral_promotion >; using type = safe_base< result_base_type, std::numeric_limits::min(), std::numeric_limits::max(), P, E >; }; template struct addition_result { using type = typename safe_type_promotion::type; }; template struct subtraction_result { typedef typename safe_type_promotion::type type; }; template struct multiplication_result { typedef typename safe_type_promotion::type type; }; template struct division_result { typedef typename safe_type_promotion::type type; }; // forward to correct divide implementation template checked_result static constexpr divide( const T & t, const U & u ){ return checked::divide(t, u); } template struct modulus_result { typedef typename safe_type_promotion::type type; }; template struct left_shift_result { typedef typename safe_type_promotion::type type; }; template struct right_shift_result { typedef typename safe_type_promotion::type type; }; }; } // numeric } // boost #endif // BOOST_NUMERIC_cpp_HPP