Skip to content

Instantly share code, notes, and snippets.

@detomon
Last active August 29, 2015 14:19
Show Gist options
  • Save detomon/614afd4ef8aa4bba59e6 to your computer and use it in GitHub Desktop.
Save detomon/614afd4ef8aa4bba59e6 to your computer and use it in GitHub Desktop.
A collection of macro functions to manipulate bitfields of arbitrary size
/**
* Bitfield function collection
*
* Can be used to define variables which require more bits than the biggest data
* type can hold. Bits are organized within multiple `slots` which is an array
* of the biggest integer type available.
*
* However, multiple bits cannot overlap two slots:
* bit_get_field (mybits, 62, 8) will only contain bits from the first slot
*
* Example:
*
* // define bitfield with space for 90 bits
* bitfield_t mybits [BITFIELD_SIZE (90)];
*
* // clear all bits
* bitfield_clear (mybits);
*
* // set bit at offset 78 to 1
* bit_set (mybits, 78);
*
* // set bit 83 to 0
* bit_unset (mybits, 83);
*
* // set bit at offset 83 to 1
* bit_set (mybits, 83);
*
* // check if bit at offset 83 is set
* if (bit_check (mybits, 83)) {
* printf ("Bit 83 is set\n");
* }
*
* // get value of bit at offset 78 (0 or 1)
* int n = bit_get (mybits, 78);
*
* printf ("Bit 78: %d\n", n);
*/
#ifndef _BITFIELD_H_
#define _BITFIELD_H_
#include <stdint.h>
#include <string.h>
/**
* The type name
*
* Can be renamed to something else
*/
#define BITFIELD_TYPE bitfield_t
/**
* Check if system supports 64 bit integers
*/
#if INT64_MAX && INTPTR_MAX == INT64_MAX
typedef uint64_t BITFIELD_TYPE;
#else
typedef uint32_t BITFIELD_TYPE;
#endif
/**
* The inline modifier
*/
#ifndef _MSC_VER
#define BITFIELD_INLINE static inline
#else
#define BITFIELD_INLINE static __inline
#endif
/**
* Size of slot in bytes
*/
#define BITFIELD_SLOT_SIZE (sizeof (BITFIELD_TYPE))
/**
* Number of bits in slot
*/
#define BITFIELD_SHIFT (BITFIELD_SLOT_SIZE << 3)
/**
* Value for masking offset in slot
*/
#define BITFIELD_MASK (BITFIELD_SHIFT - 1)
/**
* Get number of bitfield slots required for given number of bits
*
* Example:
*
* // define variable `mybits` with space for 90 bits
* bitfield_t mybits [BITFIELD_SIZE (90)];
*/
#define BITFIELD_SIZE(length) ((((length) + (BITFIELD_SHIFT - 1)) & ~(BITFIELD_SHIFT - 1)) / BITFIELD_SHIFT)
/**
* General macro for reading and writing (slot aligned) bits
*/
#define BITFIELD_BIT(bitfield, offset, mask, opr) (((bitfield) [offset / BITFIELD_SHIFT]) opr (mask << (offset & BITFIELD_MASK)))
/**
* Clear bitfield variable
*
* Example:
*
* // clear all bits
* bitfield_clear (mybits);
*/
#define bitfield_clear(bitfield) memset ((bitfield), 0, sizeof (bitfield))
/**
* Returns value > 0 if specified bit is set
*
* Example:
*
* // check if bit at offset 65 is set
* if (bit_check (mybits, 65)) {
* ...
*/
BITFIELD_INLINE bitfield_t bit_check (BITFIELD_TYPE bitfield [], unsigned offset)
{
return BITFIELD_BIT (bitfield, offset, 1, &);
}
/**
* Returns exactly 1 if specified bit is set
*
* Example:
*
* // get value of bit at offset 15
* int bit = bit_get (mybits, 15);
*/
BITFIELD_INLINE int bit_get (BITFIELD_TYPE bitfield [], unsigned offset)
{
return bit_check (bitfield, offset) >> (offset & BITFIELD_MASK);
}
/**
* Returns bits with `size` at specified `offset`
*
* Example:
*
* // get value of bits 17-25
* bitfield_t bits = bit_get_field (mybits, 17, 9);
*/
BITFIELD_INLINE BITFIELD_TYPE bit_get_field (BITFIELD_TYPE bitfield [], unsigned offset, unsigned size)
{
BITFIELD_TYPE mask = ~(~(BITFIELD_TYPE) 0 << size);
return BITFIELD_BIT (bitfield, offset, mask, &) >> (offset & BITFIELD_MASK);
}
/**
* Set bit at specified `offset` to 1
*
* Example:
*
* // set bit at offset 27 to 1
* bit_set (mybits, 27);
*/
BITFIELD_INLINE void bit_set (BITFIELD_TYPE bitfield [], unsigned offset)
{
BITFIELD_BIT (bitfield, offset, 1, |=);
}
/**
* Set bits with `size` at specified `offset` to `value`
*
* `size` cannot be 0.
*
* Example:
*
* // set bits at offset 31-34 to 12
* bit_set_field (mybits, 31, 4, 12);
*/
BITFIELD_INLINE void bit_set_field (BITFIELD_TYPE bitfield [], unsigned offset, unsigned size, BITFIELD_TYPE value)
{
BITFIELD_TYPE mask = ~(~(BITFIELD_TYPE) 0 << size);
BITFIELD_TYPE slot = bitfield [offset / BITFIELD_SHIFT];
slot &= ~(mask << (offset & BITFIELD_MASK));
slot |= (value & mask) << offset;
bitfield [offset / BITFIELD_SHIFT] = slot;
}
/**
* Set bit at specified `offset` to 0
*
* Example:
*
* // set bit at offset 27 to 0
* bit_unset (mybits, 27);
*/
BITFIELD_INLINE void bit_unset (BITFIELD_TYPE bitfield [], unsigned offset)
{
BITFIELD_BIT (bitfield, offset, 1, &= ~);
}
/**
* Set bits with `size` at specified `offset` to 0
*
* Example:
*
* // set bits at offset 31-34 to 0
* bit_unset_field (mybits, 31, 4, 0);
*/
BITFIELD_INLINE BITFIELD_TYPE bit_unset_field (BITFIELD_TYPE bitfield [], unsigned offset, unsigned size)
{
BITFIELD_TYPE mask = (1 << (size - 1)) - 1;
return BITFIELD_BIT (bitfield, offset, mask, & ~);
}
#endif /* _BITFIELD_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment