source/Flags.h (111 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <initializer_list>
#include <type_traits>
namespace marianatrench {
/**
* A set of flags.
*
* `Flags<Enum>` can be used to store an OR-combination of enum values, where
* `Enum` is an enum class type. `Enum` underlying values must be a power of 2.
*/
template <typename Enum>
class Flags final {
static_assert(std::is_enum_v<Enum>, "Enum must be an enumeration type");
static_assert(
std::is_unsigned_v<std::underlying_type_t<Enum>>,
"The underlying type of Enum must be an unsigned arithmetic type");
public:
using EnumType = Enum;
private:
using IntT = std::underlying_type_t<Enum>;
public:
Flags() = default;
/* implicit */ Flags(Enum flag) : value_(static_cast<IntT>(flag)) {}
/* implicit */ Flags(std::initializer_list<Enum> flags) : value_(0) {
for (auto flag : flags) {
value_ |= static_cast<IntT>(flag);
}
}
Flags(const Flags&) = default;
Flags(Flags&&) = default;
Flags& operator=(const Flags&) = default;
Flags& operator=(Flags&&) = default;
~Flags() = default;
Flags& operator&=(Enum flag) {
value_ &= static_cast<IntT>(flag);
return *this;
}
Flags& operator&=(Flags flags) {
value_ &= flags.value_;
return *this;
}
Flags& operator|=(Enum flag) {
value_ |= static_cast<IntT>(flag);
return *this;
}
Flags& operator|=(Flags flags) {
value_ |= flags.value_;
return *this;
}
Flags& operator^=(Enum flag) {
value_ ^= static_cast<IntT>(flag);
return *this;
}
Flags& operator^=(Flags flags) {
value_ ^= flags.value_;
return *this;
}
Flags operator&(Enum flag) const {
return Flags(value_ & static_cast<IntT>(flag));
}
Flags operator&(Flags flags) const {
return Flags(value_ & flags.value_);
}
Flags operator|(Enum flag) const {
return Flags(value_ | static_cast<IntT>(flag));
}
Flags operator|(Flags flags) const {
return Flags(value_ | flags.value_);
}
Flags operator^(Enum flag) const {
return Flags(value_ ^ static_cast<IntT>(flag));
}
Flags operator^(Flags flags) const {
return Flags(value_ ^ flags.value_);
}
Flags operator~() const {
return Flags(~value_);
}
explicit operator bool() const {
return value_ != 0;
}
bool operator!() const {
return value_ == 0;
}
bool operator==(Flags flags) const {
return value_ == flags.value_;
}
bool test(Enum flag) const {
if (static_cast<IntT>(flag) == 0) {
return value_ == 0;
} else {
return (value_ & static_cast<IntT>(flag)) == static_cast<IntT>(flag);
}
}
Flags& set(Enum flag, bool on = true) {
if (on) {
value_ |= static_cast<IntT>(flag);
} else {
value_ &= ~static_cast<IntT>(flag);
}
return *this;
}
bool empty() const {
return value_ == 0;
}
void clear() {
value_ = 0;
}
bool is_subset_of(Flags flags) const {
return (value_ | flags.value_) == flags.value_;
}
private:
explicit Flags(IntT value) : value_(value) {}
private:
IntT value_ = 0;
};
} // namespace marianatrench