Skip to content

Instantly share code, notes, and snippets.

@d3x0r
Last active June 1, 2020 09:55
Show Gist options
  • Save d3x0r/adec6cdeec34592037dd3f81905d302d to your computer and use it in GitHub Desktop.
Save d3x0r/adec6cdeec34592037dd3f81905d302d to your computer and use it in GitHub Desktop.
Uniform length bit mask set (array of N bit items)

MASK SETS & FLAG SETS

MASK Sets are arrays of bit-fields of some bit-width (5, 3, ... ) they are set/returned as unsigned integer values. They are stored-in/accessed via a uint8_t which gives byte-offset calculations. they return their value as uintmax_t from the offset memory address directly; Some platforms(Arm) may SIGBUS because of wide offset accesses spanning word boundaries. This issue may be fixed by rounding, grabbing the word aligned values and shifting manually Declarataion/Instantiation of a mask set is done with MASKSET macro below

Example Usage

// declares a mask set called 'variableName'
MASKSET( variableName, 25 /*itemCount*/, 3 /*bitCount*/ );

int n = GETMASK( variableName, 3 ); // get the fourth item (offset by 9 bits)
n = n * 2/3;
SETMASK( variableName, 3, n ); // put back the new value.

But, I wanted a signed N bit field...

This is some JS code I did to sign extend a value... could be implemented into a macro like #define getSignedMask( maskSet, N, bits ) ( ( GETMASK(maskSet,N) & (1 << (bits-1)) )?~0<<bits | GETMASK(maskSet,N) : GETMASK(maskSet,N) ) Maybe with some work, collapse the double read access into a thread local temporary variable?

			if( signed ) {
				if(  n & ( 1 << (3-1) ) ) {
					var negone = ~0;
					negone <<= (count-1);
					n |= negone;
				}
			}

FLAGSET

THis is much simpler, basically an optimized mask set with a fixed with of 1.


	FLAGSET( bitArrayName, 1024 ); 
	if( !TESTFLAG( bitArrayName, 64 ) ) 
		SETFLAG( bitArrayName, 64 ) );
