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