1 // Boost.GIL (Generic Image Library)
2 //
3 // Copyright (c) 2015, Oracle and/or its affiliates.
4 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
5 //
6 // Licensed under the Boost Software License version 1.0.
7 // http://www.boost.org/users/license.html
8 //
9 // Source: Boost.Geometry (aka GGL, Generic Geometry Library)
10 // Modifications: adapted for Boost.GIL
11 //  - Rename namespace boost::geometry to boost::gil
12 //  - Rename include guards
13 //  - Remove support for boost::multiprecision types
14 //  - Remove support for 128-bit integer types
15 //
16 #ifndef BOOST_GIL_PROMOTE_INTEGRAL_HPP
17 #define BOOST_GIL_PROMOTE_INTEGRAL_HPP
18 
19 #include <boost/mpl/begin.hpp>
20 #include <boost/mpl/deref.hpp>
21 #include <boost/mpl/end.hpp>
22 #include <boost/mpl/list.hpp>
23 #include <boost/mpl/next.hpp>
24 
25 #include <climits>
26 #include <cstddef>
27 #include <type_traits>
28 
29 namespace boost { namespace gil
30 {
31 
32 namespace detail { namespace promote_integral
33 {
34 
35 // meta-function that returns the bit size of a type
36 template
37 <
38     typename T,
39     bool IsFundamental = std::is_fundamental<T>::type::value
40 >
41 struct bit_size {};
42 
43 // for fundamental types, just return CHAR_BIT * sizeof(T)
44 template <typename T>
45 struct bit_size<T, true> : std::integral_constant<std::size_t, (CHAR_BIT * sizeof(T))> {};
46 
47 template
48 <
49     typename T,
50     typename Iterator,
51     typename EndIterator,
52     std::size_t MinSize
53 >
54 struct promote_to_larger
55 {
56     typedef typename boost::mpl::deref<Iterator>::type current_type;
57 
58     typedef typename std::conditional
59         <
60             (bit_size<current_type>::type::value >= MinSize),
61             current_type,
62             typename promote_to_larger
63                 <
64                     T,
65                     typename boost::mpl::next<Iterator>::type,
66                     EndIterator,
67                     MinSize
68                 >::type
69         >::type type;
70 };
71 
72 // The following specialization is required to finish the loop over
73 // all list elements
74 template <typename T, typename EndIterator, std::size_t MinSize>
75 struct promote_to_larger<T, EndIterator, EndIterator, MinSize>
76 {
77     // if promotion fails, keep the number T
78     // (and cross fingers that overflow will not occur)
79     typedef T type;
80 };
81 
82 }} // namespace detail::promote_integral
83 
84 /*!
85     \brief Meta-function to define an integral type with size
86     than is (roughly) twice the bit size of T
87     \ingroup utility
88     \details
89     This meta-function tries to promote the fundamental integral type T
90     to a another integral type with size (roughly) twice the bit size of T.
91 
92     To do this, two times the bit size of T is tested against the bit sizes of:
93          short, int, long, boost::long_long_type, boost::int128_t
94     and the one that first matches is chosen.
95 
96     For unsigned types the bit size of T is tested against the bit
97     sizes of the types above, if T is promoted to a signed type, or
98     the bit sizes of
99          unsigned short, unsigned int, unsigned long, std::size_t,
100          boost::ulong_long_type, boost::uint128_t
101     if T is promoted to an unsigned type.
102 
103     By default an unsigned type is promoted to a signed type.
104     This behavior is controlled by the PromoteUnsignedToUnsigned
105     boolean template parameter, whose default value is "false".
106     To promote an unsigned type to an unsigned type set the value of
107     this template parameter to "true".
108 
109     Finally, if the passed type is either a floating-point type or a
110     user-defined type it is returned as is.
111 
112     \note boost::long_long_type and boost::ulong_long_type are
113     considered only if the macro BOOST_HAS_LONG_LONG is defined
114 
115 */
116 template
117 <
118     typename T,
119     bool PromoteUnsignedToUnsigned = false,
120     bool UseCheckedInteger = false,
121     bool IsIntegral = std::is_integral<T>::type::value
122 >
123 class promote_integral
124 {
125 private:
126     static bool const is_unsigned = std::is_unsigned<T>::type::value;
127 
128     typedef detail::promote_integral::bit_size<T> bit_size_type;
129 
130     // Define the minimum size (in bits) needed for the promoted type
131     // If T is the input type and P the promoted type, then the
132     // minimum number of bits for P are (below b stands for the number
133     // of bits of T):
134     // * if T is unsigned and P is unsigned: 2 * b
135     // * if T is signed and P is signed: 2 * b - 1
136     // * if T is unsigned and P is signed: 2 * b + 1
137     typedef typename std::conditional
138         <
139             (PromoteUnsignedToUnsigned && is_unsigned),
140             std::integral_constant<std::size_t, (2 * bit_size_type::value)>,
141             typename std::conditional
142                 <
143                     is_unsigned,
144                     std::integral_constant<std::size_t, (2 * bit_size_type::value + 1)>,
145                     std::integral_constant<std::size_t, (2 * bit_size_type::value - 1)>
146                 >::type
147         >::type min_bit_size_type;
148 
149     // Define the list of signed integral types we are going to use
150     // for promotion
151     typedef boost::mpl::list
152         <
153             short, int, long
154 #if defined(BOOST_HAS_LONG_LONG)
155             , boost::long_long_type
156 #endif
157         > signed_integral_types;
158 
159     // Define the list of unsigned integral types we are going to use
160     // for promotion
161     typedef boost::mpl::list
162         <
163             unsigned short, unsigned int, unsigned long, std::size_t
164 #if defined(BOOST_HAS_LONG_LONG)
165             , boost::ulong_long_type
166 #endif
167         > unsigned_integral_types;
168 
169     // Define the list of integral types that will be used for
170     // promotion (depending in whether we was to promote unsigned to
171     // unsigned or not)
172     typedef typename std::conditional
173         <
174             (is_unsigned && PromoteUnsignedToUnsigned),
175             unsigned_integral_types,
176             signed_integral_types
177         >::type integral_types;
178 
179 public:
180     typedef typename detail::promote_integral::promote_to_larger
181         <
182             T,
183             typename boost::mpl::begin<integral_types>::type,
184             typename boost::mpl::end<integral_types>::type,
185             min_bit_size_type::value
186         >::type type;
187 };
188 
189 
190 template <typename T, bool PromoteUnsignedToUnsigned, bool UseCheckedInteger>
191 class promote_integral
192     <
193         T, PromoteUnsignedToUnsigned, UseCheckedInteger, false
194     >
195 {
196 public:
197     typedef T type;
198 };
199 
200 }} // namespace boost::gil
201 
202 #endif // BOOST_GIL_PROMOTE_INTEGRAL_HPP
203