flagword

The flagword parameterized class is used to pack a bunch of options into a single value.

There are three ways to represent such a set of flags: (a) as bits within some flavor of integer; (b) as a bit vector of arbitrary length; and (c) as a list or spare array. This class implements type (a), which are quite common in the Win32 API, so existing needs easily meet the restrictions of this type (namely, flags are constants that are powers of two, and at most 32 flags can be packed into one set), and it is trivial to extract the native format expected by the Win32 API calls.

Explaination by Example

Start with an enumerated type specifying flags that are powers of two.

enum color { red=1, yellow=2, blue=4, green=8, purple=16, orange=32, brown=64, black=128 };
The idea is that you can logically OR multiple flags together to create a set of flags. For example, red|green|blackwill have a unique bit combination that distinguishes it from any other set of colors. The problem is that OR-ing the flags together will produce a result of type int, not of type color. This compromises the compile-time type checking of the system.
void selection (int mycolors);
You can't declare the function to take a color, because then you could not call the function with the result of the logical-OR. You could define your own operator| to operate on this type, but you would have to do so for every such type. This is a real possibility, though.

The flagword class creates a type-checked way of handling these flags, along with many other features.

typedef classics::flagword<color> colorflags;

Now you can declare the function as
void selection (colorflags mycolors);
and the compiler will perform strong type checking on this argument, and it is clear to the reader that a set of colors, not (just) a single color, is expected.

You can pass a single color enumeration constant to the function because there is an implicit converstion from color to colorflags.

selection (blue);
For passing multiple flags, it's a little harder than the ideal (an operator| taking color for both arguments and returning a flagword, generated automatically when the template is instantiated) because the operator| would exist in the classics namespace and not be found when applying the operator between two arguments of types that are in a different namespace. To make matters worse, the compiler chokes when you try a using declaration or the qualified function name (classics::operator|) syntax.

So, the operator| is provided for colorflags only, not for the underlying color enumeration. You can add the function manually if you want, but in general all the operations are provided for flagword types and rely on conversion from the underlying enumeration type in mixed expressions

So, if you're not totally lost by this point, the way to join multiple flags together is to cast one of them manually.

selection (colorflags(red)|green|black);
Alternativly, you could use a variable of type colorflags.
colorflags my_choice= red;
my_choice |= green;
selection (my_choice|black);
As you see from the example and the list below, the flagword is fully expressive. But you don't know the half of it yet.

Logical Flag Operations

|, |= logical bit-wise OR.
&, &= logical bit-wise AND.
^, ^= meaning not yet defined
prefix ~ Reverse all bits

True Negative Flags

In a traditional int packed with flags, the presence of a bit means that the flag is set. Does the absence of a bit mean that the flag is definitly unset, or simply unspecified? A number of data structures in the Win32 API run into this issue, and solve it by using a pair of words: One states which flags are meaningful, and the other gives the meanings for those selected flags. The flagword class models this behavior directly, and in fact implements it in this way so it's trivial to extract the raw data for use in Win32 API functions or other legacy code.

The constructor can take two arguments. The first is the bit image for the data; which flags are set. The second is the bit image for the validity mask; which flags are meaningful in the first argument.

colorflags my_choice (red|blue, red|yellow|blue|green);
draw_list (my_choice);
The hypothetical draw_list function could display something like this:
red
yellow
blue
green That is, the draw_list function can tell that my_choice contains two flags that are ON out of four that we care about, and the others are unspecified. It knows that yellow is OFF, as opposed to orange which is not specified at all.

