#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 "utility.hpp" #include "safe_common.hpp" #include "checked.hpp" 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 { 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; 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; // 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 using result_type = usual_arithmetic_conversions< integral_promotion, integral_promotion >; template struct addition_result { using type = result_type; }; template struct subtraction_result { using type = result_type; }; template struct multiplication_result { using type = result_type; }; template struct division_result { using type = result_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 { using type = result_type; }; // forward to correct modulus implementation template checked_result static constexpr modulus( const T & t, const U & u ){ return checked::modulus(t, u); } template struct left_shift_result { using type = result_type; }; template struct right_shift_result { using type = result_type; }; template struct bitwise_result { using type = result_type; }; }; } // numeric } // boost #endif // BOOST_NUMERIC_cpp_HPP