a4caa44580
* Add clang format file .clang-format * Use clang format on bitset --------- Co-authored-by: MeirGavish <meir.gavish@gmail.com>
203 lines
5.3 KiB
C
203 lines
5.3 KiB
C
/** @file bitset.h
|
|
*
|
|
* @brief A bitset for operating on flags
|
|
*/
|
|
#ifndef BITSET_H
|
|
#define BITSET_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
/**
|
|
* @def BITSET_BITS_PER_WORD
|
|
* @brief Number of bits in a word for a bitset.
|
|
*
|
|
* Number of bits in a word for a bitset. Will always be 32 here.
|
|
*/
|
|
#define BITSET_BITS_PER_WORD 32
|
|
|
|
/**
|
|
* @def BITSET_ARRAY_SIZE
|
|
* @brief Number of words in a bitset
|
|
*
|
|
* Number of words in every bitset. This represents the maximum number and each
|
|
* bitset will always use this number of words, though it's capacity can be any length
|
|
* from `1` to `BITSET_BITS_PER_WORD * BITSET_ARRAY_SIZE`
|
|
*/
|
|
#define BITSET_ARRAY_SIZE 8
|
|
|
|
/**
|
|
* @def BITSET_MAX_BITS
|
|
* @brief Maximum number of bits in a bitset
|
|
*/
|
|
#define BITSET_MAX_BITS (BITSET_BITS_PER_WORD * BITSET_ARRAY_SIZE)
|
|
|
|
/**
|
|
* @brief A bitset spread across multiple `uint32_t` words
|
|
*/
|
|
typedef struct Bitset
|
|
{
|
|
/**
|
|
* @brief Word array of `uint32_t` to hold the bitset data
|
|
*/
|
|
uint32_t* w;
|
|
|
|
/**
|
|
* @brief Number of bits in a word, will be 32
|
|
*/
|
|
uint32_t nbits;
|
|
|
|
/**
|
|
* @brief Number of words int the `w` array
|
|
*/
|
|
uint32_t nwords;
|
|
|
|
/**
|
|
* @brief Number of actual flags (nbits * nwords)
|
|
*/
|
|
uint32_t cap;
|
|
} Bitset;
|
|
|
|
/**
|
|
* @brief An iterator into a @ref Bitset
|
|
*
|
|
* This iterator will parse and find the next index to a '1' bit as efficiently as possible.
|
|
*
|
|
* There is no implementation of the following (yet):
|
|
* - Reverse iteration
|
|
* - Bit-by-bit iteration
|
|
* - Iterating on offsets to '0' bits
|
|
*/
|
|
typedef struct
|
|
{
|
|
/**
|
|
* @brief @ref Bitset this is iterating through
|
|
*/
|
|
const Bitset* bitset;
|
|
|
|
/**
|
|
* @brief Current word the iterator is on
|
|
*/
|
|
int word;
|
|
|
|
/**
|
|
* @brief Current bit the iterator is on
|
|
*/
|
|
int bit;
|
|
|
|
/**
|
|
* @brief Number of bits that have been iterated through in total
|
|
*/
|
|
int itr;
|
|
} BitsetItr;
|
|
|
|
/**
|
|
* @brief Set a flag in a bitset to a value
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
* @param idx the index of the flag to set
|
|
* @param on the value to set the flag to
|
|
*/
|
|
void bitset_set_idx(Bitset* bitset, int idx, bool on);
|
|
|
|
/**
|
|
* @brief Get the value of a flag
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
* @param idx the index of the flag to get
|
|
*
|
|
* @return the value of the flag as `true` or `false`
|
|
*/
|
|
bool bitset_get_idx(Bitset* bitset, int idx);
|
|
|
|
// Get the next free (set to 0) index in the bitset.
|
|
// It also sets the bit which it maybe should do... It really shouldn't do two things
|
|
// But it's such a fast operation idk. // TODO: decide what you wanna do
|
|
int bitset_allocate_idx(Bitset* bitset);
|
|
|
|
/**
|
|
* @brief Clear the bitset, all to 0
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
*/
|
|
void bitset_clear(Bitset* bitset);
|
|
|
|
/**
|
|
* @brief Check if a bitset is empty (all 0's)
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
*
|
|
* @return `true` if empty, `false` otherwise
|
|
*/
|
|
bool bitset_is_empty(Bitset* bitset);
|
|
|
|
/**
|
|
* @brief Count how many bits are set to `1` in a bitset
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
*
|
|
* @return The number of flags set to `1` in a bitset
|
|
*/
|
|
int bitset_num_set_bits(Bitset* bitset);
|
|
|
|
/**
|
|
* @brief Find the index of the nth set bit
|
|
*
|
|
* Find the index of the nth flag set to `1`. This function is useful to get one value quickly,
|
|
* but does not operate iteratively well. Use a @BitsetItr for iterative access to a bitset.
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
*
|
|
* @return The index of the nth flag set to `1` in the bitset
|
|
*/
|
|
int bitset_find_idx_of_nth_set(const Bitset* bitset, int n);
|
|
|
|
/**
|
|
* @brief Declare a @ref BitsetItr
|
|
*
|
|
* @param bitset A @ref Bitset to operate on
|
|
*
|
|
* @return A newly constructed BitsetItr
|
|
*/
|
|
BitsetItr bitset_itr_create(const Bitset* bitset);
|
|
|
|
/**
|
|
* @brief Get the index of the next set bit in the bitset from a @ref BitsetItr
|
|
*
|
|
* @param itr A @ref BitsetItr to operate on
|
|
*
|
|
* @return a positive number if successful, UNDEFINED otherwise (out-of-bounds)
|
|
*/
|
|
int bitset_itr_next(BitsetItr* itr);
|
|
|
|
/**
|
|
* @def BITSET_DEFINE
|
|
* @brief Make a standard bitset
|
|
*
|
|
* Make a bitset with a valid static array to store it's array of words.
|
|
*
|
|
* Use this to define bitsets in the code, specifically as a `static` scoped
|
|
* variable. The passed `name` will be the same name as the bitset.
|
|
*
|
|
* Usage example:
|
|
*
|
|
* ```c
|
|
* BITSET_DEFINE(_my_bitset, 128);
|
|
* // normal operation...
|
|
* bitset_clear(&_my_bitset);
|
|
* ```
|
|
*
|
|
* @param name the name of the bitset
|
|
* @param capacity the capacity of the bitset
|
|
*/
|
|
#define BITSET_DEFINE(name, capacity) \
|
|
static uint32_t name##_w[BITSET_ARRAY_SIZE] = {0}; \
|
|
static Bitset name = { \
|
|
.w = name##_w, \
|
|
.nbits = BITSET_BITS_PER_WORD, \
|
|
.nwords = BITSET_ARRAY_SIZE, \
|
|
.cap = capacity, \
|
|
};
|
|
|
|
#endif // BITSET_H
|