ATLAS Offline Software
Loading...
Searching...
No Matches
bitmask.h File Reference

Helpers for treating a class enum as a bitmask. More...

#include <type_traits>
Include dependency graph for bitmask.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Namespaces

namespace  CxxUtils

Macros

#define ATH_BITMASK   IS_ATH_BITMASK=1
 Mark that a class enum should be treated as a bitmask.

Functions

template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E > operator~ (E lhs)
 operator~
template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
constexpr auto operator& (E lhs, F rhs)
 operator&
template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
constexpr auto operator| (E lhs, F rhs)
 operator|
template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
constexpr auto operator^ (E lhs, F rhs)
 operator^
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E & > operator&= (E &lhs, E rhs)
 operator&=
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E & > operator|= (E &lhs, E rhs)
 operator|=
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E & > operator^= (E &lhs, E rhs)
 operator^=
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E & > CxxUtils::set (E &lhs, E rhs)
 Convenience function to set bits in a class enum bitmask.
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, E & > CxxUtils::reset (E &lhs, E rhs)
 Convenience function to clear bits in a class enum bitmask.
template<class E>
constexpr std::enable_if_t< is_bitmask_v< E >, bool > CxxUtils::test (E lhs, E rhs)
 Convenience function to test bits in a class enum bitmask.

Detailed Description

Helpers for treating a class enum as a bitmask.

Author
scott snyder snyde.nosp@m.r@bn.nosp@m.l.gov
Date
Mar, 2018

C++11 class enums are very nice from a type-safety viewpoint. However, they are a bit awkward if you want to use them to represent a bitmask. For example:

enum class Mask { Bit0 = 1, Bit1 = 2, Bit2 = 4 };
Mask m = Mask::Bit1 | Mask::Bit2;

doesn't compile because the enumerators are not convertible to integers. One can cast back and forth between the enum and integers, but that's awkward to do everywhere.

This header defines overloads for the bitwise operators that work with a class enum. To enable these overloads, you need to add the ATH_BITMASK macro at the end of your enum declaration:

enum class Mask { Bit0 = 1, Bit1 = 2, Bit2 = 4,
#define ATH_BITMASK
Mark that a class enum should be treated as a bitmask.
Definition bitmask.h:70

After that, the usual bitwise operations (&, |, ^, &=, |=, ^=, ~) should work as expected. There are also a few convenience functions defined in the CxxUtils namespace: set, reset, and test.

In case of two different enum types (with common underlying type) the (non-assignment) boolean operators (&, |, ^) are also defined:

int result = Mask::Bit1 & OtherMask::Bit2

This approach was suggested by these postings:

http://blog.bitwigglers.org/using-enum-classes-as-type-safe-bitmasks https://www.justsoftwaresolutions.co.uk/cplusplus/using-enum-classes-as-bitfields.html

except that we rely on injecting a known enumerator into the type rather than using a separate traits class. This way works better if the enumeration is defined in a nested scope.

Definition in file bitmask.h.

Macro Definition Documentation

◆ ATH_BITMASK

#define ATH_BITMASK   IS_ATH_BITMASK=1

Mark that a class enum should be treated as a bitmask.

Put this at the end of the enumeration, after a comma, like this:

enum class Mask { Bit0 = 1, Bit1 = 2, Bit2 = 4,

Definition at line 70 of file bitmask.h.

Function Documentation

◆ operator&()

template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
auto operator& ( E lhs,
F rhs )
constexpr

operator&

One operand needs to be a bitmask and the other share at least the same underlying type. This allows bit operations with the underlying type (e.g. int) and chained operations involving more than two bitmasks.

Definition at line 147 of file bitmask.h.

148{
149 typedef relaxed_underlying_type_t<E> underlying;
150 return static_cast<enum_or_underlying_t<E,F>>(static_cast<underlying>(lhs) &
151 static_cast<underlying>(rhs));
152}

◆ operator&=()

template<class E>
std::enable_if_t< is_bitmask_v< E >, E & > operator&= ( E & lhs,
E rhs )
constexpr

operator&=

Definition at line 185 of file bitmask.h.

186{
187 typedef std::underlying_type_t<E> underlying;
188 lhs = static_cast<E> (static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
189 return lhs;
190}

◆ operator^()

template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
auto operator^ ( E lhs,
F rhs )
constexpr

operator^

One operand needs to be a bitmask and the other share at least the same underlying type. This allows bit operations with the underlying type (e.g. int) and chained operations involving more than two bitmasks.

Definition at line 173 of file bitmask.h.

174{
175 typedef relaxed_underlying_type_t<E> underlying;
176 return static_cast<enum_or_underlying_t<E,F>>(static_cast<underlying>(lhs) ^
177 static_cast<underlying>(rhs));
178}

◆ operator^=()

template<class E>
std::enable_if_t< is_bitmask_v< E >, E & > operator^= ( E & lhs,
E rhs )
constexpr

operator^=

Definition at line 209 of file bitmask.h.

210{
211 typedef std::underlying_type_t<E> underlying;
212 lhs = static_cast<E> (static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
213 return lhs;
214}

◆ operator|()

template<class E, class F, typename = std::enable_if_t<(is_bitmask_v<E> || is_bitmask_v<F>) && has_same_underlying_v<E,F>>>
auto operator| ( E lhs,
F rhs )
constexpr

operator|

One operand needs to be a bitmask and the other share at least the same underlying type. This allows bit operations with the underlying type (e.g. int) and chained operations involving more than two bitmasks.

Definition at line 160 of file bitmask.h.

161{
162 typedef relaxed_underlying_type_t<E> underlying;
163 return static_cast<enum_or_underlying_t<E,F>>(static_cast<underlying>(lhs) |
164 static_cast<underlying>(rhs));
165}

◆ operator|=()

template<class E>
std::enable_if_t< is_bitmask_v< E >, E & > operator|= ( E & lhs,
E rhs )
constexpr

operator|=

Definition at line 197 of file bitmask.h.

198{
199 typedef std::underlying_type_t<E> underlying;
200 lhs = static_cast<E> (static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
201 return lhs;
202}

◆ operator~()

template<class E>
std::enable_if_t< is_bitmask_v< E >, E > operator~ ( E lhs)
constexpr

operator~

Definition at line 132 of file bitmask.h.

133{
134 typedef std::underlying_type_t<E> underlying;
135 return static_cast<E> (~static_cast<underlying>(lhs));
136}