Simplified integer_log2 implementation.

Removed unnecessary template specializations, removed workaround for
compilers not supporting partial template specializations. Use unsigned
integers for bit counting, which allows to replace the division with
a shift.
This commit is contained in:
Andrey Semashev
2021-12-21 20:39:22 +03:00
parent a832e8fe65
commit c5df07cb21

View File

@ -15,98 +15,72 @@
#ifndef BOOST_INTEGER_INTEGER_LOG2_HPP #ifndef BOOST_INTEGER_INTEGER_LOG2_HPP
#define BOOST_INTEGER_INTEGER_LOG2_HPP #define BOOST_INTEGER_INTEGER_LOG2_HPP
#include <boost/limits.hpp> #include <climits>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#if defined(BOOST_BORLANDC)
#include <climits>
#endif
namespace boost { namespace boost {
namespace detail { namespace detail {
template <typename T> template <typename T>
int integer_log2_impl(T x, int n) { inline int integer_log2_impl(T x, unsigned int n)
{
int result = 0;
int result = 0; while (x != 1)
{
const T t = static_cast<T>(x >> n);
if (t)
{
result += static_cast<int>(n);
x = t;
}
n >>= 1u;
}
while (x != 1) { return result;
}
const T t = static_cast<T>(x >> n); // helper to find the maximum power of two
if (t) { // less than p
result += n; template <unsigned int p, unsigned int n, bool = (2u*n < p)>
x = t; struct max_pow2_less :
} public max_pow2_less< p, 2u*n >
n /= 2; {
};
} template <unsigned int p, unsigned int n>
struct max_pow2_less<p, n, false>
{
BOOST_STATIC_CONSTANT(unsigned int, value = n);
};
return result; } // namespace detail
}
// ------------
// integer_log2
// ------------
template <typename T>
inline int integer_log2(T x)
{
BOOST_ASSERT(x > 0);
// helper to find the maximum power of two return detail::integer_log2_impl
// less than p (more involved than necessary, (
// to avoid PTS) x,
// detail::max_pow2_less<
template <int p, int n> // We could simply rely on numeric_limits but sometimes
struct max_pow2_less { // Borland tries to use numeric_limits<const T>, because
// of its usual const-related problems in argument deduction
enum { c = 2*n < p }; // - gps
// Also, numeric_limits is not specialized for __int128 in libstdc++.
BOOST_STATIC_CONSTANT(int, value = sizeof(T) * CHAR_BIT,
c ? (max_pow2_less< c*p, 2*c*n>::value) : n); CHAR_BIT / 2u
>::value
}; );
}
template <>
struct max_pow2_less<0, 0> {
BOOST_STATIC_CONSTANT(int, value = 0);
};
// this template is here just for Borland :(
// we could simply rely on numeric_limits but sometimes
// Borland tries to use numeric_limits<const T>, because
// of its usual const-related problems in argument deduction
// - gps
template <typename T>
struct width {
#ifdef BOOST_BORLANDC
BOOST_STATIC_CONSTANT(int, value = sizeof(T) * CHAR_BIT);
#else
BOOST_STATIC_CONSTANT(int, value = (std::numeric_limits<T>::digits));
#endif
};
} // detail
// ---------
// integer_log2
// ---------------
//
template <typename T>
int integer_log2(T x) {
BOOST_ASSERT(x > 0);
const int n = detail::max_pow2_less<
detail::width<T> :: value, 4
> :: value;
return detail::integer_log2_impl(x, n);
}
} }
#endif // BOOST_INTEGER_INTEGER_LOG2_HPP
#endif // include guard