Skip to content

Instantly share code, notes, and snippets.

@garettbass
Last active May 6, 2021 16:45
Show Gist options
  • Save garettbass/2056e5f1a88d44fc7cfc7d6b16f4f220 to your computer and use it in GitHub Desktop.
Save garettbass/2056e5f1a88d44fc7cfc7d6b16f4f220 to your computer and use it in GitHub Desktop.
A generic-length bitset in C
#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