From b87e758281fd2ba1ec9251d13b9a50dd545b3ae1 Mon Sep 17 00:00:00 2001 From: m-peko Date: Sun, 11 Oct 2020 09:17:08 +0200 Subject: [PATCH 1/2] Support raw flags, without string representation --- include/bitflags/bitflags.hpp | 320 +++++++++++++++++++++------------- tests/src/bitflags_test.cpp | 153 ++++++++++++++++ 2 files changed, 351 insertions(+), 122 deletions(-) diff --git a/include/bitflags/bitflags.hpp b/include/bitflags/bitflags.hpp index e4b97c7..3c20635 100644 --- a/include/bitflags/bitflags.hpp +++ b/include/bitflags/bitflags.hpp @@ -37,56 +37,117 @@ namespace bf { namespace internal { -template -struct flag; - /** - * Comparison operators overloads + * struct flag_helper + * + * Helper struct that contains comparison operators and + * bitwise operators overloads used by any of the flag types. * - * flag flag + * NOTE: This struct is for internal use only. */ +template +struct flag_helper { + constexpr flag_helper() = default; + constexpr flag_helper(flag_helper&& rhs) = default; + constexpr flag_helper(flag_helper const& rhs) = default; + + flag_helper& operator=(flag_helper&& rhs) = default; + flag_helper& operator=(flag_helper const& rhs) = default; + + ~flag_helper() = default; + + /** + * Comparison operators overloads + * + * FlagT FlagT + */ + + [[nodiscard]] friend constexpr bool operator==(FlagT const& lhs, FlagT const& rhs) noexcept { + return lhs.bits == rhs.bits; + } + + [[nodiscard]] friend constexpr bool operator!=(FlagT const& lhs, FlagT const& rhs) noexcept { + return lhs.bits != rhs.bits; + } -template -[[nodiscard]] constexpr bool operator==(flag const& lhs, flag const& rhs) noexcept; + /** + * Bitwise operators overloads + * + * FlagT + * + * FlagT FlagT + */ -template -[[nodiscard]] constexpr bool operator!=(flag const& lhs, flag const& rhs) noexcept; + [[nodiscard]] friend constexpr FlagT operator~(FlagT const& rhs) noexcept { + return ~rhs.bits; + } + + [[nodiscard]] friend constexpr FlagT operator&(FlagT const& lhs, FlagT const& rhs) noexcept { + return lhs.bits & rhs.bits; + } + + [[nodiscard]] friend constexpr FlagT operator|(FlagT const& lhs, FlagT const& rhs) noexcept { + return lhs.bits | rhs.bits; + } + + [[nodiscard]] friend constexpr FlagT operator^(FlagT const& lhs, FlagT const& rhs) noexcept { + return lhs.bits ^ rhs.bits; + } +}; /** - * Bitwise operators overloads + * struct raw_flag * - * flag + * Flag type that does not contain string representation. * - * flag flag + * NOTE: This struct is for internal use only. */ +template +struct raw_flag : flag_helper> { + T bits; -template -[[nodiscard]] constexpr flag operator~(flag const& rhs) noexcept; + constexpr raw_flag(T bits) noexcept + : bits(bits) + {} -template -[[nodiscard]] constexpr flag operator&(flag const& lhs, flag const& rhs) noexcept; + [[nodiscard]] explicit constexpr operator T() const noexcept { + return bits; + } -template -[[nodiscard]] constexpr flag operator|(flag const& lhs, flag const& rhs) noexcept; + /** + * Bitwise operators overloads + * + * raw_flag = raw_flag + */ + + constexpr raw_flag& operator&=(raw_flag const& rhs) noexcept { + bits &= rhs.bits; + return *this; + } -template -[[nodiscard]] constexpr flag operator^(flag const& lhs, flag const& rhs) noexcept; + constexpr raw_flag& operator|=(raw_flag const& rhs) noexcept { + bits |= rhs.bits; + return *this; + } + + constexpr raw_flag& operator^=(raw_flag const& rhs) noexcept { + bits ^= rhs.bits; + return *this; + } +}; /** * struct flag * - * Represents a single flag in a collection of multiple flags. - * This structure is for internal use only. + * Flag type that contains string representation. + * + * NOTE: This struct is for internal use only. */ -template -struct flag { +template +struct flag : flag_helper> { T bits; std::string_view name; - constexpr flag() = default; - constexpr flag(flag&& rhs) = default; - constexpr flag(flag const& rhs) = default; - constexpr flag(T bits) noexcept : bits(bits) {} @@ -96,55 +157,16 @@ struct flag { , name(name) {} - flag& operator=(flag&& rhs) = default; - flag& operator=(flag const& rhs) = default; - - ~flag() = default; - [[nodiscard]] explicit constexpr operator T() const noexcept { return bits; } - /** - * Comparison operators overloads - * - * flag flag - */ - - [[nodiscard]] friend constexpr bool operator==(flag const& lhs, flag const& rhs) noexcept { - return lhs.bits == rhs.bits; - } - - [[nodiscard]] friend constexpr bool operator!=(flag const& lhs, flag const& rhs) noexcept { - return lhs.bits != rhs.bits; - } - /** * Bitwise operators overloads * - * flag - * - * flag flag - * - * flag = flag + * flag = flag */ - [[nodiscard]] friend constexpr flag operator~(flag const& rhs) noexcept { - return ~rhs.bits; - } - - [[nodiscard]] friend constexpr flag operator&(flag const& lhs, flag const& rhs) noexcept { - return lhs.bits & rhs.bits; - } - - [[nodiscard]] friend constexpr flag operator|(flag const& lhs, flag const& rhs) noexcept { - return lhs.bits | rhs.bits; - } - - [[nodiscard]] friend constexpr flag operator^(flag const& lhs, flag const& rhs) noexcept { - return lhs.bits ^ rhs.bits; - } - constexpr flag& operator&=(flag const& rhs) noexcept { bits &= rhs.bits; return *this; @@ -165,8 +187,9 @@ struct flag { * struct min * * Provides member typedef type which is defined as minimal unsigned - * integral type capable of storing N integers. - * This structure is for internal use only. + * integral type capable of storing N number of integers. + * + * NOTE: This struct is for internal use only. */ template struct min { @@ -187,7 +210,8 @@ using min_t = typename min::type; /** * Shifts integer of type T by specified offset. * If the offset is less than 0, 0 is returned. - * This function is for internal use only. + * + * NOTE: This function is for internal use only. * * @param offset Offset to be used for shifting * @@ -204,36 +228,63 @@ constexpr T shift(int const offset) { } // internal -template +template < + typename ImplT, + typename T, + template typename FlagT +> class bitflags; /** * Bitwise operators overloads * - * bitflags + * bitflags * - * bitflags flag + * bitflags FlagT */ -template -[[nodiscard]] constexpr T operator~(bitflags const& rhs) noexcept; - -template -[[nodiscard]] constexpr T operator&(bitflags const& lhs, internal::flag const& rhs) noexcept; - -template -[[nodiscard]] constexpr T operator|(bitflags const& lhs, internal::flag const& rhs) noexcept; - -template -[[nodiscard]] constexpr T operator^(bitflags const& lhs, internal::flag const& rhs) noexcept; +template < + typename ImplT, + typename T, + template typename FlagT +> +[[nodiscard]] constexpr T operator~(bitflags const& rhs) noexcept; + +template < + typename ImplT, + typename T, + template typename FlagT +> +[[nodiscard]] constexpr T operator&(bitflags const& lhs, FlagT const& rhs) noexcept; + +template < + typename ImplT, + typename T, + template typename FlagT +> +[[nodiscard]] constexpr T operator|(bitflags const& lhs, FlagT const& rhs) noexcept; + +template < + typename ImplT, + typename T, + template typename FlagT +> +[[nodiscard]] constexpr T operator^(bitflags const& lhs, FlagT const& rhs) noexcept; /** * class bitflags * - * Represents a typesafe bitmask flag generator that manages a set of flags. - * The flags should only be defined for integral types. + * Typesafe bitmask flag generator that manages set of flags. + * Flags should be defined only for integral types. */ -template > +template < + typename ImplT, + typename T = internal::min_t, + template < + typename, + typename + > typename FlagT = internal::flag +> class bitflags : public ImplT { public: using underlying_type = T; @@ -242,11 +293,11 @@ class bitflags : public ImplT { constexpr bitflags(bitflags&& rhs) = default; constexpr bitflags(bitflags const& rhs) = default; - constexpr bitflags(internal::flag&& rhs) noexcept + constexpr bitflags(FlagT&& rhs) noexcept : curr_(std::move(rhs)) {} - constexpr bitflags(internal::flag const& rhs) noexcept + constexpr bitflags(FlagT const& rhs) noexcept : curr_(rhs) {} @@ -267,12 +318,12 @@ class bitflags : public ImplT { return *this; } - bitflags& operator=(internal::flag&& rhs) noexcept { + bitflags& operator=(FlagT&& rhs) noexcept { curr_ = std::move(rhs); return *this; } - bitflags& operator=(internal::flag const& rhs) noexcept { + bitflags& operator=(FlagT const& rhs) noexcept { curr_ = rhs; return *this; } @@ -283,51 +334,51 @@ class bitflags : public ImplT { return curr_.bits; } - [[nodiscard]] constexpr bool operator==(internal::flag const& rhs) const noexcept { + [[nodiscard]] constexpr bool operator==(FlagT const& rhs) const noexcept { return curr_ == rhs; } - [[nodiscard]] constexpr bool operator!=(internal::flag const& rhs) const noexcept { + [[nodiscard]] constexpr bool operator!=(FlagT const& rhs) const noexcept { return curr_ != rhs; } /** * Bitwise operators overloads * - * bitflags + * bitflags * - * bitflags flag + * bitflags FlagT * - * bitflags = flag + * bitflags = FlagT */ [[nodiscard]] friend constexpr bitflags operator~(bitflags const& rhs) noexcept { return ~rhs.curr_; } - [[nodiscard]] friend constexpr bitflags operator&(bitflags const& lhs, internal::flag const& rhs) noexcept { + [[nodiscard]] friend constexpr bitflags operator&(bitflags const& lhs, FlagT const& rhs) noexcept { return lhs.curr_ & rhs; } - [[nodiscard]] friend constexpr bitflags operator|(bitflags const& lhs, internal::flag const& rhs) noexcept { + [[nodiscard]] friend constexpr bitflags operator|(bitflags const& lhs, FlagT const& rhs) noexcept { return lhs.curr_ | rhs; } - [[nodiscard]] friend constexpr bitflags operator^(bitflags const& lhs, internal::flag const& rhs) noexcept { + [[nodiscard]] friend constexpr bitflags operator^(bitflags const& lhs, FlagT const& rhs) noexcept { return lhs.curr_ ^ rhs; } - constexpr bitflags& operator&=(internal::flag const& rhs) noexcept { + constexpr bitflags& operator&=(FlagT const& rhs) noexcept { curr_ &= rhs; return *this; } - constexpr bitflags& operator|=(internal::flag const& rhs) noexcept { + constexpr bitflags& operator|=(FlagT const& rhs) noexcept { curr_ |= rhs; return *this; } - constexpr bitflags& operator^=(internal::flag const& rhs) noexcept { + constexpr bitflags& operator^=(FlagT const& rhs) noexcept { curr_ ^= rhs; return *this; } @@ -346,7 +397,7 @@ class bitflags : public ImplT { * * @return Empty set of flags */ - [[nodiscard]] static constexpr internal::flag empty() noexcept { + [[nodiscard]] static constexpr FlagT empty() noexcept { return T{}; } @@ -355,7 +406,7 @@ class bitflags : public ImplT { * * @return Set of all defined flags */ - [[nodiscard]] static constexpr internal::flag all() noexcept { + [[nodiscard]] static constexpr FlagT all() noexcept { return ~T{}; } @@ -386,7 +437,7 @@ class bitflags : public ImplT { * @return True if the specified flags is contained within the * current set of flags, otherwise false */ - [[nodiscard]] constexpr bool contains(internal::flag const& rhs) const noexcept { + [[nodiscard]] constexpr bool contains(FlagT const& rhs) const noexcept { return static_cast(curr_ & rhs) || rhs == empty(); } @@ -401,7 +452,7 @@ class bitflags : public ImplT { * current set of flags, otherwise false */ template - [[nodiscard]] constexpr bool contains(internal::flag const& rhs_1, U const& ... rhs_n) const noexcept { + [[nodiscard]] constexpr bool contains(FlagT const& rhs_1, U const& ... rhs_n) const noexcept { return contains(rhs_1) && contains(rhs_n...); } @@ -410,7 +461,7 @@ class bitflags : public ImplT { * * @param rhs Flag to be set */ - constexpr void set(internal::flag const& rhs) noexcept { + constexpr void set(FlagT const& rhs) noexcept { curr_ |= rhs; } @@ -419,16 +470,17 @@ class bitflags : public ImplT { * * @param rhs Flag to be unset */ - constexpr void remove(internal::flag const& rhs) noexcept { + constexpr void remove(FlagT const& rhs) noexcept { curr_ &= ~rhs; } /** - * Sets specified flag if not already present. Otherwise, unsets the specified flag. + * Sets specified flag if not already present. + * Otherwise, unsets the specified flag. * * @param rhs Flag to be toggled */ - constexpr void toggle(internal::flag const& rhs) noexcept { + constexpr void toggle(FlagT const& rhs) noexcept { curr_ ^= rhs; } @@ -440,27 +492,51 @@ class bitflags : public ImplT { } private: - internal::flag curr_; + FlagT curr_; }; } // bf +/** + * Macros used for creating set of raw flags, + * i.e. flags without string representation. + */ + +#define BEGIN_RAW_BITFLAGS(NAME) \ + template \ + struct NAME##Impl { \ + using flag = bf::internal::raw_flag; \ + static constexpr int begin_ = __LINE__; + +#define END_RAW_BITFLAGS(NAME) \ + static constexpr int end_ = __LINE__; \ + }; \ + using NAME = bf::bitflags< \ + NAME##Impl< bf::bitflags< NAME##Impl >::underlying_type >, \ + bf::bitflags< NAME##Impl >::underlying_type, \ + bf::internal::raw_flag \ + >; + +#define RAW_FLAG(NAME) \ + static constexpr flag NAME{ bf::internal::shift(__LINE__ - begin_ - 2) }; + +/** + * Macros used for creating set of ordinary flags, + * i.e. flags with string representation. + */ + #define BEGIN_BITFLAGS(NAME) \ template \ struct NAME##Impl { \ using flag = bf::internal::flag; \ static constexpr int begin_ = __LINE__; -#define END_BITFLAGS(NAME) \ - static constexpr int end_ = __LINE__; \ - }; \ - using NAME = bf::bitflags< \ - NAME##Impl< \ - bf::bitflags< \ - NAME##Impl \ - >::underlying_type \ - > \ - >; \ +#define END_BITFLAGS(NAME) \ + static constexpr int end_ = __LINE__; \ + }; \ + using NAME = bf::bitflags< \ + NAME##Impl< bf::bitflags< NAME##Impl >::underlying_type > \ + >; #define FLAG(NAME) \ static constexpr flag NAME{ bf::internal::shift(__LINE__ - begin_ - 2), #NAME }; diff --git a/tests/src/bitflags_test.cpp b/tests/src/bitflags_test.cpp index 570212a..54b5035 100644 --- a/tests/src/bitflags_test.cpp +++ b/tests/src/bitflags_test.cpp @@ -31,6 +31,13 @@ #include struct BitflagsTest : testing::Test { + BEGIN_RAW_BITFLAGS(RawFlags) + RAW_FLAG(none) + RAW_FLAG(flag_a) + RAW_FLAG(flag_b) + RAW_FLAG(flag_c) + END_RAW_BITFLAGS(RawFlags) + BEGIN_BITFLAGS(Flags) FLAG(none) FLAG(flag_a) @@ -40,6 +47,13 @@ struct BitflagsTest : testing::Test { }; TEST_F(BitflagsTest, Bits) { + // raw flags (without string representation) + EXPECT_EQ(0b0000U, RawFlags::none.bits); + EXPECT_EQ(0b0001U, RawFlags::flag_a.bits); + EXPECT_EQ(0b0010U, RawFlags::flag_b.bits); + EXPECT_EQ(0b0100U, RawFlags::flag_c.bits); + + // flags (with string representation) EXPECT_EQ(0b0000U, Flags::none.bits); EXPECT_EQ(0b0001U, Flags::flag_a.bits); EXPECT_EQ(0b0010U, Flags::flag_b.bits); @@ -54,6 +68,13 @@ TEST_F(BitflagsTest, Name) { } TEST_F(BitflagsTest, CastToUnderlyingType) { + // raw flags (without string representation) + EXPECT_EQ(0b0000U, static_cast(RawFlags::none)); + EXPECT_EQ(0b0001U, static_cast(RawFlags::flag_a)); + EXPECT_EQ(0b0010U, static_cast(RawFlags::flag_b)); + EXPECT_EQ(0b0100U, static_cast(RawFlags::flag_c)); + + // flags (with string representation) EXPECT_EQ(0b0000U, static_cast(Flags::none)); EXPECT_EQ(0b0001U, static_cast(Flags::flag_a)); EXPECT_EQ(0b0010U, static_cast(Flags::flag_b)); @@ -61,6 +82,14 @@ TEST_F(BitflagsTest, CastToUnderlyingType) { } TEST_F(BitflagsTest, OperatorNot) { + // raw flags (without string representation) + RawFlags raw_flags = ~RawFlags::none; + + EXPECT_TRUE(raw_flags & RawFlags::flag_a); + EXPECT_TRUE(raw_flags & RawFlags::flag_b); + EXPECT_TRUE(raw_flags & RawFlags::flag_c); + + // flags (with string representation) Flags flags = ~Flags::none; EXPECT_TRUE(flags & Flags::flag_a); @@ -69,6 +98,14 @@ TEST_F(BitflagsTest, OperatorNot) { } TEST_F(BitflagsTest, OperatorAnd) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a | RawFlags::flag_b; + + EXPECT_TRUE(raw_flags & RawFlags::flag_a); + EXPECT_TRUE(raw_flags & RawFlags::flag_b); + EXPECT_FALSE(raw_flags & RawFlags::flag_c); + + // flags (with string representation) Flags flags = Flags::flag_a | Flags::flag_b; EXPECT_TRUE(flags & Flags::flag_a); @@ -77,11 +114,28 @@ TEST_F(BitflagsTest, OperatorAnd) { } TEST_F(BitflagsTest, OperatorOr) { + // raw flags (without string representation) + EXPECT_EQ(0b0011U, RawFlags::flag_a | RawFlags::flag_b); + EXPECT_EQ(0b0111U, RawFlags::flag_a | RawFlags::flag_b | RawFlags::flag_c); + + // flags (with string representation) EXPECT_EQ(0b0011U, Flags::flag_a | Flags::flag_b); EXPECT_EQ(0b0111U, Flags::flag_a | Flags::flag_b | Flags::flag_c); } TEST_F(BitflagsTest, OperatorXor) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a; + + EXPECT_EQ(0b0001U, raw_flags); + + raw_flags ^= RawFlags::flag_a; + EXPECT_EQ(0b0000U, raw_flags); + + raw_flags ^= RawFlags::flag_a; + EXPECT_EQ(0b0001U, raw_flags); + + // flags (with string representation) Flags flags = Flags::flag_a; EXPECT_EQ(0b0001U, flags); @@ -94,6 +148,16 @@ TEST_F(BitflagsTest, OperatorXor) { } TEST_F(BitflagsTest, Empty) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::empty(); + + EXPECT_TRUE(raw_flags.is_empty()); + EXPECT_FALSE(raw_flags.is_all()); + EXPECT_FALSE(raw_flags & RawFlags::flag_a); + EXPECT_FALSE(raw_flags & RawFlags::flag_b); + EXPECT_FALSE(raw_flags & RawFlags::flag_c); + + // flags (with string representation) Flags flags = Flags::empty(); EXPECT_TRUE(flags.is_empty()); @@ -104,6 +168,16 @@ TEST_F(BitflagsTest, Empty) { } TEST_F(BitflagsTest, All) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::all(); + + EXPECT_FALSE(raw_flags.is_empty()); + EXPECT_TRUE(raw_flags.is_all()); + EXPECT_TRUE(raw_flags & RawFlags::flag_a); + EXPECT_TRUE(raw_flags & RawFlags::flag_b); + EXPECT_TRUE(raw_flags & RawFlags::flag_c); + + // flags (with string representation) Flags flags = Flags::all(); EXPECT_FALSE(flags.is_empty()); @@ -114,6 +188,18 @@ TEST_F(BitflagsTest, All) { } TEST_F(BitflagsTest, Contains) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a | RawFlags::flag_b; + + EXPECT_TRUE(raw_flags.contains(RawFlags::none)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + EXPECT_TRUE(raw_flags.contains(RawFlags::none, RawFlags::flag_a, RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::none, RawFlags::flag_a, RawFlags::flag_c)); + + // flags (with string representation) Flags flags = Flags::flag_a | Flags::flag_b; EXPECT_TRUE(flags.contains(Flags::none)); @@ -126,6 +212,21 @@ TEST_F(BitflagsTest, Contains) { } TEST_F(BitflagsTest, Set) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::none; + + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + raw_flags.set(RawFlags::flag_a); + raw_flags.set(RawFlags::flag_b); + + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + // flags (with string representation) Flags flags = Flags::none; EXPECT_FALSE(flags.contains(Flags::flag_a)); @@ -141,6 +242,21 @@ TEST_F(BitflagsTest, Set) { } TEST_F(BitflagsTest, Remove) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a | RawFlags::flag_b | RawFlags::flag_c; + + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_c)); + + raw_flags.remove(RawFlags::flag_a); + raw_flags.remove(RawFlags::flag_b); + + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_c)); + + // flags (with string representation) Flags flags = Flags::flag_a | Flags::flag_b | Flags::flag_c; EXPECT_TRUE(flags.contains(Flags::flag_a)); @@ -156,6 +272,28 @@ TEST_F(BitflagsTest, Remove) { } TEST_F(BitflagsTest, Toggle) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a | RawFlags::flag_b; + + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + raw_flags.toggle(RawFlags::flag_a); + raw_flags.toggle(RawFlags::flag_c); + + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_c)); + + raw_flags.toggle(RawFlags::flag_a); + raw_flags.toggle(RawFlags::flag_b); + + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_c)); + + // flags (with string representation) Flags flags = Flags::flag_a | Flags::flag_b; EXPECT_TRUE(flags.contains(Flags::flag_a)); @@ -178,6 +316,21 @@ TEST_F(BitflagsTest, Toggle) { } TEST_F(BitflagsTest, Clear) { + // raw flags (without string representation) + RawFlags raw_flags = RawFlags::flag_a | RawFlags::flag_b; + + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_TRUE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + raw_flags.clear(); + + EXPECT_TRUE(raw_flags.is_empty()); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_a)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_b)); + EXPECT_FALSE(raw_flags.contains(RawFlags::flag_c)); + + // flags (with string representation) Flags flags = Flags::flag_a | Flags::flag_b; EXPECT_TRUE(flags.contains(Flags::flag_a)); From 181d9ba7bd73ae1b003a6552437316b5be5620c9 Mon Sep 17 00:00:00 2001 From: m-peko Date: Sun, 11 Oct 2020 10:38:22 +0200 Subject: [PATCH 2/2] Update README.md --- README.md | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f857f60..6497210 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ int main() { * [Motivation](#motivation) * [Getting Started](#getting-started) + * [Raw flags vs flags](#raw-flags-vs-flags) * [How to Declare Set of Flags?](#how-to-declare-set-of-flags) * [Bits and Names](#bits-and-names) * [Bitwise Operators](#bitwise-operators) @@ -94,9 +95,29 @@ _So, why should I use `bitflags` library?_ `bitflags` is a single-header header-only C++17 library for easily managing set of auto-generated type-safe flags. +### Raw flags vs flags? + +`bitflags` library provides you with 2 flag types: + +- __raw_flag__ without its string representation (sort of lightweight version) +- __flag__ with its string representation + ### How to Declare Set of Flags? -In order to declare a set of auto-generated flags, there are few helper macros that hide kind of "ugly" declaration syntax and provide auto-generated value for each flag: +In order to declare a set of auto-generated flags, there are few helper macros that hide kind of "ugly" declaration syntax and provide auto-generated value for each flag. + +Macros for creating set of raw flags, i.e. flags __without__ string representation: + +* `BEGIN_RAW_BITFLAGS(NAME)` + - `NAME` - name of set of raw flags + +* `RAW_FLAG(NAME)` + - `NAME` - name of specific raw flag + +* `END_RAW_BITFLAGS(NAME)` + - `NAME` - name of set of raw flags + +Macros for creating set of ordinary flags, i.e. flags __with__ string representation: * `BEGIN_BITFLAGS(NAME)` - `NAME` - name of set of flags @@ -139,10 +160,26 @@ using Flags = bf::bitflags< >; ``` +Usage is basically the same for `raw_flag`s. + ### Bits and Names +While bits are part of both `raw_flag` and `flag`, names are part of `flag` type only. + Once the flags are specified, it is possible to get bits representing each flag as well as string representation of each flag: +```cpp +BEGIN_RAW_BITFLAGS(RawFlags) + RAW_FLAG(none) + RAW_FLAG(flag_a) + RAW_FLAG(flag_b) +END_RAW_BITFLAGS(RawFlags) + +std::cout << RawFlags::flag_a.bits << std::endl; +``` + +and + ```cpp BEGIN_BITFLAGS(Flags) FLAG(none)