Last active
August 29, 2015 14:19
-
-
Save detomon/614afd4ef8aa4bba59e6 to your computer and use it in GitHub Desktop.
A collection of macro functions to manipulate bitfields of arbitrary size
This file contains hidden or 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
/** | |
* 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