Files
safe_numerics/include/cpp.hpp
2015-02-22 14:48:30 -08:00

172 lines
5.6 KiB
C++
Executable File

#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.
// note: not currently used and likely not necessary. We're using
// decltype(T() op U()) to determine "usual arithmetic conversions"
#include <boost/integer.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/integer_traits.hpp>
#include "promotion.hpp"
namespace boost {
namespace numeric {
namespace promotion {
// in C++ the following rules govern integer arithmetic
// Follow section 5 of the standard.
template<class T, class U>
struct standard_promotion {
// rank is (more or less) proportional to size of operand
template<class T1>
struct rank {
constexpr int value =
boost::integer_traits<T1>::digits
+ boost::integer_traits<T1>::is_signed
);
};
template<class T1, class U1>
struct higher_ranked_type {
// convert smaller of two types to the size of the larger
typedef typename boost::mpl::if_c<
(rank<T1>::value < rank<U1>::value),
U1,
T1
>::type type;
};
template<class TSigned, class TUnsigned>
struct clause2 {
typedef typename boost::mpl::if_c<
// if the type of the operand with signed integer type can represent all of the values of
// the type of the operand with unsigned integer type,
(boost::integer_traits<TSigned>::digits
>= boost::integer_traits<TUnsigned>::digits),
// the operand with unsigned integer type shall
// be converted to the type of the operand with signed integer type.
TSigned,
// both operands shall be converted to the unsigned integer type corresponding to the
// type of the operand with signed integer type.
TUnsigned
>::type type;
};
template<class TSigned, class TUnsigned>
struct clause1 {
typedef typename boost::mpl::if_c<
// if the operand that has unsigned integer type has rank greater than or equal to
// the rank of the type of the other operand,
rank<TUnsigned>::value >= rank<TSigned>::value,
// the operand with signed integer type shall be
// converted to the type of the operand with unsigned integer type.
TUnsigned,
// otherwise
typename clause2<TSigned, TUnsigned>::type
>::type type;
};
// if both operands have signed integer types or both have unsigned integer types, the
// operand with the type of lesser integer conversion rank shall be converted to the type of the
// operand with greater rank
template<class T1, class U1>
struct clause0 {
typedef typename boost::mpl::if_c<
// if types have the same sign
( boost::integer_traits<T>::is_signed
== boost::integer_traits<U>::is_signed),
// convert the smaller type to the larger
higher_ranked_type<T, U>,
// otherwise consider converting the signed type
typename boost::mpl::if_c<
boost::integer_traits<T>::is_signed,
typename clause1<T, U>::type,
typename clause1<U, T>::type
>::type
>::type type;
};
typedef typename clause0<T, U>::type type;
};
struct cpp {
template<
class T, T TMin, T TMax,
class U, U UMin, U UMax
>
struct add_result {
typedef typename standard_promotion<T, U>::type type;
constexpr bool underflow =
(promotion::sum_underflow<
T,
U,
type,
TMin,
UMin,
(boost::integer_traits<type>::const_min)
>::value)
);
constexpr bool overflow =
(promotion::sum_overflow<
T,
U,
type,
TMax,
UMax,
(boost::integer_traits<type>::const_max)
>::value)
);
constexpr type min = (underflow ?
(boost::integer_traits<type>::const_min)
:
TMin + UMin
));
constexpr type max = (overflow ?
(boost::integer_traits<type>::const_max)
:
TMax + UMax
));
};
template<class T, class U>
struct subtract_result {
typedef typename standard_promotion<T, U>::type type;
};
template<class T, class U>
struct multiply_result {
typedef typename standard_promotion<T, U>::type type;
};
template<class T, class U>
struct divide_result {
typedef typename standard_promotion<T, U>::type type;
};
template<class T, class U>
struct modulus_result {
typedef typename standard_promotion<T, U>::type type;
};
}; // cpp
} // promotion
} // numeric
} // boost
#endif // BOOST_NUMERIC_cpp_HPP