Last active
May 6, 2021 16:45
-
-
Save garettbass/2056e5f1a88d44fc7cfc7d6b16f4f220 to your computer and use it in GitHub Desktop.
A generic-length bitset in C
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
#pragma once | |
#include <assert.h> | |
#include <limits.h> | |
#include <stdbool.h> | |
#include <stddef.h> | |
#include <stdint.h> | |
//------------------------------------------------------------------------------ | |
typedef uint64_t bitset_block_t; | |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
enum { _BITSET_BLOCK_BITCOUNT = sizeof(bitset_block_t) * CHAR_BIT }; | |
enum { _BITSET_BITMASK_BITS = _BITSET_BLOCK_BITCOUNT - 1 }; | |
#define _BITSET_BLOCKCOUNT(BITCOUNT)\ | |
(((BITCOUNT) + (_BITSET_BLOCK_BITCOUNT-1) & -_BITSET_BLOCK_BITCOUNT)\ | |
/ _BITSET_BLOCK_BITCOUNT) | |
#define _BITSET_BLOCKINDEX(BITINDEX)\ | |
((BITINDEX) / _BITSET_BLOCK_BITCOUNT) | |
#define _BITSET_BITMASK(BITINDEX)\ | |
(((bitset_block_t)1) << (BITINDEX & _BITSET_BITMASK_BITS)) | |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
// bitset_t(N) | |
// Defines the type of a bitset with N bits. | |
// Usage: typedef bitset_t(128) bitset_128; | |
#define bitset_t(N)\ | |
union {\ | |
bitset_block_t _blocks[_BITSET_BLOCKCOUNT((N))];\ | |
char (*_blockcount)[_BITSET_BLOCKCOUNT((N))];\ | |
char (*_bitwidth)[(N)];\ | |
} | |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
// unsigned bitset_bitwidth(const bitset_t& bitset); | |
// Returns the bit-width in a given bitset, which is the value N provided to | |
// bitset_t(N) when defining the bitset type. | |
#define bitset_bitwidth(bitset) ((unsigned)sizeof(*(bitset)._bitwidth)) | |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
// bool bitset_get(const bitset_t& bitset, unsigned bitindex); | |
// Gets the value of the bit at the provided bit index. | |
static inline bool | |
bitset_get(const bitset_block_t* blocks, unsigned block_count, unsigned bitindex) { | |
const size_t blockindex = _BITSET_BLOCKINDEX(bitindex); | |
const bitset_block_t bitmask = _BITSET_BITMASK(bitindex); | |
return (blocks[blockindex] & bitmask) == bitmask; | |
} | |
#define bitset_get(bitset, bitindex)\ | |
(assert((bitindex) >= 0),\ | |
assert((bitindex) < bitset_bitwidth((bitset))),\ | |
bitset_get((bitset)._blocks, (sizeof((bitset)._blockcount)), (bitindex))) | |
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
// void bitset_set(const bitset_t& bitset, unsigned bitindex, bool bitvalue); | |
// Sets the value of the bit at the provided bit index. | |
static inline void | |
bitset_set(bitset_block_t* blocks, unsigned block_count, unsigned bitindex, bool bitvalue) { | |
const size_t blockindex = _BITSET_BLOCKINDEX(bitindex); | |
const bitset_block_t bitmask = _BITSET_BITMASK(bitindex); | |
const bitset_block_t block = blocks[blockindex]; | |
const bitset_block_t block_0 = (block & ~bitmask) * !bitvalue; | |
const bitset_block_t block_1 = (block | bitmask) * bitvalue; | |
blocks[blockindex] = block_0 | block_1; | |
} | |
#define bitset_set(bitset, bitindex, bitvalue)\ | |
(assert((bitindex) >= 0),\ | |
assert((bitindex) < bitset_bitwidth((bitset))),\ | |
bitset_set((bitset)._blocks, (sizeof((bitset)._blockcount)), (bitindex), (bitvalue))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment