Chris@102: // Boost.Geometry (aka GGL, Generic Geometry Library) Chris@102: Chris@102: // Copyright (c) 2015, Oracle and/or its affiliates. Chris@102: Chris@102: // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle Chris@102: Chris@102: // Licensed under the Boost Software License version 1.0. Chris@102: // http://www.boost.org/users/license.html Chris@102: Chris@102: #ifndef BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP Chris@102: #define BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP Chris@102: Chris@102: // For now deactivate the use of multiprecision integers Chris@102: // TODO: activate it later Chris@102: #define BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER Chris@102: Chris@102: #include Chris@102: #include Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) Chris@102: #include Chris@102: #endif Chris@102: Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: #include Chris@102: Chris@102: Chris@102: namespace boost { namespace geometry Chris@102: { Chris@102: Chris@102: #ifndef DOXYGEN_NO_DETAIL Chris@102: namespace detail { namespace promote_integral Chris@102: { Chris@102: Chris@102: // meta-function that returns the bit size of a type Chris@102: template Chris@102: < Chris@102: typename T, Chris@102: bool IsFundamental = boost::is_fundamental::type::value Chris@102: > Chris@102: struct bit_size Chris@102: {}; Chris@102: Chris@102: Chris@102: // for fundamental types, just return CHAR_BIT * sizeof(T) Chris@102: template Chris@102: struct bit_size Chris@102: : boost::mpl::size_t<(CHAR_BIT * sizeof(T))> Chris@102: {}; Chris@102: Chris@102: Chris@102: #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) Chris@102: // partial specialization for cpp_int Chris@102: template Chris@102: < Chris@102: unsigned MinSize, Chris@102: unsigned MaxSize, Chris@102: boost::multiprecision::cpp_integer_type SignType, Chris@102: boost::multiprecision::cpp_int_check_type Checked, Chris@102: typename Allocator, Chris@102: boost::multiprecision::expression_template_option ExpressionTemplates Chris@102: > Chris@102: struct bit_size Chris@102: < Chris@102: boost::multiprecision::number Chris@102: < Chris@102: boost::multiprecision::cpp_int_backend Chris@102: < Chris@102: MinSize, MaxSize, SignType, Checked, Allocator Chris@102: >, Chris@102: ExpressionTemplates Chris@102: >, Chris@102: false Chris@102: > : boost::mpl::size_t Chris@102: {}; Chris@102: #endif // BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER Chris@102: Chris@102: Chris@102: template Chris@102: < Chris@102: typename T, Chris@102: typename Iterator, Chris@102: typename EndIterator, Chris@102: std::size_t MinSize Chris@102: > Chris@102: struct promote_to_larger Chris@102: { Chris@102: typedef typename boost::mpl::deref::type current_type; Chris@102: Chris@102: typedef typename boost::mpl::if_c Chris@102: < Chris@102: (bit_size::type::value >= MinSize), Chris@102: current_type, Chris@102: typename promote_to_larger Chris@102: < Chris@102: T, Chris@102: typename boost::mpl::next::type, Chris@102: EndIterator, Chris@102: MinSize Chris@102: >::type Chris@102: >::type type; Chris@102: }; Chris@102: Chris@102: // The following specialization is required to finish the loop over Chris@102: // all list elements Chris@102: template Chris@102: struct promote_to_larger Chris@102: { Chris@102: // if promotion fails, keep the number T Chris@102: // (and cross fingers that overflow will not occur) Chris@102: typedef T type; Chris@102: }; Chris@102: Chris@102: }} // namespace detail::promote_integral Chris@102: #endif // DOXYGEN_NO_DETAIL Chris@102: Chris@102: Chris@102: Chris@102: /*! Chris@102: \brief Meta-function to define an integral type with size Chris@102: than is (roughly) twice the bit size of T Chris@102: \ingroup utility Chris@102: \details Chris@102: This meta-function tries to promote the fundamental integral type T Chris@102: to a another integral type with size (roughly) twice the bit size of T. Chris@102: Chris@102: To do this, two times the bit size of T is tested against the bit sizes of: Chris@102: short, int, long, boost::long_long_type, boost::int128_t Chris@102: and the one that first matches is chosen. Chris@102: Chris@102: For unsigned types the bit size of T is tested against the bit Chris@102: sizes of the types above, if T is promoted to a signed type, or Chris@102: the bit sizes of Chris@102: unsigned short, unsigned int, unsigned long, std::size_t, Chris@102: boost::ulong_long_type, boost::uint128_t Chris@102: if T is promoted to an unsigned type. Chris@102: Chris@102: By default an unsigned type is promoted to a signed type. Chris@102: This behavior is controlled by the PromoteUnsignedToUnsigned Chris@102: boolean template parameter, whose default value is "false". Chris@102: To promote an unsigned type to an unsigned type set the value of Chris@102: this template parameter to "true". Chris@102: Chris@102: If the macro BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is not Chris@102: defined, boost's multiprecision integer cpp_int<> is used as a Chris@102: last resort. Chris@102: Chris@102: If BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER is defined and an Chris@102: appropriate type cannot be detected, the input type is returned as is. Chris@102: Chris@102: Finally, if the passed type is either a floating-point type or a Chris@102: user-defined type it is returned as is. Chris@102: Chris@102: \note boost::long_long_type and boost::ulong_long_type are Chris@102: considered only if the macro BOOST_HAS_LONG_LONG is defined Chris@102: Chris@102: \note boost::int128_type and boost::uint128_type are considered Chris@102: only if the macros BOOST_HAS_INT128 and BOOST_GEOMETRY_ENABLE_INT128 Chris@102: are defined Chris@102: */ Chris@102: template Chris@102: < Chris@102: typename T, Chris@102: bool PromoteUnsignedToUnsigned = false, Chris@102: bool UseCheckedInteger = false, Chris@102: bool IsIntegral = boost::is_integral::type::value Chris@102: > Chris@102: class promote_integral Chris@102: { Chris@102: private: Chris@102: static bool const is_unsigned = boost::is_unsigned::type::value; Chris@102: Chris@102: typedef detail::promote_integral::bit_size bit_size_type; Chris@102: Chris@102: #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) Chris@102: // Define the proper check policy for the multiprecision integer Chris@102: typedef typename boost::mpl::if_c Chris@102: < Chris@102: UseCheckedInteger, Chris@102: boost::integral_constant Chris@102: < Chris@102: boost::multiprecision::cpp_int_check_type, Chris@102: boost::multiprecision::checked Chris@102: >, Chris@102: boost::integral_constant Chris@102: < Chris@102: boost::multiprecision::cpp_int_check_type, Chris@102: boost::multiprecision::unchecked Chris@102: > Chris@102: >::type check_policy_type; Chris@102: Chris@102: // Meta-function to get the multiprecision integer type for the Chris@102: // given size and sign type (signed/unsigned) Chris@102: template Chris@102: < Chris@102: unsigned int Size, Chris@102: boost::multiprecision::cpp_integer_type SignType Chris@102: > Chris@102: struct multiprecision_integer_type Chris@102: { Chris@102: typedef boost::multiprecision::number Chris@102: < Chris@102: boost::multiprecision::cpp_int_backend Chris@102: < Chris@102: Size, Chris@102: Size, Chris@102: SignType, Chris@102: check_policy_type::value, Chris@102: void Chris@102: > Chris@102: > type; Chris@102: }; Chris@102: #endif Chris@102: Chris@102: // Define the minimum size (in bits) needed for the promoted type Chris@102: // If T is the input type and P the promoted type, then the Chris@102: // minimum number of bits for P are (below b stands for the number Chris@102: // of bits of T): Chris@102: // * if T is unsigned and P is unsigned: 2 * b Chris@102: // * if T is signed and P is signed: 2 * b - 1 Chris@102: // * if T is unsigned and P is signed: 2 * b + 1 Chris@102: typedef typename boost::mpl::if_c Chris@102: < Chris@102: (PromoteUnsignedToUnsigned && is_unsigned), Chris@102: boost::mpl::size_t<(2 * bit_size_type::value)>, Chris@102: typename boost::mpl::if_c Chris@102: < Chris@102: is_unsigned, Chris@102: boost::mpl::size_t<(2 * bit_size_type::value + 1)>, Chris@102: boost::mpl::size_t<(2 * bit_size_type::value - 1)> Chris@102: >::type Chris@102: >::type min_bit_size_type; Chris@102: Chris@102: // Define the list of signed integral types we are going to use Chris@102: // for promotion Chris@102: typedef boost::mpl::list Chris@102: < Chris@102: short, int, long Chris@102: #if defined(BOOST_HAS_LONG_LONG) Chris@102: , boost::long_long_type Chris@102: #endif Chris@102: #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) Chris@102: , boost::int128_type Chris@102: #endif Chris@102: #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) Chris@102: , typename multiprecision_integer_type Chris@102: < Chris@102: min_bit_size_type::value, Chris@102: boost::multiprecision::signed_magnitude Chris@102: >::type Chris@102: #endif Chris@102: > signed_integral_types; Chris@102: Chris@102: // Define the list of unsigned integral types we are going to use Chris@102: // for promotion Chris@102: typedef boost::mpl::list Chris@102: < Chris@102: unsigned short, unsigned int, unsigned long, std::size_t Chris@102: #if defined(BOOST_HAS_LONG_LONG) Chris@102: , boost::ulong_long_type Chris@102: #endif Chris@102: #if defined(BOOST_HAS_INT128) && defined(BOOST_GEOMETRY_ENABLE_INT128) Chris@102: , boost::uint128_type Chris@102: #endif Chris@102: #if !defined(BOOST_GEOMETRY_NO_MULTIPRECISION_INTEGER) Chris@102: , typename multiprecision_integer_type Chris@102: < Chris@102: min_bit_size_type::value, Chris@102: boost::multiprecision::unsigned_magnitude Chris@102: >::type Chris@102: #endif Chris@102: > unsigned_integral_types; Chris@102: Chris@102: // Define the list of integral types that will be used for Chris@102: // promotion (depending in whether we was to promote unsigned to Chris@102: // unsigned or not) Chris@102: typedef typename boost::mpl::if_c Chris@102: < Chris@102: (is_unsigned && PromoteUnsignedToUnsigned), Chris@102: unsigned_integral_types, Chris@102: signed_integral_types Chris@102: >::type integral_types; Chris@102: Chris@102: public: Chris@102: typedef typename detail::promote_integral::promote_to_larger Chris@102: < Chris@102: T, Chris@102: typename boost::mpl::begin::type, Chris@102: typename boost::mpl::end::type, Chris@102: min_bit_size_type::value Chris@102: >::type type; Chris@102: }; Chris@102: Chris@102: Chris@102: template Chris@102: class promote_integral Chris@102: < Chris@102: T, PromoteUnsignedToUnsigned, UseCheckedInteger, false Chris@102: > Chris@102: { Chris@102: public: Chris@102: typedef T type; Chris@102: }; Chris@102: Chris@102: Chris@102: }} // namespace boost::geometry Chris@102: Chris@102: #endif // BOOST_GEOMETRY_UTIL_PROMOTE_INTEGRAL_HPP