You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
6.6 KiB
197 lines
6.6 KiB
#ifndef BOOST_NUMERIC_CPP_HPP |
|
#define BOOST_NUMERIC_CPP_HPP |
|
|
|
// 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 <type_traits> // integral constant, remove_cv, conditional |
|
#include <limits> |
|
#include <boost/integer.hpp> // integer type selection |
|
|
|
#include "safe_common.hpp" |
|
#include "checked_result.hpp" |
|
|
|
namespace boost { |
|
namespace safe_numerics { |
|
|
|
// 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 { |
|
public: |
|
using local_char_type = typename boost::int_t<CharBits>::exact; |
|
using local_short_type = typename boost::int_t<ShortBits>::exact; |
|
using local_int_type = typename boost::int_t<IntBits>::exact; |
|
using local_long_type = typename boost::int_t<LongBits>::exact; |
|
using local_long_long_type = typename boost::int_t<LongLongBits>::exact; |
|
|
|
template<class T> |
|
using rank = |
|
typename std::conditional< |
|
std::is_same<local_char_type, typename std::make_signed<T>::type>::value, |
|
std::integral_constant<int, 1>, |
|
typename std::conditional< |
|
std::is_same<local_short_type, typename std::make_signed<T>::type>::value, |
|
std::integral_constant<int, 2>, |
|
typename std::conditional< |
|
std::is_same<local_int_type, typename std::make_signed<T>::type>::value, |
|
std::integral_constant<int, 3>, |
|
typename std::conditional< |
|
std::is_same<local_long_type, typename std::make_signed<T>::type>::value, |
|
std::integral_constant<int, 4>, |
|
typename std::conditional< |
|
std::is_same<local_long_long_type, typename std::make_signed<T>::type>::value, |
|
std::integral_constant<int, 5>, |
|
std::integral_constant<int, 6> // catch all - never promote integral |
|
>::type >::type >::type >::type >::type; |
|
|
|
// section 4.5 integral promotions |
|
|
|
// convert smaller of two types to the size of the larger |
|
template<class T, class U> |
|
using higher_ranked_type = typename std::conditional< |
|
(rank<T>::value < rank<U>::value), |
|
U, |
|
T |
|
>::type; |
|
|
|
template<class T, class U> |
|
using copy_sign = typename std::conditional< |
|
std::is_signed<U>::value, |
|
typename std::make_signed<T>::type, |
|
typename std::make_unsigned<T>::type |
|
>::type; |
|
|
|
template<class T> |
|
using integral_promotion = copy_sign< |
|
higher_ranked_type<local_int_type, T>, |
|
T |
|
>; |
|
|
|
// note presumption that T & U don't have he same sign |
|
// if that's not true, these won't work |
|
template<class T, class U> |
|
using select_signed = typename std::conditional< |
|
std::numeric_limits<T>::is_signed, |
|
T, |
|
U |
|
>::type; |
|
|
|
template<class T, class U> |
|
using select_unsigned = typename std::conditional< |
|
std::numeric_limits<T>::is_signed, |
|
U, |
|
T |
|
>::type; |
|
|
|
// section 5 clause 11 - usual arithmetic conversions |
|
template<typename T, typename U> |
|
using usual_arithmetic_conversions = |
|
// clause 0 - if both operands have the same type |
|
typename std::conditional< |
|
std::is_same<T, U>::value, |
|
// no further conversion is needed |
|
T, |
|
// clause 1 - otherwise if both operands have the same sign |
|
typename std::conditional< |
|
std::numeric_limits<T>::is_signed |
|
== std::numeric_limits<U>::is_signed, |
|
// convert to the higher ranked type |
|
higher_ranked_type<T, U>, |
|
// clause 2 - otherwise if the rank of he unsigned type exceeds |
|
// the rank of the of the signed type |
|
typename std::conditional< |
|
rank<select_unsigned<T, U>>::value |
|
>= rank< select_signed<T, U>>::value, |
|
// use unsigned type |
|
select_unsigned<T, U>, |
|
// clause 3 - otherwise if the type of the signed integer type can |
|
// represent all the values of the unsigned type |
|
typename std::conditional< |
|
std::numeric_limits< select_signed<T, U>>::digits >= |
|
std::numeric_limits< select_unsigned<T, U>>::digits, |
|
// use signed type |
|
select_signed<T, U>, |
|
// clause 4 - otherwise use unsigned version of the signed type |
|
std::make_signed< select_signed<T, U>> |
|
>::type >::type >::type |
|
>; |
|
|
|
template<typename T, typename U> |
|
using result_type = typename usual_arithmetic_conversions< |
|
integral_promotion<typename base_type<T>::type>, |
|
integral_promotion<typename base_type<U>::type> |
|
>::type; |
|
public: |
|
template<typename T, typename U> |
|
struct addition_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct subtraction_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct multiplication_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct division_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct modulus_result { |
|
using type = result_type<T, U>; |
|
}; |
|
// note: comparison_result (<, >, ...) is special. |
|
// The return value is always a bool. The type returned here is |
|
// the intermediate type applied to make the values comparable. |
|
template<typename T, typename U> |
|
struct comparison_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct left_shift_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct right_shift_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct bitwise_and_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct bitwise_or_result { |
|
using type = result_type<T, U>; |
|
}; |
|
template<typename T, typename U> |
|
struct bitwise_xor_result { |
|
using type = result_type<T, U>; |
|
}; |
|
}; |
|
|
|
} // safe_numerics |
|
} // boost |
|
|
|
#endif // BOOST_NUMERIC_cpp_HPP
|
|
|