Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:37

0001 #ifndef BOOST_NUMERIC_UTILITY_HPP
0002 #define BOOST_NUMERIC_UTILITY_HPP
0003 
0004 //  Copyright (c) 2015 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #include <cstdint> // intmax_t, uintmax_t, uint8_t, ...
0011 #include <algorithm>
0012 #include <type_traits> // conditional
0013 #include <limits>
0014 #include <cassert>
0015 #include <utility> // pair
0016 
0017 #include <boost/integer.hpp> // (u)int_t<>::least, exact
0018 
0019 namespace boost {
0020 namespace safe_numerics {
0021 namespace utility {
0022 
0023 ///////////////////////////////////////////////////////////////////////////////
0024 // used for debugging
0025 
0026 // provokes warning message with names of type T
0027 // usage - print_types<T, ...>;
0028 // see https://cukic.co/2019/02/19/tmp-testing-and-debugging-templates
0029 
0030 /*
0031 template<typename Tx>
0032 using print_type = typename Tx::error_message;
0033 */
0034 template <typename... Ts>
0035 struct [[deprecated]] print_types {};
0036 
0037 // display value of constexpr during compilation
0038 // usage print_value(N) pn;
0039 template<int N> 
0040 struct print_value {
0041     enum test : char {
0042         value = N < 0 ? N - 256 : N + 256
0043     };
0044 };
0045 
0046 // static warning - same as static_assert but doesn't
0047 // stop compilation. 
0048 template <typename T>
0049 struct static_test{};
0050 
0051 template <>
0052 struct static_test<std::false_type>{
0053     [[deprecated]] static_test(){}
0054 };
0055 
0056 template<typename T>
0057 using static_warning = static_test<T>;
0058 
0059 /*
0060 // can be called by constexpr to produce a compile time
0061 // trap of parameter passed is false.
0062 // usage constexpr_assert(bool)
0063 constexpr int constexpr_assert(const bool tf){
0064     return 1 / tf;
0065 }
0066 */
0067 
0068 ///////////////////////////////////////////////////////////////////////////////
0069 // return an integral constant equal to the the number of bits
0070 // held by some integer type (including the sign bit)
0071 
0072 template<typename T>
0073 using bits_type = std::integral_constant<
0074     int,
0075     std::numeric_limits<T>::digits
0076     + (std::numeric_limits<T>::is_signed ? 1 : 0)
0077 >;
0078 
0079 /*
0080 From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
0081 Find the log base 2 of an integer with a lookup table
0082 
0083     static const char LogTable256[256] =
0084     {
0085     #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
0086         -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
0087         LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
0088         LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
0089     };
0090 
0091     unsigned int v; // 32-bit word to find the log of
0092     unsigned r;     // r will be lg(v)
0093     register unsigned int t, tt; // temporaries
0094 
0095     if (tt = v >> 16)
0096     {
0097       r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
0098     }
0099     else 
0100     {
0101       r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
0102     }
0103 
0104 The lookup table method takes only about 7 operations to find the log of a 32-bit value. 
0105 If extended for 64-bit quantities, it would take roughly 9 operations. Another operation
0106 can be trimmed off by using four tables, with the possible additions incorporated into each.
0107 Using int table elements may be faster, depending on your architecture.
0108 */
0109 
0110 namespace ilog2_detail {
0111 
0112     template<int N>
0113     constexpr inline unsigned int ilog2(const typename boost::uint_t<N>::exact & t){
0114         using half_type = typename boost::uint_t<N/2>::exact;
0115         const half_type upper_half = static_cast<half_type>(t >> N/2);
0116         const half_type lower_half = static_cast<half_type>(t);
0117         return upper_half == 0 ? ilog2<N/2>(lower_half) : N/2 + ilog2<N/2>(upper_half);
0118     }
0119     template<>
0120     constexpr inline unsigned int ilog2<8>(const typename boost::uint_t<8>::exact & t){
0121         #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
0122         const char LogTable256[256] = {
0123             static_cast<char>(-1), 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
0124             LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
0125             LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
0126         };
0127         return LogTable256[t];
0128     }
0129 
0130 } // ilog2_detail
0131 
0132 template<typename T>
0133 constexpr inline unsigned int ilog2(const T & t){
0134 //  log not defined for negative numbers
0135 //    assert(t > 0);
0136     if(t == 0)
0137         return 0;
0138     return ilog2_detail::ilog2<bits_type<T>::value>(
0139         static_cast<
0140             typename boost::uint_t<
0141                 bits_type<T>::value
0142             >::least
0143         >(t)
0144     );
0145 }
0146 
0147 // the number of bits required to render the value in x
0148 // including sign bit
0149 template<typename T>
0150 constexpr inline unsigned int significant_bits(const T & t){
0151     return 1 + ((t < 0) ? ilog2(~t) : ilog2(t));
0152 }
0153 
0154 /*
0155 // give the value t, return the number which corresponds
0156 // to all 1's which is higher than that number
0157 template<typename T>
0158 constexpr unsigned int bits_value(const T & t){
0159     const unsigned int sb = significant_bits(t);
0160     const unsigned int sb_max = significant_bits(std::numeric_limits<T>::max());
0161     return sb < sb_max ? ((sb << 1) - 1) : std::numeric_limits<T>::max();
0162 }
0163 */
0164 
0165 ///////////////////////////////////////////////////////////////////////////////
0166 // meta functions returning types
0167 
0168 // If we use std::max in here we get internal compiler errors
0169 // with MSVC (tested VC2017) ...
0170 
0171 // Notes from https://en.cppreference.com/w/cpp/algorithm/max
0172 // Capturing the result of std::max by reference if one of the parameters
0173 // is rvalue produces a dangling reference if that parameter is returned.
0174 
0175 template <class T>
0176 // turns out this problem crashes all versions of gcc compilers.  So
0177 // make sure we return by value
0178 //constexpr const T & max(
0179 constexpr inline T max(
0180     const T & lhs,
0181     const T & rhs
0182 ){
0183     return lhs > rhs ? lhs : rhs;
0184 }
0185 
0186 // given a signed range, return type required to hold all the values
0187 // in the range
0188 template<
0189     std::intmax_t Min,
0190     std::intmax_t Max
0191 >
0192 using signed_stored_type = typename boost::int_t<
0193     max(
0194         significant_bits(Min),
0195         significant_bits(Max)
0196     ) + 1
0197 >::least ;
0198 
0199 // given an unsigned range, return type required to hold all the values
0200 // in the range
0201 template<
0202     std::uintmax_t Min,
0203     std::uintmax_t Max
0204 >
0205 // unsigned range
0206 using unsigned_stored_type = typename boost::uint_t<
0207     significant_bits(Max)
0208 >::least;
0209 
0210 ///////////////////////////////////////////////////////////////////////////////
0211 // constexpr functions
0212 
0213 // need our own version because official version
0214 // a) is not constexpr
0215 // b) is not guarenteed to handle non-assignable types
0216 template<typename T>
0217 constexpr inline std::pair<T, T>
0218 minmax(const std::initializer_list<T> & l){
0219     assert(l.size() > 0);
0220     const T * minimum = l.begin();
0221     const T * maximum = l.begin();
0222     for(const T * i = l.begin(); i != l.end(); ++i){
0223         if(*i < * minimum)
0224             minimum = i;
0225         else
0226         if(* maximum < *i)
0227             maximum = i;
0228     }
0229     return std::pair<T, T>{* minimum, * maximum};
0230 }
0231 
0232 // for any given t
0233 // a) figure number of significant bits
0234 // b) return a value with all significant bits set
0235 // so for example:
0236 // 3 == round_out(2) because
0237 // 2 == 10 and 3 == 11
0238 template<typename T>
0239 constexpr inline T round_out(const T & t){
0240     if(t >= 0){
0241         const std::uint8_t sb = utility::significant_bits(t);
0242         return (sb < sizeof(T) * 8)
0243             ? ((T)1 << sb) - 1
0244             : std::numeric_limits<T>::max();
0245     }
0246     else{
0247         const std::uint8_t sb = utility::significant_bits(~t);
0248         return (sb < sizeof(T) * 8)
0249             ? ~(((T)1 << sb) - 1)
0250             : std::numeric_limits<T>::min();
0251     }
0252 }
0253 
0254 } // utility
0255 } // safe_numerics
0256 } // boost
0257 
0258 #endif  // BOOST_NUMERIC_UTILITY_HPP