Created
April 9, 2014 00:10
-
-
Save karlgluck/10211717 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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