Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:36

0001 #ifndef BOOST_NUMERIC_CPP_HPP
0002 #define BOOST_NUMERIC_CPP_HPP
0003 
0004 //  Copyright (c) 2012 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 // policy which creates results types equal to that of C++ promotions.
0011 // Using the policy will permit the program to build and run in release
0012 // mode which is identical to that in debug mode except for the fact
0013 // that errors aren't trapped. 
0014 
0015 #include <type_traits> // integral constant, remove_cv, conditional
0016 #include <limits>
0017 #include <boost/integer.hpp> // integer type selection
0018 
0019 #include "safe_common.hpp"
0020 #include "checked_result.hpp"
0021 
0022 namespace boost {
0023 namespace safe_numerics {
0024 
0025 // in C++ the following rules govern integer arithmetic
0026 
0027 // This policy is use to emulate another compiler/machine architecture
0028 // For example, a Z80 has 8 bit char, 16 bit short, 16 bit int, 32 bit long.  So one
0029 // would use cpp<8, 16, 16, 32, 32> to test programs destined to run on a Z80
0030 
0031 // Follow section 5 of the standard.
0032 template<
0033     int CharBits,
0034     int ShortBits,
0035     int IntBits,
0036     int LongBits,
0037     int LongLongBits
0038 >
0039 struct cpp {
0040 public:
0041     using local_char_type = typename boost::int_t<CharBits>::exact;
0042     using local_short_type = typename boost::int_t<ShortBits>::exact;
0043     using local_int_type = typename boost::int_t<IntBits>::exact;
0044     using local_long_type = typename boost::int_t<LongBits>::exact;
0045     using local_long_long_type = typename boost::int_t<LongLongBits>::exact;
0046 
0047     template<class T>
0048     using rank =
0049         typename std::conditional<
0050             std::is_same<local_char_type, typename std::make_signed<T>::type>::value,
0051             std::integral_constant<int, 1>,
0052         typename std::conditional<
0053             std::is_same<local_short_type, typename std::make_signed<T>::type>::value,
0054             std::integral_constant<int, 2>,
0055         typename std::conditional<
0056             std::is_same<local_int_type, typename std::make_signed<T>::type>::value,
0057             std::integral_constant<int, 3>,
0058         typename std::conditional<
0059             std::is_same<local_long_type, typename std::make_signed<T>::type>::value,
0060             std::integral_constant<int, 4>,
0061         typename std::conditional<
0062             std::is_same<local_long_long_type, typename std::make_signed<T>::type>::value,
0063             std::integral_constant<int, 5>,
0064             std::integral_constant<int, 6> // catch all - never promote integral
0065         >::type >::type >::type >::type >::type;
0066 
0067     // section 4.5 integral promotions
0068 
0069    // convert smaller of two types to the size of the larger
0070     template<class T, class U>
0071     using higher_ranked_type = typename std::conditional<
0072         (rank<T>::value < rank<U>::value),
0073         U,
0074         T
0075     >::type;
0076 
0077     template<class T, class U>
0078     using copy_sign = typename std::conditional<
0079         std::is_signed<U>::value,
0080         typename std::make_signed<T>::type,
0081         typename std::make_unsigned<T>::type
0082     >::type;
0083 
0084     template<class T>
0085     using integral_promotion = copy_sign<
0086         higher_ranked_type<local_int_type, T>,
0087         T
0088     >;
0089 
0090     // note presumption that T & U don't have he same sign
0091     // if that's not true, these won't work
0092     template<class T, class U>
0093     using select_signed = typename std::conditional<
0094         std::numeric_limits<T>::is_signed,
0095         T,
0096         U
0097     >::type;
0098 
0099     template<class T, class U>
0100     using select_unsigned = typename std::conditional<
0101         std::numeric_limits<T>::is_signed,
0102         U,
0103         T
0104     >::type;
0105 
0106     // section 5 clause 11 - usual arithmetic conversions
0107     template<typename T, typename U>
0108     using usual_arithmetic_conversions =
0109         // clause 0 - if both operands have the same type
0110         typename std::conditional<
0111             std::is_same<T, U>::value,
0112             // no further conversion is needed
0113             T,
0114         // clause 1 - otherwise if both operands have the same sign
0115         typename std::conditional<
0116             std::numeric_limits<T>::is_signed
0117             == std::numeric_limits<U>::is_signed,
0118             // convert to the higher ranked type
0119             higher_ranked_type<T, U>,
0120         // clause 2 - otherwise if the rank of he unsigned type exceeds
0121         // the rank of the of the signed type
0122         typename std::conditional<
0123             rank<select_unsigned<T, U>>::value
0124             >= rank< select_signed<T, U>>::value,
0125             // use unsigned type
0126             select_unsigned<T, U>,
0127         // clause 3 - otherwise if the type of the signed integer type can
0128         // represent all the values of the unsigned type
0129         typename std::conditional<
0130             std::numeric_limits< select_signed<T, U>>::digits >=
0131             std::numeric_limits< select_unsigned<T, U>>::digits,
0132             // use signed type
0133             select_signed<T, U>,
0134         // clause 4 - otherwise use unsigned version of the signed type
0135             std::make_signed< select_signed<T, U>>
0136         >::type >::type >::type
0137     >;
0138 
0139     template<typename T, typename U>
0140     using result_type = typename usual_arithmetic_conversions<
0141         integral_promotion<typename base_type<T>::type>,
0142         integral_promotion<typename base_type<U>::type>
0143     >::type;
0144 public:
0145     template<typename T, typename U>
0146     struct addition_result {
0147        using type = result_type<T, U>;
0148     };
0149     template<typename T, typename U>
0150     struct subtraction_result {
0151        using type = result_type<T, U>;
0152     };
0153     template<typename T, typename U>
0154     struct multiplication_result {
0155        using type = result_type<T, U>;
0156     };
0157     template<typename T, typename U>
0158     struct division_result {
0159        using type = result_type<T, U>;
0160     };
0161     template<typename T, typename U>
0162     struct modulus_result {
0163        using type = result_type<T, U>;
0164     };
0165     // note: comparison_result (<, >, ...) is special.
0166     // The return value is always a bool.  The type returned here is
0167     // the intermediate type applied to make the values comparable.
0168     template<typename T, typename U>
0169     struct comparison_result {
0170         using type = result_type<T, U>;
0171     };
0172     template<typename T, typename U>
0173     struct left_shift_result {
0174        using type = result_type<T, U>;
0175     };
0176     template<typename T, typename U>
0177     struct right_shift_result {
0178        using type = result_type<T, U>;
0179     };
0180     template<typename T, typename U>
0181     struct bitwise_and_result {
0182        using type = result_type<T, U>;
0183     };
0184     template<typename T, typename U>
0185     struct bitwise_or_result {
0186        using type = result_type<T, U>;
0187     };
0188     template<typename T, typename U>
0189     struct bitwise_xor_result {
0190        using type = result_type<T, U>;
0191     };
0192 };
0193 
0194 } // safe_numerics
0195 } // boost
0196 
0197 #endif // BOOST_NUMERIC_cpp_HPP