-
Notifications
You must be signed in to change notification settings - Fork 163
Bitset Flags
When FS2 was written, it was (and still is) common practice to represent collection of flags as integer variables that have bits ANDed and ORed into and out of them. While certainly fast and efficient, this method places a burden on the developer to ensure that the right bits are set and queried. As several auditing passes through the FSO codebase have shown, it is easy to make mistakes, especially when flags have very similar names (as an example, there was a ship object flag called SF_STEALTH and a ship class flag called SIF_STEALTH; this was confused in at least one place, leading to unwanted behaviour). To address this, we have created bitset flags, using a combination of the STL's std::bitset and the C++11 enum class feature. These flagsets, as they are called from here on, guarantee type safety: Attempting to use the wrong kind of flag in the wrong place will cause compiler errors.
For any flagset, a set of flags needs to be defined. To facilitate this, the header globalincs/flagset.h defines a macro called "FLAG_LIST". It is used like this:
FLAG_LIST(Flag_List) {
Flag1,
Flag2,
NUM_VALUES
}
Do note the last value: It is required for every flagset, and must always be the last value defined. This value should be used in cases where an invalid value is required (For example, when a flag change packet is sent during multiplayer, flags that aren't supposed to be set are set to the ::NUM_VALUES value).
In order to use these flags, we then need to define a flagset variable. This is done like this:
flagset<Flag_List> flags;
To read the value of any flag, use the [] accessor, like this:
bool value = flags[Flag_List::Flag1];
If multiple values have to be queried, you can use this:
bool value = flags[Flag_List::Flag1, Flag_List::Flag2]; // equivalent to value = flags[Flag_List::Flag1] || flags[Flag_List::Flag2]
To change a flag value, use the set and remove methods:
flags.set(Flag_List::Flag1); // flags[Flag_List::Flag1] returns true
flags.remove(Flag_List::Flag2); // flags[Flag_List::Flag1] returns false
To clear all flags in the flagset, use the reset method:
flags.reset(); // All flag values report false