Chris@16: // (c) Copyright Fernando Luis Cacciola Carballal 2000-2004 Chris@16: // Use, modification, and distribution is subject to the Boost Software Chris@16: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See library home page at http://www.boost.org/libs/numeric/conversion Chris@16: // Chris@16: // Contact the author at: fernando_cacciola@hotmail.com Chris@16: // Chris@16: #ifndef BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP Chris@16: #define BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP Chris@16: Chris@16: #include Chris@16: Chris@16: #include "boost/numeric/conversion/detail/meta.hpp" Chris@16: #include "boost/numeric/conversion/detail/conversion_traits.hpp" Chris@16: #include "boost/numeric/conversion/bounds.hpp" Chris@16: Chris@16: #include "boost/type_traits/is_same.hpp" Chris@16: Chris@16: #include "boost/mpl/integral_c.hpp" Chris@16: Chris@16: namespace boost { namespace numeric { namespace convdetail Chris@16: { Chris@16: // Integral Constants representing rounding modes Chris@16: typedef mpl::integral_c round2zero_c ; Chris@16: typedef mpl::integral_c round2nearest_c ; Chris@16: typedef mpl::integral_c round2inf_c ; Chris@16: typedef mpl::integral_c round2neg_inf_c ; Chris@16: Chris@16: // Metafunction: Chris@16: // Chris@16: // for_round_style::type Chris@16: // Chris@16: // {RoundStyle} Integral Constant specifying a round style as declared above. Chris@16: // {RoundToZero,RoundToNearest,RoundToInf,RoundToNegInf} arbitrary types. Chris@16: // Chris@16: // Selects one of the 4 types according to the value of RoundStyle. Chris@16: // Chris@16: template Chris@16: struct for_round_style Chris@16: { Chris@16: typedef ct_switch4 selector ; Chris@16: Chris@16: typedef typename selector::type type ; Chris@16: } ; Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Range Checking Logic. Chris@16: // Chris@16: // The range checking logic is built up by combining 1 or 2 predicates. Chris@16: // Each predicate is encapsulated in a template class and exposes Chris@16: // the static member function 'apply'. Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: Chris@16: // Because a particular logic can combine either 1 or two predicates, the following Chris@16: // tags are used to allow the predicate applier to receive 2 preds, but optimize away Chris@16: // one of them if it is 'non-applicable' Chris@16: struct non_applicable { typedef mpl::false_ do_apply ; } ; Chris@16: struct applicable { typedef mpl::true_ do_apply ; } ; Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Chris@16: // Range Checking Logic implementations. Chris@16: // Chris@16: // The following classes, collectivelly named 'Predicates', are instantiated within Chris@16: // the corresponding range checkers. Chris@16: // Their static member function 'apply' is called to perform the actual range checking logic. Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: // s < Lowest(T) ? cNegOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct LT_LoT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s < static_cast(bounds::lowest()) ? cNegOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s < 0 ? cNegOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct LT_Zero : applicable Chris@16: { Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s < static_cast(0) ? cNegOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s <= Lowest(T)-1 ? cNegOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct LE_PrevLoT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s <= static_cast(bounds::lowest()) - static_cast(1.0) Chris@16: ? cNegOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s < Lowest(T)-0.5 ? cNegOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct LT_HalfPrevLoT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s < static_cast(bounds::lowest()) - static_cast(0.5) Chris@16: ? cNegOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s > Highest(T) ? cPosOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct GT_HiT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s > static_cast(bounds::highest()) Chris@16: ? cPosOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s >= Lowest(T) + 1 ? cPosOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct GE_SuccHiT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s >= static_cast(bounds::highest()) + static_cast(1.0) Chris@16: ? cPosOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: // s >= Lowest(T) + 0.5 ? cPosgOverflow : cInRange Chris@16: // Chris@16: template Chris@16: struct GT_HalfSuccHiT : applicable Chris@16: { Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: return s >= static_cast(bounds::highest()) + static_cast(0.5) Chris@16: ? cPosOverflow : cInRange ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Chris@16: // Predicate Combiner. Chris@16: // Chris@16: // This helper classes are used to possibly combine the range checking logic Chris@16: // individually performed by the predicates Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: Chris@16: // Applies both predicates: first 'PredA', and if it equals 'cInRange', 'PredB' Chris@16: template Chris@16: struct applyBoth Chris@16: { Chris@16: typedef typename PredA::argument_type argument_type ; Chris@16: Chris@16: static range_check_result apply ( argument_type s ) Chris@16: { Chris@16: range_check_result r = PredA::apply(s) ; Chris@16: if ( r == cInRange ) Chris@16: r = PredB::apply(s); Chris@16: return r ; Chris@16: } Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct combine Chris@16: { Chris@16: typedef applyBoth Both ; Chris@16: typedef void NNone ; // 'None' is defined as a macro in (/usr/X11R6/include/X11/X.h) Chris@16: Chris@16: typedef typename PredA::do_apply do_applyA ; Chris@16: typedef typename PredB::do_apply do_applyB ; Chris@16: Chris@16: typedef typename for_both::type type ; Chris@16: } ; Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Range Checker classes. Chris@16: // Chris@16: // The following classes are VISIBLE base classes of the user-level converter<> class. Chris@16: // They supply the optimized 'out_of_range()' and 'validate_range()' static member functions Chris@16: // visible in the user interface. Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: // Dummy range checker. Chris@16: template Chris@16: struct dummy_range_checker Chris@16: { Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result out_of_range ( argument_type ) { return cInRange ; } Chris@16: static void validate_range ( argument_type ) {} Chris@16: } ; Chris@16: Chris@16: // Generic range checker. Chris@16: // Chris@16: // All the range checking logic for all possible combinations of source and target Chris@16: // can be arranged in terms of one or two predicates, which test overflow on both neg/pos 'sides' Chris@16: // of the ranges. Chris@16: // Chris@16: // These predicates are given here as IsNegOverflow and IsPosOverflow. Chris@16: // Chris@16: template Chris@16: struct generic_range_checker Chris@16: { Chris@16: typedef OverflowHandler overflow_handler ; Chris@16: Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: Chris@16: static range_check_result out_of_range ( argument_type s ) Chris@16: { Chris@16: typedef typename combine::type Predicate ; Chris@16: Chris@16: return Predicate::apply(s); Chris@16: } Chris@16: Chris@16: static void validate_range ( argument_type s ) Chris@16: { OverflowHandler()( out_of_range(s) ) ; } Chris@16: } ; Chris@16: Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Chris@16: // Selectors for the optimized Range Checker class. Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: template Chris@16: struct GetRC_Sig2Sig_or_Unsig2Unsig Chris@16: { Chris@16: typedef dummy_range_checker Dummy ; Chris@16: Chris@16: typedef LT_LoT Pred1 ; Chris@16: typedef GT_HiT Pred2 ; Chris@16: Chris@16: typedef generic_range_checker Normal ; Chris@16: Chris@16: typedef typename Traits::subranged subranged ; Chris@16: Chris@16: typedef typename mpl::if_::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Sig2Unsig Chris@16: { Chris@16: typedef LT_Zero Pred1 ; Chris@16: typedef GT_HiT Pred2 ; Chris@16: Chris@16: typedef generic_range_checker ChoiceA ; Chris@16: Chris@16: typedef generic_range_checker ChoiceB ; Chris@16: Chris@16: typedef typename Traits::target_type T ; Chris@16: typedef typename Traits::source_type S ; Chris@16: Chris@16: typedef typename subranged_Unsig2Sig::type oposite_subranged ; Chris@16: Chris@16: typedef typename mpl::not_::type positively_subranged ; Chris@16: Chris@16: typedef typename mpl::if_::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Unsig2Sig Chris@16: { Chris@16: typedef GT_HiT Pred1 ; Chris@16: Chris@16: typedef generic_range_checker type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Int2Int Chris@16: { Chris@16: typedef GetRC_Sig2Sig_or_Unsig2Unsig Sig2SigQ ; Chris@16: typedef GetRC_Sig2Unsig Sig2UnsigQ ; Chris@16: typedef GetRC_Unsig2Sig Unsig2SigQ ; Chris@16: typedef Sig2SigQ Unsig2UnsigQ ; Chris@16: Chris@16: typedef typename Traits::sign_mixture sign_mixture ; Chris@16: Chris@16: typedef typename Chris@16: for_sign_mixture::type Chris@16: selector ; Chris@16: Chris@16: typedef typename selector::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Int2Float Chris@16: { Chris@16: typedef dummy_range_checker type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Float2Int Chris@16: { Chris@16: typedef LE_PrevLoT Pred1 ; Chris@16: typedef GE_SuccHiT Pred2 ; Chris@16: typedef LT_HalfPrevLoT Pred3 ; Chris@16: typedef GT_HalfSuccHiT Pred4 ; Chris@16: typedef GT_HiT Pred5 ; Chris@16: typedef LT_LoT Pred6 ; Chris@16: Chris@16: typedef generic_range_checker ToZero ; Chris@16: typedef generic_range_checker ToNearest ; Chris@16: typedef generic_range_checker ToInf ; Chris@16: typedef generic_range_checker ToNegInf ; Chris@16: Chris@16: typedef typename Float2IntRounder::round_style round_style ; Chris@16: Chris@16: typedef typename for_round_style::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_Float2Float Chris@16: { Chris@16: typedef dummy_range_checker Dummy ; Chris@16: Chris@16: typedef LT_LoT Pred1 ; Chris@16: typedef GT_HiT Pred2 ; Chris@16: Chris@16: typedef generic_range_checker Normal ; Chris@16: Chris@16: typedef typename Traits::subranged subranged ; Chris@16: Chris@16: typedef typename mpl::if_::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC_BuiltIn2BuiltIn Chris@16: { Chris@16: typedef GetRC_Int2Int Int2IntQ ; Chris@16: typedef GetRC_Int2Float Int2FloatQ ; Chris@16: typedef GetRC_Float2Int Float2IntQ ; Chris@16: typedef GetRC_Float2Float Float2FloatQ ; Chris@16: Chris@16: typedef typename Traits::int_float_mixture int_float_mixture ; Chris@16: Chris@16: typedef typename for_int_float_mixture::type selector ; Chris@16: Chris@16: typedef typename selector::type type ; Chris@16: } ; Chris@16: Chris@16: template Chris@16: struct GetRC Chris@16: { Chris@16: typedef GetRC_BuiltIn2BuiltIn BuiltIn2BuiltInQ ; Chris@16: Chris@16: typedef dummy_range_checker Dummy ; Chris@16: Chris@16: typedef mpl::identity DummyQ ; Chris@16: Chris@16: typedef typename Traits::udt_builtin_mixture udt_builtin_mixture ; Chris@16: Chris@16: typedef typename for_udt_builtin_mixture::type selector ; Chris@16: Chris@16: typedef typename selector::type type ; Chris@16: } ; Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Converter classes. Chris@16: // Chris@16: // The following classes are VISIBLE base classes of the user-level converter<> class. Chris@16: // They supply the optimized 'nearbyint()' and 'convert()' static member functions Chris@16: // visible in the user interface. Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: // Chris@16: // Trivial Converter : used when (cv-unqualified) T == (cv-unqualified) S Chris@16: // Chris@16: template Chris@16: struct trivial_converter_impl : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type Chris@16: ,BOOST_DEDUCED_TYPENAME Traits::result_type Chris@16: > Chris@16: ,public dummy_range_checker Chris@16: { Chris@16: typedef Traits traits ; Chris@16: Chris@16: typedef typename Traits::source_type source_type ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: typedef typename Traits::result_type result_type ; Chris@16: Chris@16: static result_type low_level_convert ( argument_type s ) { return s ; } Chris@16: static source_type nearbyint ( argument_type s ) { return s ; } Chris@16: static result_type convert ( argument_type s ) { return s ; } Chris@16: } ; Chris@16: Chris@16: Chris@16: // Chris@16: // Rounding Converter : used for float to integral conversions. Chris@16: // Chris@16: template Chris@16: struct rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type Chris@16: ,BOOST_DEDUCED_TYPENAME Traits::result_type Chris@16: > Chris@16: ,public RangeChecker Chris@16: ,public Float2IntRounder Chris@16: ,public RawConverter Chris@16: { Chris@16: typedef RangeChecker RangeCheckerBase ; Chris@16: typedef Float2IntRounder Float2IntRounderBase ; Chris@16: typedef RawConverter RawConverterBase ; Chris@16: Chris@16: typedef Traits traits ; Chris@16: Chris@16: typedef typename Traits::source_type source_type ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: typedef typename Traits::result_type result_type ; Chris@16: Chris@16: static result_type convert ( argument_type s ) Chris@16: { Chris@16: RangeCheckerBase::validate_range(s); Chris@16: source_type s1 = Float2IntRounderBase::nearbyint(s); Chris@16: return RawConverterBase::low_level_convert(s1); Chris@16: } Chris@16: } ; Chris@16: Chris@16: Chris@16: // Chris@16: // Non-Rounding Converter : used for all other conversions. Chris@16: // Chris@16: template Chris@16: struct non_rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type Chris@16: ,BOOST_DEDUCED_TYPENAME Traits::result_type Chris@16: > Chris@16: ,public RangeChecker Chris@16: ,public RawConverter Chris@16: { Chris@16: typedef RangeChecker RangeCheckerBase ; Chris@16: typedef RawConverter RawConverterBase ; Chris@16: Chris@16: typedef Traits traits ; Chris@16: Chris@16: typedef typename Traits::source_type source_type ; Chris@16: typedef typename Traits::argument_type argument_type ; Chris@16: typedef typename Traits::result_type result_type ; Chris@16: Chris@16: static source_type nearbyint ( argument_type s ) { return s ; } Chris@16: Chris@16: static result_type convert ( argument_type s ) Chris@16: { Chris@16: RangeCheckerBase::validate_range(s); Chris@16: return RawConverterBase::low_level_convert(s); Chris@16: } Chris@16: } ; Chris@16: Chris@16: Chris@16: Chris@16: Chris@16: //-------------------------------------------------------------------------- Chris@16: // Chris@16: // Selectors for the optimized Converter class. Chris@16: // Chris@16: //-------------------------------------------------------------------------- Chris@16: Chris@16: template Chris@16: struct get_non_trivial_converter Chris@16: { Chris@16: typedef GetRC InternalRangeCheckerQ ; Chris@16: Chris@16: typedef is_same use_internal_RC ; Chris@16: Chris@16: typedef mpl::identity UserRangeCheckerQ ; Chris@16: Chris@16: typedef typename Chris@16: mpl::eval_if::type Chris@16: RangeChecker ; Chris@16: Chris@16: typedef non_rounding_converter NonRounding ; Chris@16: typedef rounding_converter Rounding ; Chris@16: Chris@16: typedef mpl::identity NonRoundingQ ; Chris@16: typedef mpl::identity RoundingQ ; Chris@16: Chris@16: typedef typename Traits::int_float_mixture int_float_mixture ; Chris@16: Chris@16: typedef typename Chris@16: for_int_float_mixture::type Chris@16: selector ; Chris@16: Chris@16: typedef typename selector::type type ; Chris@16: } ; Chris@16: Chris@16: template< class Traits Chris@16: ,class OverflowHandler Chris@16: ,class Float2IntRounder Chris@16: ,class RawConverter Chris@16: ,class UserRangeChecker Chris@16: > Chris@16: struct get_converter_impl Chris@16: { Chris@16: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT( 0x0561 ) ) Chris@16: // bcc55 prefers sometimes template parameters to be explicit local types. Chris@16: // (notice that is is illegal to reuse the names like this) Chris@16: typedef Traits Traits ; Chris@16: typedef OverflowHandler OverflowHandler ; Chris@16: typedef Float2IntRounder Float2IntRounder ; Chris@16: typedef RawConverter RawConverter ; Chris@16: typedef UserRangeChecker UserRangeChecker ; Chris@16: #endif Chris@16: Chris@16: typedef trivial_converter_impl Trivial ; Chris@16: typedef mpl::identity TrivialQ ; Chris@16: Chris@16: typedef get_non_trivial_converter< Traits Chris@16: ,OverflowHandler Chris@16: ,Float2IntRounder Chris@16: ,RawConverter Chris@16: ,UserRangeChecker Chris@16: > NonTrivialQ ; Chris@16: Chris@16: typedef typename Traits::trivial trivial ; Chris@16: Chris@16: typedef typename mpl::eval_if::type type ; Chris@16: } ; Chris@16: Chris@16: } } } // namespace boost::numeric::convdetail Chris@16: Chris@16: #endif Chris@16: Chris@16: