#ifndef __BitUtils__
#define __BitUtils__
#include <cstdint>
#include <cstring>
#include "Debug/Assertion.hpp"
#include <climits>
namespace Lib {
class BitUtils
{
public:
static unsigned log2(unsigned v)
{
#ifdef __GNUC__
if(v == 0)
return 0;
return (sizeof(v) * CHAR_BIT - 1) - __builtin_clz(v);
#else
unsigned bit = 0;
while(v >>= 1) bit++;
return bit;
#endif
}
static unsigned oneBits(unsigned v)
{
#ifdef __GNUC__
return __builtin_popcount(v);
#else
unsigned bits = 0;
while(v) {
bits += v & 1;
v >>= 1;
}
return bits;
#endif
}
template<unsigned lower, unsigned upper>
static constexpr uint64_t bitmask64() {
static_assert(lower < upper, "empty range");
static_assert(upper - lower <= 64, "too many bits");
uint64_t mask = ~0;
mask >>= lower;
mask <<= lower;
mask <<= 64 - upper;
mask >>= 64 - upper;
return mask;
}
template<unsigned lower, unsigned upper>
static uint64_t getBits(const uint64_t& bits) {
auto mask = bitmask64<lower, upper>();
return (bits & mask) >> lower;
}
template<unsigned lower, unsigned upper>
static void setBits(uint64_t& bits, uint64_t data) {
auto mask = bitmask64<lower, upper>();
data <<= lower;
data &= mask;
IGNORE_MAYBE_UNINITIALIZED(
bits &= ~mask;
)
bits |= data;
}
};
};
#define END_BITFIELD 0,
#define BITFIELD_MEMBER(type, getter, setter, width, rest) width + CAR(rest),\
type getter() const { return BitUtils::getBits<CAR(rest), CAR(rest) + width>(this->_content); }\
void setter(type val) { BitUtils::setBits<CAR(rest), CAR(rest) + width>(this->_content, val); }\
CDR(rest)
#define BITFIELD(bits, members)\
static_assert(bits >= CAR(members), "bitfield must have less than " #bits "bits");\
CDR(members)
#define BITFIELD_PTR_GET(type, getter, mask) \
type *getter() const { return reinterpret_cast<type *>(BitUtils::getBits<mask, CHAR_BIT * sizeof(type *)>(this->_content)); }
#define BITFIELD_PTR_SET(type, setter, mask) \
void setter(const type *val) { BitUtils::setBits<mask, CHAR_BIT * sizeof(type *)>(this->_content, reinterpret_cast<uint64_t>(val)); }
#endif