1 #ifndef BOOST_NUMERIC_UTILITY_HPP
2 #define BOOST_NUMERIC_UTILITY_HPP
4 // Copyright (c) 2015 Robert Ramey
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
10 #include <cstdint> // intmax_t, uintmax_t, uint8_t, ...
12 #include <type_traits> // conditional
15 #include <utility> // pair
17 #include <boost/integer.hpp> // (u)int_t<>::least, exact
20 namespace safe_numerics {
23 ///////////////////////////////////////////////////////////////////////////////
26 // provokes warning message with names of type T
27 // usage - print_types<T, ...>;
28 // see https://cukic.co/2019/02/19/tmp-testing-and-debugging-templates
32 using print_type = typename Tx::error_message;
34 template <typename... Ts>
35 struct [[deprecated]] print_types {};
37 // display value of constexpr during compilation
38 // usage print_value(N) pn;
42 value = N < 0 ? N - 256 : N + 256
46 // static warning - same as static_assert but doesn't
52 struct static_test<std::false_type>{
53 [[deprecated]] static_test(){}
57 using static_warning = static_test<T>;
60 // can be called by constexpr to produce a compile time
61 // trap of parameter passed is false.
62 // usage constexpr_assert(bool)
63 constexpr int constexpr_assert(const bool tf){
68 ///////////////////////////////////////////////////////////////////////////////
69 // return an integral constant equal to the the number of bits
70 // held by some integer type (including the sign bit)
73 using bits_type = std::integral_constant<
75 std::numeric_limits<T>::digits
76 + (std::numeric_limits<T>::is_signed ? 1 : 0)
80 From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
81 Find the log base 2 of an integer with a lookup table
83 static const char LogTable256[256] =
85 #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
86 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
87 LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
88 LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
91 unsigned int v; // 32-bit word to find the log of
92 unsigned r; // r will be lg(v)
93 register unsigned int t, tt; // temporaries
97 r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
101 r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
104 The lookup table method takes only about 7 operations to find the log of a 32-bit value.
105 If extended for 64-bit quantities, it would take roughly 9 operations. Another operation
106 can be trimmed off by using four tables, with the possible additions incorporated into each.
107 Using int table elements may be faster, depending on your architecture.
110 namespace ilog2_detail {
113 constexpr inline unsigned int ilog2(const typename boost::uint_t<N>::exact & t){
114 using half_type = typename boost::uint_t<N/2>::exact;
115 const half_type upper_half = static_cast<half_type>(t >> N/2);
116 const half_type lower_half = static_cast<half_type>(t);
117 return upper_half == 0 ? ilog2<N/2>(lower_half) : N/2 + ilog2<N/2>(upper_half);
120 constexpr inline unsigned int ilog2<8>(const typename boost::uint_t<8>::exact & t){
121 #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
122 const char LogTable256[256] = {
123 static_cast<char>(-1), 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
124 LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
125 LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
127 return LogTable256[t];
133 constexpr inline unsigned int ilog2(const T & t){
134 // log not defined for negative numbers
138 return ilog2_detail::ilog2<bits_type<T>::value>(
140 typename boost::uint_t<
147 // the number of bits required to render the value in x
148 // including sign bit
150 constexpr inline unsigned int significant_bits(const T & t){
151 return 1 + ((t < 0) ? ilog2(~t) : ilog2(t));
155 // give the value t, return the number which corresponds
156 // to all 1's which is higher than that number
158 constexpr unsigned int bits_value(const T & t){
159 const unsigned int sb = significant_bits(t);
160 const unsigned int sb_max = significant_bits(std::numeric_limits<T>::max());
161 return sb < sb_max ? ((sb << 1) - 1) : std::numeric_limits<T>::max();
165 ///////////////////////////////////////////////////////////////////////////////
166 // meta functions returning types
168 // If we use std::max in here we get internal compiler errors
169 // with MSVC (tested VC2017) ...
171 // Notes from https://en.cppreference.com/w/cpp/algorithm/max
172 // Capturing the result of std::max by reference if one of the parameters
173 // is rvalue produces a dangling reference if that parameter is returned.
176 // turns out this problem crashes all versions of gcc compilers. So
177 // make sure we return by value
178 //constexpr const T & max(
179 constexpr inline T max(
183 return lhs > rhs ? lhs : rhs;
186 // given a signed range, return type required to hold all the values
192 using signed_stored_type = typename boost::int_t<
194 significant_bits(Min),
195 significant_bits(Max)
199 // given an unsigned range, return type required to hold all the values
206 using unsigned_stored_type = typename boost::uint_t<
207 significant_bits(Max)
210 ///////////////////////////////////////////////////////////////////////////////
211 // constexpr functions
213 // need our own version because official version
214 // a) is not constexpr
215 // b) is not guarenteed to handle non-assignable types
217 constexpr inline std::pair<T, T>
218 minmax(const std::initializer_list<T> & l){
219 assert(l.size() > 0);
220 const T * minimum = l.begin();
221 const T * maximum = l.begin();
222 for(const T * i = l.begin(); i != l.end(); ++i){
229 return std::pair<T, T>{* minimum, * maximum};
233 // a) figure number of significant bits
234 // b) return a value with all significant bits set
236 // 3 == round_out(2) because
237 // 2 == 10 and 3 == 11
239 constexpr inline T round_out(const T & t){
241 const std::uint8_t sb = utility::significant_bits(t);
242 return (sb < sizeof(T) * 8)
244 : std::numeric_limits<T>::max();
247 const std::uint8_t sb = utility::significant_bits(~t);
248 return (sb < sizeof(T) * 8)
249 ? ~(((T)1 << sb) - 1)
250 : std::numeric_limits<T>::min();
258 #endif // BOOST_NUMERIC_UTILITY_HPP