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