Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C/C++ efficient bit array

Tags:

c++

arrays

c

bit

Can you recommend efficient/clean way to manipulate arbitrary length bit array?

Right now I am using regular int/char bitmask, but those are not very clean when array length is greater than datatype length.

std vector<bool> is not available for me.

like image 778
Anycorn Avatar asked Apr 13 '10 21:04

Anycorn


2 Answers

Since you mention C as well as C++, I'll assume that a C++-oriented solution like boost::dynamic_bitset might not be applicable, and talk about a low-level C implementation instead. Note that if something like boost::dynamic_bitset works for you, or there's a pre-existing C library you can find, then using them can be better than rolling your own.

Warning: None of the following code has been tested or even compiled, but it should be very close to what you'd need.

To start, assume you have a fixed bitset size N. Then something like the following works:

typedef uint32_t word_t;
enum { WORD_SIZE = sizeof(word_t) * 8 };

word_t data[N / 32 + 1];

inline int bindex(int b) { return b / WORD_SIZE; }
inline int boffset(int b) { return b % WORD_SIZE; }

void set_bit(int b) { 
    data[bindex(b)] |= 1 << (boffset(b)); 
}
void clear_bit(int b) { 
    data[bindex(b)] &= ~(1 << (boffset(b)));
}
int get_bit(int b) { 
    return data[bindex(b)] & (1 << (boffset(b));
}
void clear_all() { /* set all elements of data to zero */ }
void set_all() { /* set all elements of data to one */ }

As written, this is a bit crude since it implements only a single global bitset with a fixed size. To address these problems, you want to start with a data struture something like the following:

struct bitset { word_t *words; int nwords; };

and then write functions to create and destroy these bitsets.

struct bitset *bitset_alloc(int nbits) {
    struct bitset *bitset = malloc(sizeof(*bitset));
    bitset->nwords = (n / WORD_SIZE + 1);
    bitset->words = malloc(sizeof(*bitset->words) * bitset->nwords);
    bitset_clear(bitset);
    return bitset;
}

void bitset_free(struct bitset *bitset) {
    free(bitset->words);
    free(bitset);
}

Now, it's relatively straightforward to modify the previous functions to take a struct bitset * parameter. There's still no way to re-size a bitset during its lifetime, nor is there any bounds checking, but neither would be hard to add at this point.

like image 174
Dale Hagglund Avatar answered Sep 23 '22 00:09

Dale Hagglund


boost::dynamic_bitset if the length is only known in run time.

std::bitset if the length is known in compile time (although arbitrary).

like image 21
kennytm Avatar answered Sep 22 '22 00:09

kennytm