diff --git a/headers/enum.hpp/enum_bitflags.hpp b/headers/enum.hpp/enum_bitflags.hpp index a84d275..df2ac34 100644 --- a/headers/enum.hpp/enum_bitflags.hpp +++ b/headers/enum.hpp/enum_bitflags.hpp @@ -18,7 +18,6 @@ namespace enum_hpp::bitflags using underlying_type = std::underlying_type_t; bitflags() = default; - bitflags(const bitflags&) = default; bitflags& operator=(const bitflags&) = default; @@ -39,6 +38,25 @@ namespace enum_hpp::bitflags constexpr enum_type as_enum() const noexcept { return static_cast(flags_); } + + constexpr bool has(bitflags flags) const noexcept { + return flags.flags_ == (flags_ & flags.flags_); + } + + constexpr bitflags& set(bitflags flags) noexcept { + flags_ |= flags.flags_; + return *this; + } + + constexpr bitflags& toggle(bitflags flags) noexcept { + flags_ ^= flags.flags_; + return *this; + }; + + constexpr bitflags& clear(bitflags flags) noexcept { + flags_ &= ~flags.flags_; + return *this; + } private: underlying_type flags_{}; }; diff --git a/untests/enum_bitflags_tests.cpp b/untests/enum_bitflags_tests.cpp index 00b7fbb..ab96d14 100644 --- a/untests/enum_bitflags_tests.cpp +++ b/untests/enum_bitflags_tests.cpp @@ -17,7 +17,9 @@ namespace none = 0, read = 1 << 0, write = 1 << 1, + execute = 1 << 2, read_write = read | write, + all = read_write | execute }; ENUM_HPP_REGISTER_BITFLAGS_OPERATORS(access) @@ -26,6 +28,38 @@ namespace TEST_CASE("enum_bitflags") { namespace bf = enum_hpp::bitflags; + SUBCASE("ctors") { + { + constexpr bf::bitflags f; + STATIC_CHECK(!f); + STATIC_CHECK(f.as_raw() == 0x0); + STATIC_CHECK(f.as_enum() == access::none); + } + { + constexpr bf::bitflags f = access::read_write; + STATIC_CHECK(!!f); + STATIC_CHECK(f.as_raw() == 0x3); + STATIC_CHECK(f.as_enum() == access::read_write); + } + { + constexpr bf::bitflags f{0x3}; + STATIC_CHECK(!!f); + STATIC_CHECK(f.as_raw() == 0x3); + STATIC_CHECK(f.as_enum() == access::read_write); + } + { + constexpr bf::bitflags f = access::read | access::write; + constexpr bf::bitflags g = f; + STATIC_CHECK(g.as_raw() == 0x3); + } + { + constexpr bf::bitflags f = access::read | access::write; + bf::bitflags g; + g = f; + CHECK(g.as_raw() == 0x3); + } + } + SUBCASE("enum_operators") { STATIC_CHECK((~access::read) == bf::bitflags(0xFE)); STATIC_CHECK((access::read | access::write) == bf::bitflags(0x3)); @@ -177,6 +211,71 @@ TEST_CASE("enum_bitflags") { } } + SUBCASE("has") { + constexpr bf::bitflags f = access::read_write; + STATIC_CHECK(f.has(access::read)); + STATIC_CHECK(f.has(access::read_write)); + STATIC_CHECK(f.has(access::read | access::write)); + STATIC_CHECK_FALSE(f.has(access::execute)); + STATIC_CHECK_FALSE(f.has(access::read | access::execute)); + } + + SUBCASE("set") { + bf::bitflags f; + CHECK(&f == &f.set(access::read)); + CHECK(f.has(access::read)); + CHECK(&f == &f.set(access::read | access::write)); + CHECK(f.has(access::read | access::write)); + CHECK_FALSE(f.has(access::execute)); + } + + SUBCASE("toggle") { + bf::bitflags f = access::read_write; + + CHECK(&f == &f.toggle(access::read)); + CHECK_FALSE(f.has(access::read)); + CHECK(f.has(access::write)); + CHECK_FALSE(f.has(access::execute)); + + CHECK(&f == &f.toggle(access::read | access::write)); + CHECK(f.has(access::read)); + CHECK_FALSE(f.has(access::write)); + CHECK_FALSE(f.has(access::execute)); + + CHECK(&f == &f.toggle(access::execute)); + CHECK(f.has(access::read)); + CHECK_FALSE(f.has(access::write)); + CHECK(f.has(access::execute)); + } + + SUBCASE("clear") { + { + bf::bitflags f = access::all; + + CHECK(&f == &f.clear(access::read)); + CHECK_FALSE(f.has(access::read)); + CHECK(f.has(access::write)); + CHECK(f.has(access::execute)); + + CHECK(&f == &f.clear(access::read | access::execute)); + CHECK_FALSE(f.has(access::read)); + CHECK(f.has(access::write)); + CHECK_FALSE(f.has(access::execute)); + } + { + bf::bitflags f = access::all; + CHECK(&f == &f.clear(access::write | access::execute)); + CHECK(f.has(access::read)); + CHECK_FALSE(f.has(access::write)); + CHECK_FALSE(f.has(access::execute)); + + CHECK(&f == &f.clear(access::read | access::execute)); + CHECK_FALSE(f.has(access::read)); + CHECK_FALSE(f.has(access::write)); + CHECK_FALSE(f.has(access::execute)); + } + } + SUBCASE("any") { STATIC_CHECK_FALSE(bf::any(access::none)); STATIC_CHECK(bf::any(access::read));