When you test for flags, you can specify whether you want to know if the flag is set or not (neither yellow nor orange is set), or whether a flag is explicitly negative (yellow is, orange isn't). You don't need to put up with the complexity if you don't need it. Converting an enumeration constant into a flagword gives a set with one bit set and all other bits off and invalid.

Tri-state Logic

Internally, the flagword is represented as a word of flags and a second word specifying which flags are valid. An alternate way of thinking about it is to use three-state logic.

Unlike the Boolean states we are used to, tri-value flags have three states: true, false, and unspecified. Treating the third state as an unknown (could be true or false, I don't know), you have a natural definition of what AND and OR mean. It's clear that unspecified|true produces a result of true, because it doesn't matter what the unknown value turns out to be. In cases where you can't tell, the result becomes unknown too.

The operator| and operator& functions on flagwords use this logic. You can see that it degenerates to the ordinary Boolean logic when unknown states are not being used.

A: if either argument is true, the result must be true.
B: if both arguments are false, the result is definitly false.
C: can't tell.

result Mask= (D1&M1)|(D2&M2)|(M1&M2)
result Data= (D1|D2)

Key: D1,M1 are data and mask words for left argument; D2,M2 are data and mask words for right argument; Dr,Mr are data and mask words for result. An x bit means "don't care".

A: if either argument is false, output must be false and the other argument doesn't matter.
B: if (and only if) both arguments are true, output is true.
C: otherwise, result is unknown.

result Mask= (~D1&M1)|(~D2&M2)|(M1&M2)
result Data= (D1&D2)

Combining Flags with +

Besides the traditional logical operators of | and &, other useful operations suggest themselves. In fact, there are 19,683 possible trit-wise operators, which are a subset of the 4 billion possible data/mask pair operations. Naturally, I won't try to enumerate them or figure out what they are good for. Instead, I'll add functions to the class whenever a need becomes apparent.

One important operation is to combine flags according to this rule: For each valid flag in the right argument put (on or off) into the left argument; otherwise leave the flags in the left argument unchanged. This has been defined as operator+, and the truth table is shown below.

A: if right argument is valid, take that.
B: otherwise, if left argument is valid, take that.
C: otherwise, result is unknown.

result Mask= M1|M2
result Dada= (D2&M2)|(~M2&D1)

Note that this function is not commutitive. That is, X+Y is not the same as Y+X. When "adding" flags, the right hand argument is "on top", and covers the information in the left argument. The flags from the left argument only show through any gaps where the right argument has unspecified values.

In fact, I originally had another operation slated for this class, to be used in applying default flags to a set of user-supplied flags. The defaults should only affect flags that the user has not specified; any that the user set (true or false) are left alone. When I started to draw up the truth table for this operation, I realized that it's exactly the same as + with the arguments reversed.

In the earlier examples, using + will have the same result as |. This is by design, and a consequence of the way single value enumeration constants are converted to flagwords as well as in the logic of the tables.

But, using + on actual flagwords (not just promoted enumeration constants) gives added power: You can set and clear flags at the same time.

To make this clear, recall the example of the checkbox. The variable my_choice has two bits set ON and two bits set OFF, and others that are unspecified. If you combined flags with OR, the ON bits get set in the result and the OFF bits have no effect. To turn off bits, you need to negate and use AND. But when applying the user's configuration to a set of default values, you want to bring in the specified values, ON or OFF.

colorflags my_choice (red|blue, red|yellow|blue|green);
colorflags original (red|green|purple, /*out of*/ red|green|purple|black);
colorflags combined= original + my_choice;
The ADD operation used to compute combined will start with the value of original (red on, green on, purple on, black off) and apply the valid values in my_choice: it will turn on red, turn on blue, turn off yellow, and turn off green. The right-hand argument said nothing about black, so it's value is left unchanged. This is distinguished from green, which is explicitly turned off.

Word Size

The colorflags example used a single template parameter to flagword. However, you can optionally use a second parameter to specify the underlying word type. The idea is that you could make 16-bit flags if you needed the space (or to model legacy code that packed the data and mask into a single int), or use a __int64 if you had more flags. You could, however, use any type you like that supported the essential underlying bit operations.

Flag Testing Functions

Just providing flag manipulation is an interesting mathmatical design exersize, but it doesn't do us much good in a program unless there is also a way to test flags.

Typically, once you care about invidial flags you care about each one individually, one at a time. That is, flags are just a way to pack a bunch of Boolean variables into one small package. When it comes to implementing the function that looks at the flags, it needs to check each flag as if it were an individual setting. To that end, there are three single-flag testing functions.

  • is_on
  • is_off
  • is_valid
Each of these functions take a single enumeration constant as an argument. For example, the draw_list function above might contain a statement similar to this:
if (selection.is_on(red)) { ...
Note that is_off is not the opposite of is_on. Calling is_on returns true if and only if the flag is definitly set to on. Calling is_off returns true if and only if the flag is definitly off. If the flag is unspecified, then both functions would return false.

If you care whether a flag is not on and don't care if it's because it was definitly set to off or simply never specified at all, use !is_on(red) instead of is_off(red). If you are not dealing with unspecified states, then be sure to always use is_on and !is_on, never is_off.

Besides testing flags individually, you may sometimes care about groups of related flags. The match function returns another flagword, not a simple Boolean value. The result sets a flag if the arguments match, and clears it if they don't match. The valid flags in the result are the same as the valid flags in the right hand argument.

This allows you to test for positive and negative states at the same time. For example,

colorflags m1 (red, /*out of*/ red|blue);  //red on, blue off
colorflags result= selection.match(m1);
  // do further processing on result...
if (selection.match(m1)) {  //check result immediatly

The call to match will produce a result with red ON if and only if the red flag in selection matches that in m1, and will set blue ON if they match with blue, and all other flags in the result are unspecified.

Meanwhile, implicitly converting a flagword to bool will test whether all valid flags are ON. In context, this means a perfect match. The if statement above will be taken only if selection has the red flag ON and the blue flag OFF. Other flags in selection don't matter.