summaryrefslogtreecommitdiffstats
blob: b5e7fe8f1e8acd15df983659e92aefb915823f56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
//  (c) 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_IS_SUBRANGED_FLC_12NOV2002_HPP
#define BOOST_NUMERIC_CONVERSION_DETAIL_IS_SUBRANGED_FLC_12NOV2002_HPP

#include "boost/config.hpp"
#include "boost/limits.hpp"

#include "boost/mpl/int.hpp"
#include "boost/mpl/multiplies.hpp"
#include "boost/mpl/less.hpp"
#include "boost/mpl/equal_to.hpp"

#include "boost/type_traits/is_same.hpp"

#include "boost/numeric/conversion/detail/meta.hpp"
#include "boost/numeric/conversion/detail/int_float_mixture.hpp"
#include "boost/numeric/conversion/detail/sign_mixture.hpp"
#include "boost/numeric/conversion/detail/udt_builtin_mixture.hpp"

namespace boost { namespace numeric { namespace convdetail
{
  //---------------------------------------------------------------
  // Implementations of the compile time predicate "T is subranged"
  //---------------------------------------------------------------

    // for integral to integral conversions
    template<class T,class S>
    struct subranged_Sig2Unsig
    {
      // Signed to unsigned conversions are 'subranged' because of possible loose
      // of negative values.
      typedef mpl::true_ type ;
    } ;

    // for unsigned integral to signed integral conversions
    template<class T,class S>
    struct subranged_Unsig2Sig
    {
       // IMPORTANT NOTE:
       //
       // This code assumes that signed/unsigned integral values are represented
       // such that:
       //
       //  numeric_limits<signed T>::digits + 1 == numeric_limits<unsigned T>::digits
       //
       // The '+1' is required since numeric_limits<>::digits gives 1 bit less for signed integral types.
       //
       // This fact is used by the following logic:
       //
       //  if ( (numeric_limits<T>::digits+1) < (2*numeric_limits<S>::digits) )
       //    then the conversion is subranged.
       //

       typedef mpl::int_< ::std::numeric_limits<S>::digits > S_digits ;
       typedef mpl::int_< ::std::numeric_limits<T>::digits > T_digits ;

       // T is signed, so take digits+1
       typedef typename T_digits::next u_T_digits ;

       typedef mpl::int_<2> Two ;

       typedef typename mpl::multiplies<S_digits,Two>::type S_digits_times_2 ;

       typedef typename mpl::less<u_T_digits,S_digits_times_2>::type type ;
    } ;

    // for integral to integral conversions of the same sign.
    template<class T,class S>
    struct subranged_SameSign
    {
       // An integral conversion of the same sign is subranged if digits(T) < digits(S).

       typedef mpl::int_< ::std::numeric_limits<S>::digits > S_digits ;
       typedef mpl::int_< ::std::numeric_limits<T>::digits > T_digits ;

       typedef typename mpl::less<T_digits,S_digits>::type type ;
    } ;

    // for integral to float conversions
    template<class T,class S>
    struct subranged_Int2Float
    {
      typedef mpl::false_ type ;
    } ;

    // for float to integral conversions
    template<class T,class S>
    struct subranged_Float2Int
    {
      typedef mpl::true_ type ;
    } ;

    // for float to float conversions
    template<class T,class S>
    struct subranged_Float2Float
    {
      // If both T and S are floats,
      // compare exponent bits and if they match, mantisa bits.

      typedef mpl::int_< ::std::numeric_limits<S>::digits > S_mantisa ;
      typedef mpl::int_< ::std::numeric_limits<T>::digits > T_mantisa ;

      typedef mpl::int_< ::std::numeric_limits<S>::max_exponent > S_exponent ;
      typedef mpl::int_< ::std::numeric_limits<T>::max_exponent > T_exponent ;

      typedef typename mpl::less<T_exponent,S_exponent>::type T_smaller_exponent ;

      typedef typename mpl::equal_to<T_exponent,S_exponent>::type equal_exponents ;

      typedef mpl::less<T_mantisa,S_mantisa> T_smaller_mantisa ;