//----------- FLAG SETS (single bit fields) -----------------
/* the default type to use for flag sets - flag sets are arrays of bits
which can be set/read with/as integer values an index.
All of the fields in a maskset are the same width */
#define FLAGSETTYPE uintmax_t
/* the number of bits a specific type is.
Example
int bit_size_int = FLAGTYPEBITS( int ); */
#define FLAGTYPEBITS(t) (sizeof(t)*CHAR_BIT)
/* how many bits to add to make sure we round to the next greater index if even 1 bit overflows */
#define FLAGROUND(t) (FLAGTYPEBITS(t)-1)
/* the index of the FLAGSETTYPE which contains the bit in question */
#define FLAGTYPE_INDEX(t,n) (((n)+FLAGROUND(t))/FLAGTYPEBITS(t))
/* how big the flag set is in count of FLAGSETTYPEs required in a row ( size of the array of FLAGSETTYPE that contains n bits) */
#define FLAGSETSIZE(t,n) (FLAGTYPE_INDEX(t,n) * sizeof( FLAGSETTYPE ) )
// declare a set of flags...
#define FLAGSET(v,n) FLAGSETTYPE (v)[((n)+FLAGROUND(FLAGSETTYPE))/FLAGTYPEBITS(FLAGSETTYPE)]
// set a single flag index
#define SETFLAG(v,n) ( ( (v)[(n)/FLAGTYPEBITS((v)[0])] |= (FLAGSETTYPE)1 << ( (n) & FLAGROUND((v)[0]) )),1)
// clear a single flag index
#define RESETFLAG(v,n) ( ( (v)[(n)/FLAGTYPEBITS((v)[0])] &= ~( (FLAGSETTYPE)1 << ( (n) & FLAGROUND((v)[0]) ) ) ),0)
// test if a flags is set
// result is 0 or not; the value returned is the bit shifted within the word, and not always '1'
#define TESTFLAG(v,n) ( (v)[(n)/FLAGTYPEBITS((v)[0])] & ( (FLAGSETTYPE)1 << ( (n) & FLAGROUND((v)[0]) ) ) )
// reverse a flag from 1 to 0 and vice versa
// return value is undefined... and is a whole bunch of flags from some offset...
// if you want ot toggle and flag and test the result, use TESTGOGGLEFLAG() instead.
#define TOGGLEFLAG(v,n) ( (v)[(n)/FLAGTYPEBITS((v)[0])] ^= (FLAGSETTYPE)1 << ( (n) & FLAGROUND((v)[0]) ))
// Toggle a bit, return the state of the bit after toggling.
#define TESTTOGGLEFLAG(v,n) ( TOGGLEFLAG(v,n), TESTFLAG(v,n) )
// this is some ugly math :)
//----------- MASK SETS -----------------
// MASK Sets are arrays of bit-fields of some bit-width (5, 3, ... )
// they are set/returned as unsigned integer values.
// They are stored-in/accessed via a uint8_t which gives byte-offset calculations.
// they return their value as uintmax_t from the offset memory address directly;
// Some platforms(Arm) may SIGBUS because of wide offset accesses spanning word boundaries.
// This issue may be fixed by rounding, grabbing the word aligned values and shifting manually
// Declarataion/Instantiation of a mask set is done with MASKSET macro below
// 32 bits max for range on mask
#define MASK_MAX_LENGTH (sizeof(MASKSET_READTYPE)*CHAR_BIT)
/* gives a 32 bit mask possible from flagset..
- updated; return max int possible; but only the low N bits will be set
- mask sets are meant for small values, but could be used for like 21 bit fields. (another form of unicode encoding I suppose)
*/
#define MASKSET_READTYPE uintmax_t
// gives byte index...
#define MASKSETTYPE uint8_t
/* how many bits the type specified can hold
Parameters
t : data type to measure (int, uint32_t, ... ) */
#define MASKTYPEBITS(t) (sizeof(t)*CHAR_BIT)
/* the maximum number of bits storable in a type */
#define MASK_MAX_TYPEBITS(t) (sizeof(t)*CHAR_BIT)
/* round up to the next count of types that fits 1 bit - used as a cieling round factor */
#define MASKROUND(t) (MASKTYPEBITS(t)-1)
/* define MAX_MAX_ROUND factor based on MASKSET_READTYPE - how to read it... */
#define MASK_MAX_ROUND() (MASK_MAX_TYPEBITS(MASKSET_READTYPE)-1)
/* byte index of the start of the mask
Parameters
t : type to measure with
n : mask index */
#define MASKTYPE_INDEX(t,n) (((n)+MASKROUND(t))/MASKTYPEBITS(t))
/* The number of bytes the set would be.
Parameters
t : the given type to measure with
n : the count of masks to fit. */
#define MASKSETSIZE(t,n) (MASKTYPE_INDEX(t,(n+1)))
// declare a set of flags...
#define MASK_TOP_MASK_VAL(length,val) ((val)&( ((MASKSET_READTYPE)-1) >> ((sizeof(MASKSET_READTYPE) * CHAR_BIT)-(length)) ))
/* the mask in the dword resulting from shift-right. (gets a mask of X bits in length) */
#define MASK_TOP_MASK(length) ( ((MASKSET_READTYPE)-1) >> ((sizeof(MASKSET_READTYPE) * CHAR_BIT)-(length)) )
/* the mast in the dword shifted to the left to overlap the field in the word */
#define MASK_MASK(n,length) (MASK_TOP_MASK(length) << (((n)*(length)) & (sizeof(MASKSET_READTYPE) - 1) ) )
// masks value with the mask size, then applies that mask back to the correct word indexing
#define MASK_MASK_VAL(n,length,val) (MASK_TOP_MASK_VAL(length,val) << (((n)*(length))&0x7) )
/* declare a mask set.
MASKSET( maskVariableName
, 32 //number of items
, 5 // number of bits per field
);
declares
uint8_t maskVariableName[ (32*5 +(CHAR_BIT-1))/CHAR_BIT ]; //data array used for storage.
const int askVariableName_mask_size = 5; // used aautomatically by macros
*/
#define MASKSET(v,n,r) MASKSETTYPE (v)[(((n)*(r))+MASK_MAX_ROUND())/MASKTYPEBITS(MASKSETTYPE)]; const int v##_mask_size = r;
/* set a field index to a value
SETMASK( askVariableName, 3, 13 ); // set set member 3 to the value '13'
*/
#define SETMASK(v,n,val) (((MASKSET_READTYPE*)((v)+((n)*(v##_mask_size))/MASKTYPEBITS((v)[0])))[0] = \
( ((MASKSET_READTYPE*)((v)+((n)*(v##_mask_size))/MASKTYPEBITS(uint8_t)))[0] \
& (~(MASK_MASK(n,v##_mask_size))) ) \
| MASK_MASK_VAL(n,v##_mask_size,val) )
/* get the value of a field
GETMASK( maskVariableName, 3 ); // returns '13' given the SETMASK() example code.
*/
#define GETMASK(v,n) ( ( ((MASKSET_READTYPE*)((v)+((n)*(v##_mask_size))/MASKTYPEBITS((v)[0])))[0] \
& MASK_MASK(n,v##_mask_size) ) \
>> (((n)*(v##_mask_size))&0x7))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment