libmoost
|
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