Bits and Flags C/C++ Macros
This document is a part of a collection of macros. For introductory remarks, see the first part (General Purpose Macros).
For a review of macrosyntax rules and related tips and tricks, see Writing Macros.
For the typedefs DWORD, WORD, BYTE and CHAR, click here.

CATEGORY 
MACRO 
BITS MANAGEMENT

mBits,
mBitsExcept,
mTestBits,
mTestBitsExcept
mBitsOn,
mBitsOnExcept,
mBitsOff,
mBitsOffExcept
mBitsOnOff,
mBitsOnOffExcept,
mBitsToggle,
mBitsToggleExcept

FlagArrays

mFlagArraySize,
mFlagArrayReset
mTestFAF,
mSetFAF,
mResetFAF,
mToggleFAF

Bits Management
Code:

#define mBits(x,m) ((x)&(m))
#define mBitsExcept(x,m,be) (((x)&(m))& ~(be))
#define mTestBits(x,m,b) (mBits(x,m)==(b)))
#define mTestBitsExcept(x,m,b,be) (mBitsExcept(x,m,be)==(b))
#define mBitsOn(lvx,by) ((lvx)=(by))
#define mBitsOnExcept(lvx,by,be) ((lvx)=(by)&~(be))
#define mBitsOff(lvx,bn) ((lvx)&= ~(bn))
#define mBitsOffExcept(lvx,bn,be) ((lvx)&= ~((bn)&~(be)))
#define mBitsToggle(lvx,b) ((lvx)^= (b))
#define mBitsToggleExcept(lvx,b,be) ((lvx)^= ((b)&~(be)))
#define mBitsOnOff(lvx,by,bn) {mBitsOff(lvx,bn);mBitsOn(lvx,by);}
#define mBitsOnOffExcept(lvx,by,bn,be) {mBitsOffExcept(lvx,bn,be);mBitsOnExcept(lvx,by,be);}

Bits management macros are typically used with bit flagwords in which every bit stands for a true/false flag. On 32bit platforms, the most efficient usage of these macros consists in reserving a DWORD variable for up to 32 different flags (even when the number of flags to manage is as small as 2, using a whole DWORD still leads to the best performance).
Arguments:
x is the main operand value.
lvx is the main operand leftvalue; the macros which contain lvx assign a new value to it and also return the new value.
m is a bit mask, b any combination of bit flags,
by (yes/on bits), bn (not/off bits), be (except bits) may contain any bit pattern
All the arguments shauld be of an integer type. In any case, they must be of a type which admits the bitwise operations & (AND),  (OR), ^ (XOR) and ~ (Complement).
On 32bit platforms and using standard integer types, the macros shall be always executed in 32bit registers and return 32bit values (DWORD or LONG). When the original width of any of such arguments is smaller than 32 bits, it is automatically cast to 32 bits. This might create problems since such casting fills the extra upper bits with 0's in the case of unsigned integers (or signed positive ones) and with 1's in the case of negative signed integers. In order to avoid such ambiguity, it is best to cast all signed integer arguments whose width is less than 32 bits to a DWORD [for example, mBits(dwArg,(DWORD)signedshortArg)].
 mBits(x,m)
 extracts from x the bits specified by the bit mask m. Use it to tests whether any of the mask bits is set.
 mBitsExcept(x,m,be)
 extracts from x the bits specified by the bit mask m, except those which are set in be.
 mTestBits(x,m,b)
 extracts from x the bits specified by the bit mask m and compares the result with the bit pattern b.
This is equivalent to the expression (mBits(x,m)==(b)).
Use this macro to test whether the masked bits coincide with a particular bit pattern.
Special case: The call mTestBits(x,m,m) returns true only if all the bits set in m are also set in x.
 mTestBitsExcept(x,m,b,be)
 is equivalent to the expression (mBitsExcept(x,m,be)==(b)).
Use it to test whether the masked bits of x, except those which are set in be, coincide with a particular bit pattern.
 mBitsOn(lvx,by)
 sets to 1 those bits of lvx which are set in b, leaving unchanged all others.
