libmoost
/home/mhx/git/github/libmoost/include/moost/math/integer/log2.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00030 #ifndef MOOST_MATH_INTEGER_LOG2_HPP
00031 #define MOOST_MATH_INTEGER_LOG2_HPP
00032 
00033 #include <cassert>
00034 #include <climits>
00035 
00036 #include <boost/static_assert.hpp>
00037 #include <boost/type_traits/is_unsigned.hpp>
00038 
00039 namespace moost { namespace math { namespace integer {
00040 
00041 #ifdef __GNUC__
00042 namespace detail {
00043 
00044 inline int count_leading_zeroes(unsigned arg)
00045 {
00046    return __builtin_clz(arg);
00047 }
00048 
00049 inline int count_leading_zeroes(unsigned long arg)
00050 {
00051    return __builtin_clzl(arg);
00052 }
00053 
00054 inline int count_leading_zeroes(boost::ulong_long_type arg)
00055 {
00056    return __builtin_clzll(arg);
00057 }
00058 
00059 }
00060 #endif
00061 
00062 template <typename T>
00063 inline unsigned log2_compat(T arg)
00064 {
00065    BOOST_STATIC_ASSERT(boost::is_unsigned<T>::value);
00066 
00067    // This could be optimised using binary search, but I doubt
00068    // it'll ever get used... ;)
00069    unsigned r = 0;
00070 
00071    while (arg > static_cast<T>(1))
00072    {
00073       arg >>= 1;
00074       ++r;
00075    }
00076 
00077    return r;
00078 }
00079 
00093 template <typename T>
00094 inline unsigned log2(T arg)
00095 {
00096    BOOST_STATIC_ASSERT(boost::is_unsigned<T>::value);
00097 
00098    assert(arg > 0U);
00099 
00100 #ifdef __GNUC__
00101    return (8U*unsigned(sizeof(T)) - 1U) - detail::count_leading_zeroes(arg);
00102 #else
00103    return log2_compat(arg);
00104 #endif
00105 }
00106 
00107 }}}
00108 
00109 #endif