1 // (c) Copyright Fernando Luis Cacciola Carballal 2000-2004 2 // Use, modification, and distribution is subject to the Boost Software 3 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 // See library home page at http://www.boost.org/libs/numeric/conversion 7 // 8 // Contact the author at: fernando_cacciola@hotmail.com 9 // 10 #ifndef BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP 11 #define BOOST_NUMERIC_CONVERSION_DETAIL_CONVERTER_FLC_12NOV2002_HPP 12 13 #include <functional> 14 15 #include "boost/numeric/conversion/detail/meta.hpp" 16 #include "boost/numeric/conversion/detail/conversion_traits.hpp" 17 #include "boost/numeric/conversion/bounds.hpp" 18 19 #include "boost/type_traits/is_same.hpp" 20 21 #include "boost/mpl/integral_c.hpp" 22 23 namespace boost { namespace numeric { namespace convdetail 24 { 25 // Integral Constants representing rounding modes 26 typedef mpl::integral_c<std::float_round_style, std::round_toward_zero> round2zero_c ; 27 typedef mpl::integral_c<std::float_round_style, std::round_to_nearest> round2nearest_c ; 28 typedef mpl::integral_c<std::float_round_style, std::round_toward_infinity> round2inf_c ; 29 typedef mpl::integral_c<std::float_round_style, std::round_toward_neg_infinity> round2neg_inf_c ; 30 31 // Metafunction: 32 // 33 // for_round_style<RoundStyle,RoundToZero,RoundToNearest,RoundToInf,RoundToNegInf>::type 34 // 35 // {RoundStyle} Integral Constant specifying a round style as declared above. 36 // {RoundToZero,RoundToNearest,RoundToInf,RoundToNegInf} arbitrary types. 37 // 38 // Selects one of the 4 types according to the value of RoundStyle. 39 // 40 template<class RoundStyle,class RoundToZero,class RoundToNearest,class RoundToInf,class RoundToNegInf> 41 struct for_round_style 42 { 43 typedef ct_switch4<RoundStyle 44 , round2zero_c, round2nearest_c, round2inf_c // round2neg_inf_c 45 , RoundToZero , RoundToNearest , RoundToInf , RoundToNegInf 46 > selector ; 47 48 typedef typename selector::type type ; 49 } ; 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 //-------------------------------------------------------------------------- 69 // Range Checking Logic. 70 // 71 // The range checking logic is built up by combining 1 or 2 predicates. 72 // Each predicate is encapsulated in a template class and exposes 73 // the static member function 'apply'. 74 // 75 //-------------------------------------------------------------------------- 76 77 78 // Because a particular logic can combine either 1 or two predicates, the following 79 // tags are used to allow the predicate applier to receive 2 preds, but optimize away 80 // one of them if it is 'non-applicable' 81 struct non_applicable { typedef mpl::false_ do_apply ; } ; 82 struct applicable { typedef mpl::true_ do_apply ; } ; 83 84 85 //-------------------------------------------------------------------------- 86 // 87 // Range Checking Logic implementations. 88 // 89 // The following classes, collectivelly named 'Predicates', are instantiated within 90 // the corresponding range checkers. 91 // Their static member function 'apply' is called to perform the actual range checking logic. 92 //-------------------------------------------------------------------------- 93 94 // s < Lowest(T) ? cNegOverflow : cInRange 95 // 96 template<class Traits> 97 struct LT_LoT : applicable 98 { 99 typedef typename Traits::target_type T ; 100 typedef typename Traits::source_type S ; 101 typedef typename Traits::argument_type argument_type ; 102 applyboost::numeric::convdetail::LT_LoT103 static range_check_result apply ( argument_type s ) 104 { 105 return s < static_cast<S>(bounds<T>::lowest()) ? cNegOverflow : cInRange ; 106 } 107 } ; 108 109 // s < 0 ? cNegOverflow : cInRange 110 // 111 template<class Traits> 112 struct LT_Zero : applicable 113 { 114 typedef typename Traits::source_type S ; 115 typedef typename Traits::argument_type argument_type ; 116 applyboost::numeric::convdetail::LT_Zero117 static range_check_result apply ( argument_type s ) 118 { 119 return s < static_cast<S>(0) ? cNegOverflow : cInRange ; 120 } 121 } ; 122 123 // s <= Lowest(T)-1 ? cNegOverflow : cInRange 124 // 125 template<class Traits> 126 struct LE_PrevLoT : applicable 127 { 128 typedef typename Traits::target_type T ; 129 typedef typename Traits::source_type S ; 130 typedef typename Traits::argument_type argument_type ; 131 applyboost::numeric::convdetail::LE_PrevLoT132 static range_check_result apply ( argument_type s ) 133 { 134 return s <= static_cast<S>(bounds<T>::lowest()) - static_cast<S>(1.0) 135 ? cNegOverflow : cInRange ; 136 } 137 } ; 138 139 // s < Lowest(T)-0.5 ? cNegOverflow : cInRange 140 // 141 template<class Traits> 142 struct LT_HalfPrevLoT : applicable 143 { 144 typedef typename Traits::target_type T ; 145 typedef typename Traits::source_type S ; 146 typedef typename Traits::argument_type argument_type ; 147 applyboost::numeric::convdetail::LT_HalfPrevLoT148 static range_check_result apply ( argument_type s ) 149 { 150 return s < static_cast<S>(bounds<T>::lowest()) - static_cast<S>(0.5) 151 ? cNegOverflow : cInRange ; 152 } 153 } ; 154 155 // s > Highest(T) ? cPosOverflow : cInRange 156 // 157 template<class Traits> 158 struct GT_HiT : applicable 159 { 160 typedef typename Traits::target_type T ; 161 typedef typename Traits::source_type S ; 162 typedef typename Traits::argument_type argument_type ; 163 applyboost::numeric::convdetail::GT_HiT164 static range_check_result apply ( argument_type s ) 165 { 166 return s > static_cast<S>(bounds<T>::highest()) 167 ? cPosOverflow : cInRange ; 168 } 169 } ; 170 171 // s >= Lowest(T) + 1 ? cPosOverflow : cInRange 172 // 173 template<class Traits> 174 struct GE_SuccHiT : applicable 175 { 176 typedef typename Traits::target_type T ; 177 typedef typename Traits::source_type S ; 178 typedef typename Traits::argument_type argument_type ; 179 applyboost::numeric::convdetail::GE_SuccHiT180 static range_check_result apply ( argument_type s ) 181 { 182 return s >= static_cast<S>(bounds<T>::highest()) + static_cast<S>(1.0) 183 ? cPosOverflow : cInRange ; 184 } 185 } ; 186 187 // s >= Lowest(T) + 0.5 ? cPosgOverflow : cInRange 188 // 189 template<class Traits> 190 struct GT_HalfSuccHiT : applicable 191 { 192 typedef typename Traits::target_type T ; 193 typedef typename Traits::source_type S ; 194 typedef typename Traits::argument_type argument_type ; 195 applyboost::numeric::convdetail::GT_HalfSuccHiT196 static range_check_result apply ( argument_type s ) 197 { 198 return s >= static_cast<S>(bounds<T>::highest()) + static_cast<S>(0.5) 199 ? cPosOverflow : cInRange ; 200 } 201 } ; 202 203 204 //-------------------------------------------------------------------------- 205 // 206 // Predicate Combiner. 207 // 208 // This helper classes are used to possibly combine the range checking logic 209 // individually performed by the predicates 210 // 211 //-------------------------------------------------------------------------- 212 213 214 // Applies both predicates: first 'PredA', and if it equals 'cInRange', 'PredB' 215 template<class PredA, class PredB> 216 struct applyBoth 217 { 218 typedef typename PredA::argument_type argument_type ; 219 applyboost::numeric::convdetail::applyBoth220 static range_check_result apply ( argument_type s ) 221 { 222 range_check_result r = PredA::apply(s) ; 223 if ( r == cInRange ) 224 r = PredB::apply(s); 225 return r ; 226 } 227 } ; 228 229 template<class PredA, class PredB> 230 struct combine 231 { 232 typedef applyBoth<PredA,PredB> Both ; 233 typedef void NNone ; // 'None' is defined as a macro in (/usr/X11R6/include/X11/X.h) 234 235 typedef typename PredA::do_apply do_applyA ; 236 typedef typename PredB::do_apply do_applyB ; 237 238 typedef typename for_both<do_applyA, do_applyB, Both, PredA, PredB, NNone>::type type ; 239 } ; 240 241 242 243 244 245 246 247 248 249 250 251 252 //-------------------------------------------------------------------------- 253 // Range Checker classes. 254 // 255 // The following classes are VISIBLE base classes of the user-level converter<> class. 256 // They supply the optimized 'out_of_range()' and 'validate_range()' static member functions 257 // visible in the user interface. 258 // 259 //-------------------------------------------------------------------------- 260 261 // Dummy range checker. 262 template<class Traits> 263 struct dummy_range_checker 264 { 265 typedef typename Traits::argument_type argument_type ; 266 out_of_rangeboost::numeric::convdetail::dummy_range_checker267 static range_check_result out_of_range ( argument_type ) { return cInRange ; } validate_rangeboost::numeric::convdetail::dummy_range_checker268 static void validate_range ( argument_type ) {} 269 } ; 270 271 // Generic range checker. 272 // 273 // All the range checking logic for all possible combinations of source and target 274 // can be arranged in terms of one or two predicates, which test overflow on both neg/pos 'sides' 275 // of the ranges. 276 // 277 // These predicates are given here as IsNegOverflow and IsPosOverflow. 278 // 279 template<class Traits, class IsNegOverflow, class IsPosOverflow, class OverflowHandler> 280 struct generic_range_checker 281 { 282 typedef OverflowHandler overflow_handler ; 283 284 typedef typename Traits::argument_type argument_type ; 285 out_of_rangeboost::numeric::convdetail::generic_range_checker286 static range_check_result out_of_range ( argument_type s ) 287 { 288 typedef typename combine<IsNegOverflow,IsPosOverflow>::type Predicate ; 289 290 return Predicate::apply(s); 291 } 292 validate_rangeboost::numeric::convdetail::generic_range_checker293 static void validate_range ( argument_type s ) 294 { OverflowHandler()( out_of_range(s) ) ; } 295 } ; 296 297 298 299 //-------------------------------------------------------------------------- 300 // 301 // Selectors for the optimized Range Checker class. 302 // 303 //-------------------------------------------------------------------------- 304 305 template<class Traits,class OverflowHandler> 306 struct GetRC_Sig2Sig_or_Unsig2Unsig 307 { 308 typedef dummy_range_checker<Traits> Dummy ; 309 310 typedef LT_LoT<Traits> Pred1 ; 311 typedef GT_HiT<Traits> Pred2 ; 312 313 typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> Normal ; 314 315 typedef typename Traits::subranged subranged ; 316 317 typedef typename mpl::if_<subranged,Normal,Dummy>::type type ; 318 } ; 319 320 template<class Traits, class OverflowHandler> 321 struct GetRC_Sig2Unsig 322 { 323 typedef LT_Zero<Traits> Pred1 ; 324 typedef GT_HiT <Traits> Pred2 ; 325 326 typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> ChoiceA ; 327 328 typedef generic_range_checker<Traits,Pred1,non_applicable,OverflowHandler> ChoiceB ; 329 330 typedef typename Traits::target_type T ; 331 typedef typename Traits::source_type S ; 332 333 typedef typename subranged_Unsig2Sig<S,T>::type oposite_subranged ; 334 335 typedef typename mpl::not_<oposite_subranged>::type positively_subranged ; 336 337 typedef typename mpl::if_<positively_subranged,ChoiceA,ChoiceB>::type type ; 338 } ; 339 340 template<class Traits, class OverflowHandler> 341 struct GetRC_Unsig2Sig 342 { 343 typedef GT_HiT<Traits> Pred1 ; 344 345 typedef generic_range_checker<Traits,non_applicable,Pred1,OverflowHandler> type ; 346 } ; 347 348 template<class Traits,class OverflowHandler> 349 struct GetRC_Int2Int 350 { 351 typedef GetRC_Sig2Sig_or_Unsig2Unsig<Traits,OverflowHandler> Sig2SigQ ; 352 typedef GetRC_Sig2Unsig <Traits,OverflowHandler> Sig2UnsigQ ; 353 typedef GetRC_Unsig2Sig <Traits,OverflowHandler> Unsig2SigQ ; 354 typedef Sig2SigQ Unsig2UnsigQ ; 355 356 typedef typename Traits::sign_mixture sign_mixture ; 357 358 typedef typename 359 for_sign_mixture<sign_mixture,Sig2SigQ,Sig2UnsigQ,Unsig2SigQ,Unsig2UnsigQ>::type 360 selector ; 361 362 typedef typename selector::type type ; 363 } ; 364 365 template<class Traits> 366 struct GetRC_Int2Float 367 { 368 typedef dummy_range_checker<Traits> type ; 369 } ; 370 371 template<class Traits, class OverflowHandler, class Float2IntRounder> 372 struct GetRC_Float2Int 373 { 374 typedef LE_PrevLoT <Traits> Pred1 ; 375 typedef GE_SuccHiT <Traits> Pred2 ; 376 typedef LT_HalfPrevLoT<Traits> Pred3 ; 377 typedef GT_HalfSuccHiT<Traits> Pred4 ; 378 typedef GT_HiT <Traits> Pred5 ; 379 typedef LT_LoT <Traits> Pred6 ; 380 381 typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> ToZero ; 382 typedef generic_range_checker<Traits,Pred3,Pred4,OverflowHandler> ToNearest ; 383 typedef generic_range_checker<Traits,Pred1,Pred5,OverflowHandler> ToInf ; 384 typedef generic_range_checker<Traits,Pred6,Pred2,OverflowHandler> ToNegInf ; 385 386 typedef typename Float2IntRounder::round_style round_style ; 387 388 typedef typename for_round_style<round_style,ToZero,ToNearest,ToInf,ToNegInf>::type type ; 389 } ; 390 391 template<class Traits, class OverflowHandler> 392 struct GetRC_Float2Float 393 { 394 typedef dummy_range_checker<Traits> Dummy ; 395 396 typedef LT_LoT<Traits> Pred1 ; 397 typedef GT_HiT<Traits> Pred2 ; 398 399 typedef generic_range_checker<Traits,Pred1,Pred2,OverflowHandler> Normal ; 400 401 typedef typename Traits::subranged subranged ; 402 403 typedef typename mpl::if_<subranged,Normal,Dummy>::type type ; 404 } ; 405 406 template<class Traits, class OverflowHandler, class Float2IntRounder> 407 struct GetRC_BuiltIn2BuiltIn 408 { 409 typedef GetRC_Int2Int<Traits,OverflowHandler> Int2IntQ ; 410 typedef GetRC_Int2Float<Traits> Int2FloatQ ; 411 typedef GetRC_Float2Int<Traits,OverflowHandler,Float2IntRounder> Float2IntQ ; 412 typedef GetRC_Float2Float<Traits,OverflowHandler> Float2FloatQ ; 413 414 typedef typename Traits::int_float_mixture int_float_mixture ; 415 416 typedef typename for_int_float_mixture<int_float_mixture, Int2IntQ, Int2FloatQ, Float2IntQ, Float2FloatQ>::type selector ; 417 418 typedef typename selector::type type ; 419 } ; 420 421 template<class Traits, class OverflowHandler, class Float2IntRounder> 422 struct GetRC 423 { 424 typedef GetRC_BuiltIn2BuiltIn<Traits,OverflowHandler,Float2IntRounder> BuiltIn2BuiltInQ ; 425 426 typedef dummy_range_checker<Traits> Dummy ; 427 428 typedef mpl::identity<Dummy> DummyQ ; 429 430 typedef typename Traits::udt_builtin_mixture udt_builtin_mixture ; 431 432 typedef typename for_udt_builtin_mixture<udt_builtin_mixture,BuiltIn2BuiltInQ,DummyQ,DummyQ,DummyQ>::type selector ; 433 434 typedef typename selector::type type ; 435 } ; 436 437 438 439 440 //-------------------------------------------------------------------------- 441 // Converter classes. 442 // 443 // The following classes are VISIBLE base classes of the user-level converter<> class. 444 // They supply the optimized 'nearbyint()' and 'convert()' static member functions 445 // visible in the user interface. 446 // 447 //-------------------------------------------------------------------------- 448 449 // 450 // Trivial Converter : used when (cv-unqualified) T == (cv-unqualified) S 451 // 452 template<class Traits> 453 struct trivial_converter_impl : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type 454 ,BOOST_DEDUCED_TYPENAME Traits::result_type 455 > 456 ,public dummy_range_checker<Traits> 457 { 458 typedef Traits traits ; 459 460 typedef typename Traits::source_type source_type ; 461 typedef typename Traits::argument_type argument_type ; 462 typedef typename Traits::result_type result_type ; 463 low_level_convertboost::numeric::convdetail::trivial_converter_impl464 static result_type low_level_convert ( argument_type s ) { return s ; } nearbyintboost::numeric::convdetail::trivial_converter_impl465 static source_type nearbyint ( argument_type s ) { return s ; } convertboost::numeric::convdetail::trivial_converter_impl466 static result_type convert ( argument_type s ) { return s ; } 467 } ; 468 469 470 // 471 // Rounding Converter : used for float to integral conversions. 472 // 473 template<class Traits,class RangeChecker,class RawConverter,class Float2IntRounder> 474 struct rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type 475 ,BOOST_DEDUCED_TYPENAME Traits::result_type 476 > 477 ,public RangeChecker 478 ,public Float2IntRounder 479 ,public RawConverter 480 { 481 typedef RangeChecker RangeCheckerBase ; 482 typedef Float2IntRounder Float2IntRounderBase ; 483 typedef RawConverter RawConverterBase ; 484 485 typedef Traits traits ; 486 487 typedef typename Traits::source_type source_type ; 488 typedef typename Traits::argument_type argument_type ; 489 typedef typename Traits::result_type result_type ; 490 convertboost::numeric::convdetail::rounding_converter491 static result_type convert ( argument_type s ) 492 { 493 RangeCheckerBase::validate_range(s); 494 source_type s1 = Float2IntRounderBase::nearbyint(s); 495 return RawConverterBase::low_level_convert(s1); 496 } 497 } ; 498 499 500 // 501 // Non-Rounding Converter : used for all other conversions. 502 // 503 template<class Traits,class RangeChecker,class RawConverter> 504 struct non_rounding_converter : public std::unary_function< BOOST_DEDUCED_TYPENAME Traits::argument_type 505 ,BOOST_DEDUCED_TYPENAME Traits::result_type 506 > 507 ,public RangeChecker 508 ,public RawConverter 509 { 510 typedef RangeChecker RangeCheckerBase ; 511 typedef RawConverter RawConverterBase ; 512 513 typedef Traits traits ; 514 515 typedef typename Traits::source_type source_type ; 516 typedef typename Traits::argument_type argument_type ; 517 typedef typename Traits::result_type result_type ; 518 nearbyintboost::numeric::convdetail::non_rounding_converter519 static source_type nearbyint ( argument_type s ) { return s ; } 520 convertboost::numeric::convdetail::non_rounding_converter521 static result_type convert ( argument_type s ) 522 { 523 RangeCheckerBase::validate_range(s); 524 return RawConverterBase::low_level_convert(s); 525 } 526 } ; 527 528 529 530 531 //-------------------------------------------------------------------------- 532 // 533 // Selectors for the optimized Converter class. 534 // 535 //-------------------------------------------------------------------------- 536 537 template<class Traits,class OverflowHandler,class Float2IntRounder,class RawConverter, class UserRangeChecker> 538 struct get_non_trivial_converter 539 { 540 typedef GetRC<Traits,OverflowHandler,Float2IntRounder> InternalRangeCheckerQ ; 541 542 typedef is_same<UserRangeChecker,UseInternalRangeChecker> use_internal_RC ; 543 544 typedef mpl::identity<UserRangeChecker> UserRangeCheckerQ ; 545 546 typedef typename 547 mpl::eval_if<use_internal_RC,InternalRangeCheckerQ,UserRangeCheckerQ>::type 548 RangeChecker ; 549 550 typedef non_rounding_converter<Traits,RangeChecker,RawConverter> NonRounding ; 551 typedef rounding_converter<Traits,RangeChecker,RawConverter,Float2IntRounder> Rounding ; 552 553 typedef mpl::identity<NonRounding> NonRoundingQ ; 554 typedef mpl::identity<Rounding> RoundingQ ; 555 556 typedef typename Traits::int_float_mixture int_float_mixture ; 557 558 typedef typename 559 for_int_float_mixture<int_float_mixture, NonRoundingQ, NonRoundingQ, RoundingQ, NonRoundingQ>::type 560 selector ; 561 562 typedef typename selector::type type ; 563 } ; 564 565 template< class Traits 566 ,class OverflowHandler 567 ,class Float2IntRounder 568 ,class RawConverter 569 ,class UserRangeChecker 570 > 571 struct get_converter_impl 572 { 573 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT( 0x0561 ) ) 574 // bcc55 prefers sometimes template parameters to be explicit local types. 575 // (notice that is is illegal to reuse the names like this) 576 typedef Traits Traits ; 577 typedef OverflowHandler OverflowHandler ; 578 typedef Float2IntRounder Float2IntRounder ; 579 typedef RawConverter RawConverter ; 580 typedef UserRangeChecker UserRangeChecker ; 581 #endif 582 583 typedef trivial_converter_impl<Traits> Trivial ; 584 typedef mpl::identity <Trivial> TrivialQ ; 585 586 typedef get_non_trivial_converter< Traits 587 ,OverflowHandler 588 ,Float2IntRounder 589 ,RawConverter 590 ,UserRangeChecker 591 > NonTrivialQ ; 592 593 typedef typename Traits::trivial trivial ; 594 595 typedef typename mpl::eval_if<trivial,TrivialQ,NonTrivialQ>::type type ; 596 } ; 597 598 } } } // namespace boost::numeric::convdetail 599 600 #endif 601 602 603