Use it to simultaneously set to 1 several flags in a bitcoded flagword.
 mBitsOnExcept(lvx,by,be)
 sets to 1 those bits of lvx which are set in b but not in be, leaving unchanged all others.
 mBitsOff(lvx,bn)
 sets to 0 those bits of lvx which are set in b, leaving unchanged all others.
Use it to simultaneously clear (reset to 0) several flags in a bitcoded flagword.
 mBitsOffExcept(lvx,bn,be)
 sets to 0 those bits of lvx which are set in b but not in be, leaving unchanged all others.
 mBitsToggle(lvx,b)
 toggles those bits of lvx which are set to 1 in b, leaving unchanged all others (the toggle operation is the same as XOR with 1).
Use this macro to simultaneously toggle several flags in a bitcoded flagword.
 mBitsToggleExcept(lvx,b,be)
 toggles those bits of lvx which are set in b but not in be, leaving unchanged all others.
 mBitsOnOff(lvx,by,bn)
 is equivalent to executing mBitsOff(lvx,bn) and then mBitsOn(lvx,by).
 mBitsOnOffExcept(x,b,be)
 is equivalent to executing mBitsOffExcept(x,bn,be) and then mBitsOnExcept(x,by,be).

FlagArrays Management
Code:

#define mFlagArraySize(nflags) (((nflags)+31)>>5)
#define mFlagArrayReset(lpFA,nflags,n) {for (n=0;n<mFlagArraySize(nflags);n++) (lpFA)[n]=0;}
#define mTestFAF(lpFA,n) ((lpFA)[(n)>>5] & (1<<((n)&0x1f)))
#define mSetFAF(lpFA,n) ((lpFA)[(n)>>5] = (1<<((n)&0x1f)))
#define mResetFAF(lpFA,n) ((lpFA)[(n)>>5] &= ~(1<<((n)&0x1f)))
#define mToggleFAF(lpFA,n) ((lpFA)[(n)>>5] ^= (1<<((n)&0x1f)))

When you need to manipulate a large number of flags (say 1000), pack them into an array of DWORDs, each containing up to 32 flags (one per bit). The following macros simplify operations on individual flags in such a FlagArray.
Arguments:
nflags (DWORD) is the total number of flags to handle
lpFA (DWORD*) points to a FlagArray
n (DWORD) specifies the nth flag (bit) of a FlagArray
 mFlagArraySize(nflags)
 returns the number of DWORDs required to contain the specified number of flags. For examples of use, see the next macro.
 mFlagArrayReset(lpFA,nflags,n)
 clears all flags in the FlagArray.
In this case, n is just an auxiliary integer variable and the macro does not return any significant value.
Examples of use:
(a) Dynamic allocation:
DWORD n;
DWORD* lpFA = new DWORD[mFlagArraySize(nflags)];
mFlagArrayReset(lpFA,nflags,n)];
...; // do anything here, using all the other
...; // macros to manipulate individual flags
delete [] lpFA; // Do not forget to disallocate
(b) Static allocation:
DWORD n;
DWORD lpFA[mFlagArraySize(100000)];
mFlagArrayReset(lpFA,nflags,n)];
...; // do anything here, using all the other
...; // macros to manipulate individual flags
 mFlagArrayReset(lpFA,nflags,n)
 clears all flags in the FlagArray.
In this case, n is just an auxiliary integer variable and the macro does not return any significant value.
Examples of use:
(a) Dynamic allocation:
DWORD n;
DWORD* lpFA = new DWORD[mFlagArraySize(nflags)];
mFlagArrayReset(lpFA,nflags,n)];
...; // do anything here, using all the other
...; // macros to manipulate individual flags
delete [] lpFA; // Do not forget to disallocate
(b) Static allocation:
DWORD n;
DWORD lpFA[mFlagArraySize(100000)];
mFlagArrayReset(lpFA,nflags,n)];
...; // do anything here, using all the other
...; // macros to manipulate individual flags
 mTestFAF(lpFA,n)
 tests the nth flag of the FlagArray and return 1 when set or 0 when not set.
 mSetFAF(lpFA,n)
 sets the nth flag of the FlagArray to 1.
 mResetFAF(lpFA,n)
 resets the nth flag of the FlagArray to 0.
 mToggleFAF(lpFA,n)
 toggles the nth flag of the FlagArray.

