libmoost
/home/mhx/git/github/libmoost/include/moost/utils/bits.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 // A (growing) collection of bit manipulation utils
00029 
00030 #ifndef MOOST_UTILS_NEXT_POWER_OF_TWO_HPP__
00031 #define MOOST_UTILS_NEXT_POWER_OF_TWO_HPP__
00032 
00033 #include <stdexcept>
00034 #include <boost/type_traits.hpp>
00035 #include <boost/static_assert.hpp>
00036 #include <boost/cstdint.hpp>
00037 
00038 namespace moost { namespace utils {
00039 
00040 template<typename unsigned_intT>
00041 unsigned_intT next_power_of_two(unsigned_intT num)
00042 {
00043    // Only allow unsigned types (sign types get all messy!)
00044    BOOST_STATIC_ASSERT(boost::is_unsigned<unsigned_intT>::value);
00045 
00046    // Only allow types that are 8, 16, 32 or 64 bits
00047    BOOST_STATIC_ASSERT(
00048       sizeof(unsigned_intT) == 8 ||
00049       sizeof(unsigned_intT) == 4 ||
00050       sizeof(unsigned_intT) == 2 ||
00051       sizeof(unsigned_intT) == 1
00052       );
00053 
00054    // Make sure int_max_t is big enough to cope
00055    BOOST_STATIC_ASSERT(sizeof(boost::intmax_t) == 8);
00056 
00057    // Convert to intmax so we can bitshift without warning for
00058    // types that have less bits that we are going to manupulate
00059    boost::intmax_t intmax = num;
00060 
00061    --intmax;
00062 
00063    switch(sizeof(unsigned_intT))
00064    {
00065    case 8: // 64 bit
00066       intmax |= intmax >> 32;
00067    case 4: // 32 bit
00068       intmax |= intmax >> 16;
00069    case 2: // 16 bit
00070       intmax |= intmax >> 8;
00071    case 1: // 08 bit
00072       intmax |= intmax >> 4;
00073       intmax |= intmax >> 2;
00074       intmax |= intmax >> 1;
00075       break;
00076    }
00077 
00078    return static_cast<unsigned_intT>(++intmax);
00079 }
00080 
00081 template<typename unsigned_intT>
00082 bool is_power_of_two(unsigned_intT num)
00083 {
00084    // Only allow unsigned types
00085    BOOST_STATIC_ASSERT(boost::is_unsigned<unsigned_intT>::value);
00086 
00087    return (0 == num) || (0 == ((num - 1) & num));
00088 }
00089 
00090 template<typename unsigned_intT>
00091 signed char msb_set(unsigned_intT num)
00092 {
00093    // Only allow unsigned types
00094    BOOST_STATIC_ASSERT(boost::is_unsigned<unsigned_intT>::value);
00095 
00096    signed char cnt = -1; // No bits set
00097    while(num) { ++cnt; num >>= 1; }
00098 
00099    return cnt; // LSB is 0 and MSB is N-1 where N is the number of bits
00100 }
00101 
00102 }}
00103 
00104 #endif // MOOST_UTILS_NEXT_POWER_OF_TWO_HPP__