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
23namespace 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 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
117 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
132 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
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 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
180 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
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 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
267 static range_check_result out_of_range ( argument_type ) { return cInRange ; }
268 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 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
293 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
464 static result_type low_level_convert ( argument_type s ) { return s ; }
465 static source_type nearbyint ( argument_type s ) { return s ; }
466 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
491 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
519 static source_type nearbyint ( argument_type s ) { return s ; }
520
521 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