      typedef mpl::eval_if<equal_exponents,T_smaller_mantisa,mpl::false_> not_bigger_exponent_case ;

      typedef typename
        mpl::eval_if<T_smaller_exponent,mpl::true_,not_bigger_exponent_case>::type
          type ;
    } ;

    // for Udt to built-in conversions
    template<class T,class S>
    struct subranged_Udt2BuiltIn
    {
      typedef mpl::true_ type ;
    } ;

    // for built-in to Udt conversions
    template<class T,class S>
    struct subranged_BuiltIn2Udt
    {
      typedef mpl::false_ type ;
    } ;

    // for Udt to Udt conversions
    template<class T,class S>
    struct subranged_Udt2Udt
    {
      typedef mpl::false_ type ;
    } ;

  //-------------------------------------------------------------------
  // Selectors for the implementations of the subranged predicate
  //-------------------------------------------------------------------

    template<class T,class S>
    struct get_subranged_Int2Int
    {
      typedef subranged_SameSign<T,S>  Sig2Sig     ;
      typedef subranged_Sig2Unsig<T,S> Sig2Unsig   ;
      typedef subranged_Unsig2Sig<T,S> Unsig2Sig   ;
      typedef Sig2Sig                  Unsig2Unsig ;

      typedef typename get_sign_mixture<T,S>::type sign_mixture ;

      typedef typename
        for_sign_mixture<sign_mixture, Sig2Sig, Sig2Unsig, Unsig2Sig, Unsig2Unsig>::type
           type ;
    } ;

    template<class T,class S>
    struct get_subranged_BuiltIn2BuiltIn
    {
      typedef get_subranged_Int2Int<T,S> Int2IntQ ;

      typedef subranged_Int2Float  <T,S> Int2Float   ;
      typedef subranged_Float2Int  <T,S> Float2Int   ;
      typedef subranged_Float2Float<T,S> Float2Float ;

      typedef mpl::identity<Int2Float  > Int2FloatQ   ;
      typedef mpl::identity<Float2Int  > Float2IntQ   ;
      typedef mpl::identity<Float2Float> Float2FloatQ ;

      typedef typename get_int_float_mixture<T,S>::type int_float_mixture ;

      typedef for_int_float_mixture<int_float_mixture, Int2IntQ, Int2FloatQ, Float2IntQ, Float2FloatQ> for_ ;

      typedef typename for_::type selected ;

      typedef typename selected::type type ;
    } ;

    template<class T,class S>
    struct get_subranged
    {
      typedef get_subranged_BuiltIn2BuiltIn<T,S> BuiltIn2BuiltInQ ;

      typedef subranged_BuiltIn2Udt<T,S> BuiltIn2Udt ;
      typedef subranged_Udt2BuiltIn<T,S> Udt2BuiltIn ;
      typedef subranged_Udt2Udt<T,S>     Udt2Udt ;

      typedef mpl::identity<BuiltIn2Udt> BuiltIn2UdtQ ;
      typedef mpl::identity<Udt2BuiltIn> Udt2BuiltInQ ;
      typedef mpl::identity<Udt2Udt    > Udt2UdtQ     ;

      typedef typename get_udt_builtin_mixture<T,S>::type udt_builtin_mixture ;
      
      typedef typename
        for_udt_builtin_mixture<udt_builtin_mixture, BuiltIn2BuiltInQ, BuiltIn2UdtQ, Udt2BuiltInQ, Udt2UdtQ>::type
          selected ;

      typedef typename selected::type selected2 ;
 
      typedef typename selected2::type type ;
    } ;


  //-------------------------------------------------------------------
  // Top level implementation selector.
  //-------------------------------------------------------------------
  template<class T, class S>
  struct get_is_subranged
  {
    typedef get_subranged<T,S>         non_trivial_case ;
    typedef mpl::identity<mpl::false_> trivial_case ;

    typedef is_same<T,S> is_trivial ;
   
    typedef typename mpl::if_<is_trivial,trivial_case,non_trivial_case>::type selected ;
    
    typedef typename selected::type type ;
  } ;

} } } // namespace boost::numeric::convdetail

#endif