From babab82c9b73c3c5623a026474c1bfbad6565bef Mon Sep 17 00:00:00 2001 From: Maxime Arthaud Date: Tue, 28 Nov 2023 08:09:09 -0800 Subject: [PATCH] Move the flags class into sparta 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 --- include/sparta/Flags.h | 152 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 include/sparta/Flags.h diff --git a/include/sparta/Flags.h b/include/sparta/Flags.h new file mode 100644 index 0000000..f65b52d --- /dev/null +++ b/include/sparta/Flags.h @@ -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 +#include + +namespace sparta { + +/** + * A set of flags. + * + * `Flags` 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 +class Flags final { + static_assert(std::is_enum_v, "Enum must be an enumeration type"); + static_assert( + std::is_unsigned_v>, + "The underlying type of Enum must be an unsigned arithmetic type"); + + public: + using EnumType = Enum; + using IntT = std::underlying_type_t; + + public: + Flags() = default; + + /* implicit */ constexpr Flags(Enum flag) : value_(static_cast(flag)) {} + + /* implicit */ constexpr Flags(std::initializer_list flags) + : value_(0) { + for (auto flag : flags) { + value_ |= static_cast(flag); + } + } + + constexpr Flags& operator&=(Enum flag) { + value_ &= static_cast(flag); + return *this; + } + + constexpr Flags& operator&=(Flags flags) { + value_ &= flags.value_; + return *this; + } + + constexpr Flags& operator|=(Enum flag) { + value_ |= static_cast(flag); + return *this; + } + + constexpr Flags& operator|=(Flags flags) { + value_ |= flags.value_; + return *this; + } + + constexpr Flags& operator^=(Enum flag) { + value_ ^= static_cast(flag); + return *this; + } + + constexpr Flags& operator^=(Flags flags) { + value_ ^= flags.value_; + return *this; + } + + constexpr Flags operator&(Enum flag) const { + return Flags(value_ & static_cast(flag)); + } + + constexpr Flags operator&(Flags flags) const { + return Flags(value_ & flags.value_); + } + + constexpr Flags operator|(Enum flag) const { + return Flags(value_ | static_cast(flag)); + } + + constexpr Flags operator|(Flags flags) const { + return Flags(value_ | flags.value_); + } + + constexpr Flags operator^(Enum flag) const { + return Flags(value_ ^ static_cast(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(flag) == 0) { + return value_ == 0; + } else { + return (value_ & static_cast(flag)) == static_cast(flag); + } + } + + constexpr Flags& set(Enum flag, bool on = true) { + if (on) { + value_ |= static_cast(flag); + } else { + value_ &= ~static_cast(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