-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: In Mariana Trench, we have a convenient utility class called `Flags` which implements a bitset on top of an enum where values are powers of 2. This makes it very efficient to store a small set of flags. I would like to re-use this in other tools (namely, Angliru). My two options are: * Copy/paste the code of that class. * Move this in a library that "other" tools can/will use. This is what this diff does. The downside of course is that sparta might become a dumping group for shared code, which is not what we want. I believe this is small and generic enough that it could fit in sparta. Reviewed By: anwesht Differential Revision: D51589404 fbshipit-source-id: 87ad709a8b786126caa48e31fe58f797d2415bca
- Loading branch information
1 parent
0979bdc
commit babab82
Showing
1 changed file
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/* | ||
* 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 sparta { | ||
|
||
/** | ||
* 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; | ||
using IntT = std::underlying_type_t<Enum>; | ||
|
||
public: | ||
Flags() = default; | ||
|
||
/* implicit */ constexpr Flags(Enum flag) : value_(static_cast<IntT>(flag)) {} | ||
|
||
/* implicit */ constexpr Flags(std::initializer_list<Enum> flags) | ||
: value_(0) { | ||
for (auto flag : flags) { | ||
value_ |= static_cast<IntT>(flag); | ||
} | ||
} | ||
|
||
constexpr Flags& operator&=(Enum flag) { | ||
value_ &= static_cast<IntT>(flag); | ||
return *this; | ||
} | ||
|
||
constexpr Flags& operator&=(Flags flags) { | ||
value_ &= flags.value_; | ||
return *this; | ||
} | ||
|
||
constexpr Flags& operator|=(Enum flag) { | ||
value_ |= static_cast<IntT>(flag); | ||
return *this; | ||
} | ||
|
||
constexpr Flags& operator|=(Flags flags) { | ||
value_ |= flags.value_; | ||
return *this; | ||
} | ||
|
||
constexpr Flags& operator^=(Enum flag) { | ||
value_ ^= static_cast<IntT>(flag); | ||
return *this; | ||
} | ||
|
||
constexpr Flags& operator^=(Flags flags) { | ||
value_ ^= flags.value_; | ||
return *this; | ||
} | ||
|
||
constexpr Flags operator&(Enum flag) const { | ||
return Flags(value_ & static_cast<IntT>(flag)); | ||
} | ||
|
||
constexpr Flags operator&(Flags flags) const { | ||
return Flags(value_ & flags.value_); | ||
} | ||
|
||
constexpr Flags operator|(Enum flag) const { | ||
return Flags(value_ | static_cast<IntT>(flag)); | ||
} | ||
|
||
constexpr Flags operator|(Flags flags) const { | ||
return Flags(value_ | flags.value_); | ||
} | ||
|
||
constexpr Flags operator^(Enum flag) const { | ||
return Flags(value_ ^ static_cast<IntT>(flag)); | ||
} | ||
|
||
constexpr Flags operator^(Flags flags) const { | ||
return Flags(value_ ^ flags.value_); | ||
} | ||
|
||
constexpr Flags operator~() const { return Flags(~value_); } | ||
|
||
explicit constexpr operator bool() const { return value_ != 0; } | ||
|
||
constexpr bool operator!() const { return value_ == 0; } | ||
|
||
constexpr bool operator==(Flags flags) const { | ||
return value_ == flags.value_; | ||
} | ||
|
||
constexpr bool operator!=(Flags flags) const { | ||
return value_ != flags.value_; | ||
} | ||
|
||
constexpr 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); | ||
} | ||
} | ||
|
||
constexpr Flags& set(Enum flag, bool on = true) { | ||
if (on) { | ||
value_ |= static_cast<IntT>(flag); | ||
} else { | ||
value_ &= ~static_cast<IntT>(flag); | ||
} | ||
return *this; | ||
} | ||
|
||
constexpr bool empty() const { return value_ == 0; } | ||
|
||
constexpr void clear() { value_ = 0; } | ||
|
||
constexpr bool is_subset_of(Flags flags) const { | ||
return (value_ | flags.value_) == flags.value_; | ||
} | ||
|
||
constexpr bool has_single_bit() const { | ||
return (value_ && !(value_ & (value_ - 1))); | ||
} | ||
|
||
constexpr IntT encode() const { return value_; } | ||
|
||
static constexpr Flags decode(IntT encoding) { return Flags(encoding); } | ||
|
||
private: | ||
explicit constexpr Flags(IntT value) : value_(value) {} | ||
|
||
private: | ||
IntT value_ = 0; | ||
}; | ||
|
||
} // namespace sparta |