Line data Source code
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 :
103 0 : static range_check_result apply ( argument_type s )
104 : {
105 0 : 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 :
117 0 : static range_check_result apply ( argument_type s )
118 : {
119 0 : 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 :
132 0 : static range_check_result apply ( argument_type s )
133 : {
134 : return s <= static_cast<S>(bounds<T>::lowest()) - static_cast<S>(1.0)
135 0 : ? 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 :
148 : 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 :
164 0 : static range_check_result apply ( argument_type s )
165 : {
166 : return s > static_cast<S>(bounds<T>::highest())
167 0 : ? 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 :
180 0 : static range_check_result apply ( argument_type s )
181 : {
182 : return s >= static_cast<S>(bounds<T>::highest()) + static_cast<S>(1.0)
183 0 : ? 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 :
196 : 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 :
220 0 : static range_check_result apply ( argument_type s )
221 : {
222 0 : range_check_result r = PredA::apply(s) ;
223 0 : if ( r == cInRange )
224 0 : 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 :
267 : static range_check_result out_of_range ( argument_type ) { return cInRange ; }
268 0 : 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 :
286 0 : static range_check_result out_of_range ( argument_type s )
287 : {
288 : typedef typename combine<IsNegOverflow,IsPosOverflow>::type Predicate ;
289 :
290 0 : return Predicate::apply(s);
291 : }
292 :
293 0 : static void validate_range ( argument_type s )
294 0 : { 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 dummy_range_checker<Traits>
454 : {
455 : typedef Traits traits ;
456 :
457 : typedef typename Traits::source_type source_type ;
458 : typedef typename Traits::argument_type argument_type ;
459 : typedef typename Traits::result_type result_type ;
460 :
461 : static result_type low_level_convert ( argument_type s ) { return s ; }
462 : static source_type nearbyint ( argument_type s ) { return s ; }
463 0 : static result_type convert ( argument_type s ) { return s ; }
464 : } ;
465 :
466 :
467 : //
468 : // Rounding Converter : used for float to integral conversions.
469 : //
470 : template<class Traits,class RangeChecker,class RawConverter,class Float2IntRounder>
471 : struct rounding_converter : public RangeChecker
472 : ,public Float2IntRounder
473 : ,public RawConverter
474 : {
475 : typedef RangeChecker RangeCheckerBase ;
476 : typedef Float2IntRounder Float2IntRounderBase ;
477 : typedef RawConverter RawConverterBase ;
478 :
479 : typedef Traits traits ;
480 :
481 : typedef typename Traits::source_type source_type ;
482 : typedef typename Traits::argument_type argument_type ;
483 : typedef typename Traits::result_type result_type ;
484 :
485 0 : static result_type convert ( argument_type s )
486 : {
487 0 : RangeCheckerBase::validate_range(s);
488 0 : source_type s1 = Float2IntRounderBase::nearbyint(s);
489 0 : return RawConverterBase::low_level_convert(s1);
490 : }
491 : } ;
492 :
493 :
494 : //
495 : // Non-Rounding Converter : used for all other conversions.
496 : //
497 : template<class Traits,class RangeChecker,class RawConverter>
498 : struct non_rounding_converter : public RangeChecker
499 : ,public RawConverter
500 : {
501 : typedef RangeChecker RangeCheckerBase ;
502 : typedef RawConverter RawConverterBase ;
503 :
504 : typedef Traits traits ;
505 :
506 : typedef typename Traits::source_type source_type ;
507 : typedef typename Traits::argument_type argument_type ;
508 : typedef typename Traits::result_type result_type ;
509 :
510 : static source_type nearbyint ( argument_type s ) { return s ; }
511 :
512 0 : static result_type convert ( argument_type s )
513 : {
514 0 : RangeCheckerBase::validate_range(s);
515 0 : return RawConverterBase::low_level_convert(s);
516 : }
517 : } ;
518 :
519 :
520 :
521 :
522 : //--------------------------------------------------------------------------
523 : //
524 : // Selectors for the optimized Converter class.
525 : //
526 : //--------------------------------------------------------------------------
527 :
528 : template<class Traits,class OverflowHandler,class Float2IntRounder,class RawConverter, class UserRangeChecker>
529 : struct get_non_trivial_converter
530 : {
531 : typedef GetRC<Traits,OverflowHandler,Float2IntRounder> InternalRangeCheckerQ ;
532 :
533 : typedef is_same<UserRangeChecker,UseInternalRangeChecker> use_internal_RC ;
534 :
535 : typedef mpl::identity<UserRangeChecker> UserRangeCheckerQ ;
536 :
537 : typedef typename
538 : mpl::eval_if<use_internal_RC,InternalRangeCheckerQ,UserRangeCheckerQ>::type
539 : RangeChecker ;
540 :
541 : typedef non_rounding_converter<Traits,RangeChecker,RawConverter> NonRounding ;
542 : typedef rounding_converter<Traits,RangeChecker,RawConverter,Float2IntRounder> Rounding ;
543 :
544 : typedef mpl::identity<NonRounding> NonRoundingQ ;
545 : typedef mpl::identity<Rounding> RoundingQ ;
546 :
547 : typedef typename Traits::int_float_mixture int_float_mixture ;
548 :
549 : typedef typename
550 : for_int_float_mixture<int_float_mixture, NonRoundingQ, NonRoundingQ, RoundingQ, NonRoundingQ>::type
551 : selector ;
552 :
553 : typedef typename selector::type type ;
554 : } ;
555 :
556 : template< class Traits
557 : ,class OverflowHandler
558 : ,class Float2IntRounder
559 : ,class RawConverter
560 : ,class UserRangeChecker
561 : >
562 : struct get_converter_impl
563 : {
564 : #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT( 0x0561 ) )
565 : // bcc55 prefers sometimes template parameters to be explicit local types.
566 : // (notice that is is illegal to reuse the names like this)
567 : typedef Traits Traits ;
568 : typedef OverflowHandler OverflowHandler ;
569 : typedef Float2IntRounder Float2IntRounder ;
570 : typedef RawConverter RawConverter ;
571 : typedef UserRangeChecker UserRangeChecker ;
572 : #endif
573 :
574 : typedef trivial_converter_impl<Traits> Trivial ;
575 : typedef mpl::identity <Trivial> TrivialQ ;
576 :
577 : typedef get_non_trivial_converter< Traits
578 : ,OverflowHandler
579 : ,Float2IntRounder
580 : ,RawConverter
581 : ,UserRangeChecker
582 : > NonTrivialQ ;
583 :
584 : typedef typename Traits::trivial trivial ;
585 :
586 : typedef typename mpl::eval_if<trivial,TrivialQ,NonTrivialQ>::type type ;
587 : } ;
588 :
589 : } } } // namespace boost::numeric::convdetail
590 :
591 : #endif
592 :
593 :
|