![]() |
Plasma Engine
2.0
|
The plBitflags class allows you to work with type-safe bitflags. More...
#include <Bitflags.h>
Public Types | |
using | ConstIterator = plBitIterator<Enum, false> |
Public Member Functions | |
PL_ALWAYS_INLINE | plBitflags () |
Constructor. Initializes the flags to the default value. | |
PL_ALWAYS_INLINE | plBitflags (Enum flag1) |
Converts the incoming type to plBitflags<T> | |
PL_ALWAYS_INLINE void | operator= (Enum flag1) |
PL_ALWAYS_INLINE bool | operator== (const StorageType rhs) const |
Comparison operator. | |
PL_ALWAYS_INLINE bool | operator!= (const StorageType rhs) const |
Comparison operator. | |
PL_ALWAYS_INLINE bool | operator== (const plBitflags< T > &rhs) const |
Comparison operator. | |
PL_ALWAYS_INLINE bool | operator!= (const plBitflags< T > &rhs) const |
Comparison operator. | |
PL_ALWAYS_INLINE void | Clear () |
Clears all flags. | |
PL_ALWAYS_INLINE bool | IsSet (Enum flag) const |
Checks if certain flags are set within the bitfield. | |
PL_ALWAYS_INLINE bool | AreAllSet (const plBitflags< T > &rhs) const |
Returns whether all the given flags are set. | |
PL_ALWAYS_INLINE bool | AreNoneSet (const plBitflags< T > &rhs) const |
Returns whether none of the given flags is set. | |
PL_ALWAYS_INLINE bool | IsAnySet (const plBitflags< T > &rhs) const |
Returns whether any of the given flags is set. | |
PL_ALWAYS_INLINE void | Add (const plBitflags< T > &rhs) |
Sets the given flag. | |
PL_ALWAYS_INLINE void | Remove (const plBitflags< T > &rhs) |
Removes the given flag. | |
PL_ALWAYS_INLINE void | Toggle (const plBitflags< T > &rhs) |
Toggles the state of the given flag. | |
PL_ALWAYS_INLINE void | AddOrRemove (const plBitflags< T > &rhs, bool bState) |
Sets or clears the given flag. | |
PL_ALWAYS_INLINE plBitflags< T > | operator| (const plBitflags< T > &rhs) const |
Returns an object that has the flags of this and rhs combined. | |
PL_ALWAYS_INLINE plBitflags< T > | operator& (const plBitflags< T > &rhs) const |
Returns an object that has the flags that were set both in this and rhs. | |
PL_ALWAYS_INLINE void | operator|= (const plBitflags< T > &rhs) |
Modifies this to also contain the bits from rhs. | |
PL_ALWAYS_INLINE void | operator&= (const plBitflags< T > &rhs) |
Modifies this to only contain the bits that were set in this and rhs. | |
PL_ALWAYS_INLINE StorageType | GetValue () const |
Returns the stored value as the underlying integer type. | |
PL_ALWAYS_INLINE void | SetValue (StorageType value) |
Overwrites the flags with a new value. | |
PL_ALWAYS_INLINE bool | IsNoFlagSet () const |
Returns true if not a single bit is set. | |
PL_ALWAYS_INLINE bool | IsAnyFlagSet () const |
Returns true if any bitflag is set. | |
PL_ALWAYS_INLINE ConstIterator | GetIterator () const |
Returns a constant iterator to the very first set bit. Note that due to the way iterating through bits is accelerated, changes to the bitflags will not affect the iterator after creation. | |
PL_ALWAYS_INLINE ConstIterator | GetEndIterator () const |
Returns an invalid iterator. Needed to support range based for loops. | |
The plBitflags class allows you to work with type-safe bitflags.
plBitflags takes a struct as its template parameter, which contains an enum for the available flag values. plBitflags wraps this type in a way which enables the compiler to do type-checks. This makes it very easy to document and enforce what flags are to be used in an interface. For example, in traditional C++ code, you usually need to have an integer as a function parameter type, when that parameter is supposed to take flags. However, WHICH flags (e.g. from which enum) cannot be enforced through compile time checks. Thus it is difficult for the user to see whether he used the correct type, and it is impossible for the compiler to help find such bugs. plBitflags solves this problem. However the flag type used to instantiate plBitflags must fulfill some requirements.
There are two ways to define your bitflags type, that can be used with plBitflags.
The easier, less powerful way: Use the PL_DECLARE_FLAGS() macro.
Example:
This will declare a type 'SimpleRenderFlags' which contains three different flags. You can then create a function which takes flags like this:
And this function can be called like this:
However it will refuse to compile with anything else, for example this will not work:
The second way to declare your bitflags type allows even more flexibility. Here you need to declare your bitflag type manually:
Here we declare a struct which contains our enum that contains all the flags that we want to have. This enum can contain flags that are combinations of other flags. Note also the 'Default' flag, which is mandatory.
The 'Bits' struct enables debuggers to show exactly which flags are enabled (with nice names) when you inspect an plBitflags instance. You could leave this struct empty, but then your debugger can not show helpful information about the flags anymore. The Bits struct should contain one named entry for each individual bit. E.g. here only the flags 'EnableEffects', 'EnableLighting' and 'EnableShadows' actually map to single bits, the other flags are combinations of those. Therefore the Bits struct only specifies names for those first three Bits.
The typedef 'StorageType' is also mandatory, such that plBitflags can access it.
Finally the macro PL_DECLARE_FLAGS_OPERATORS will define the required operator to be able to combine bitflags of your type. I.e. it enables to write plBitflags<SimpleRenderFlags> f = EnableEffects | EnableLighting;
For a real world usage example, see plCVarFlags.