Boost GIL


promote_integral.hpp
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>::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  using current_type = typename boost::mpl::deref<Iterator>::type;
57 
58  using type = typename std::conditional
59  <
60  (bit_size<current_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;
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  using type = T;
80 };
81 
82 }} // namespace detail::promote_integral
83 
116 template
117 <
118  typename T,
119  bool PromoteUnsignedToUnsigned = false,
120  bool UseCheckedInteger = false,
121  bool IsIntegral = std::is_integral<T>::value
122 >
124 {
125 private:
126  static bool const is_unsigned = std::is_unsigned<T>::value;
127 
128  using bit_size_type = detail::promote_integral::bit_size<T>;
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  using min_bit_size_type = 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;
148 
149  // Define the list of signed integral types we are going to use
150  // for promotion
151  using signed_integral_types = boost::mpl::list
152  <
153  short, int, long
154 #if defined(BOOST_HAS_LONG_LONG)
155  , boost::long_long_type
156 #endif
157  >;
158 
159  // Define the list of unsigned integral types we are going to use
160  // for promotion
161  using unsigned_integral_types = 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  >;
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  using integral_types = typename std::conditional
173  <
174  (is_unsigned && PromoteUnsignedToUnsigned),
175  unsigned_integral_types,
176  signed_integral_types
177  >::type;
178 
179 public:
180  using type = 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;
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  using type = T;
198 };
199 
200 }} // namespace boost::gil
201 
202 #endif // BOOST_GIL_PROMOTE_INTEGRAL_HPP
Meta-function to define an integral type with size than is (roughly) twice the bit size of T.
Definition: promote_integral.hpp:123