]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
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 | |
f67539c2 TL |
5 | // |
6 | // Copyright (c) 2020, Debabrata Mandal <mandaldebabrata123@gmail.com> | |
92f5a8d4 TL |
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 | |
f67539c2 | 17 | // - Replace mpl meta functions with mp11 equivalents |
92f5a8d4 TL |
18 | // |
19 | #ifndef BOOST_GIL_PROMOTE_INTEGRAL_HPP | |
20 | #define BOOST_GIL_PROMOTE_INTEGRAL_HPP | |
21 | ||
f67539c2 | 22 | #include <boost/mp11/list.hpp> |
92f5a8d4 TL |
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, | |
f67539c2 | 49 | typename IntegralTypes, |
92f5a8d4 TL |
50 | std::size_t MinSize |
51 | > | |
52 | struct promote_to_larger | |
53 | { | |
f67539c2 TL |
54 | using current_type = boost::mp11::mp_first<IntegralTypes>; |
55 | using list_after_front = boost::mp11::mp_rest<IntegralTypes>; | |
92f5a8d4 TL |
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, | |
f67539c2 | 64 | list_after_front, |
92f5a8d4 TL |
65 | MinSize |
66 | >::type | |
67 | >::type; | |
68 | }; | |
69 | ||
70 | // The following specialization is required to finish the loop over | |
71 | // all list elements | |
f67539c2 TL |
72 | template <typename T, std::size_t MinSize> |
73 | struct promote_to_larger<T, boost::mp11::mp_list<>, MinSize> | |
92f5a8d4 TL |
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 | |
f67539c2 | 149 | using signed_integral_types = boost::mp11::mp_list |
92f5a8d4 TL |
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 | |
f67539c2 | 159 | using unsigned_integral_types = boost::mp11::mp_list |
92f5a8d4 TL |
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, | |
f67539c2 | 181 | integral_types, |
92f5a8d4 TL |
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 |