Skip to content

Instantly share code, notes, and snippets.

@karlgluck
Created April 9, 2014 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save karlgluck/10211717 to your computer and use it in GitHub Desktop.
Save karlgluck/10211717 to your computer and use it in GitHub Desktop.
// this lets you write bits to a buffer and scan them back:
//
// char buffer[3];
// bitfield writer(buffer);
// writer.write(2,6); // write "2" as a 6-bit uint
// writer.write(9,4); // write "9" as a 4-bit uint
// writer.write(0,1); // etc
// writer.write(1,2);
// size_t bytes = writer.bytes(buffer); // bytes == 2
// bitfield reader(buffer);
// bitfield.read(6); // read 6 bits => returns 2
// bitfield.read(4); // read 4 bits => returns 9
// bitfield.read(1); // => 0
// bitfield.read(2); // => 1
// this is a really rough draft just to get the idea down. it passes the smoke test
// but I haven't done any QC, and excuse the stylistic mess!
// I put this this code in the public domain -- do what you like with it. credit me if you want, or not!
struct bitfield {
unsigned int *ptr;
size_t base;
bitfield(void *ptr) : ptr((unsigned int *)ptr), base(0) {}
void write(unsigned int v, size_t bits);
unsigned int read(size_t bits);
size_t bytes(void *start) const;
};
void bitfield::write(unsigned int v, size_t bits) {
static const int WORD_BITS = sizeof(unsigned int) * 8;
size_t new_base = base + bits;
if (new_base > WORD_BITS) {
size_t underflow = WORD_BITS - base;
write(v, underflow);
v >>= underflow;
new_base -= WORD_BITS;
bits = new_base;
}
// mask out the upper bits and place the value into the buffer. Note that
// this is only necessary if this is uninitialized or v contains bits
// beyond the number indicated.
*ptr = ((*ptr) & ((~(unsigned int)0) >> (WORD_BITS - base))) | (v << base);
if (new_base == WORD_BITS) { ++ptr; base = 0; } else { base = new_base; }
}
unsigned int bitfield::read(size_t bits) {
static const int WORD_BITS = sizeof(unsigned int) * 8;
if (bits > 32) return -1;
unsigned int retval = 0;
size_t new_base = base + bits;
if (new_base > WORD_BITS) {
// split read
size_t underflow = WORD_BITS - base;
retval = (*ptr) >> base; // automatically masked by shift from top
++ptr;
size_t overflow = new_base - WORD_BITS;
retval |= ((((~(unsigned int)0) >> (WORD_BITS - overflow)) & (*ptr)) << underflow);
base = overflow;
} else {
// single read
retval = ((~(unsigned int)0) >> (WORD_BITS - bits)) & ((*ptr) >> base);
base = new_base;
}
return retval;
}
size_t bitfield::bytes(void *start) const {
return ((char *)ptr - (char *)start) + ((base + 7) >> 3); // base == 0: 0, 1 <= base <= 8: 1, ... 25 <= base <= 31: 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment