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