diff --git a/include/magic_enum_flags.hpp b/include/magic_enum_flags.hpp new file mode 100644 index 0000000..b10593f --- /dev/null +++ b/include/magic_enum_flags.hpp @@ -0,0 +1,59 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.1 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP +#define NEARGYE_MAGIC_ENUM_FLAGS_HPP + +#include "magic_enum.hpp" + +namespace magic_enum { + +// Checks whether `flags set` contains `flag`. +// Note: If `flag` equals 0, it returns false, as 0 is not a flag. +template +constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t { + using U = underlying_type_t; + + return static_cast(static_cast(flags) & static_cast(flag)); +} + +// Checks whether `lhs flags set` and `rhs flags set` have common flags. +// Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag. +template +constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t { + using U = underlying_type_t; + + return (static_cast(lhs) & static_cast(rhs)) != 0; +} + +} // namespace magic_enum + +#endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP diff --git a/test/test_flags.cpp b/test/test_flags.cpp index 9a960a1..1f13435 100644 --- a/test/test_flags.cpp +++ b/test/test_flags.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -48,6 +49,7 @@ struct magic_enum::customize::enum_range { }; enum class Numbers : int { + none = 0, one = 1 << 1, two = 1 << 2, three = 1 << 3, @@ -59,6 +61,7 @@ struct magic_enum::customize::enum_range { }; enum Directions : std::uint64_t { + NoDirection = 0, Left = std::uint64_t{1} << 10, Down = std::uint64_t{1} << 20, Up = std::uint64_t{1} << 31, @@ -70,6 +73,7 @@ struct magic_enum::customize::enum_range { }; enum number : unsigned long { + no_number = 0, one = 1 << 1, two = 1 << 2, three = 1 << 3, @@ -722,3 +726,45 @@ TEST_CASE("format-base") { } #endif + +TEST_CASE("enum_flags_test") { + REQUIRE(enum_flags_test(Color::RED|Color::GREEN, Color::RED)); + REQUIRE_FALSE(enum_flags_test(Color::RED|Color::GREEN, Color::BLUE)); + + REQUIRE_FALSE(enum_flags_test(Numbers::none, Numbers::none)); + REQUIRE_FALSE(enum_flags_test(Numbers::none, Numbers::one)); + REQUIRE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::many)); + REQUIRE_FALSE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::three)); + REQUIRE_FALSE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::none)); + + REQUIRE_FALSE(enum_flags_test(Left|Right, NoDirection)); + REQUIRE(enum_flags_test(Left|Right|Up|Down, Right)); + REQUIRE_FALSE(enum_flags_test(Left|Up|Down, Right)); + + REQUIRE(enum_flags_test(number::one|number::two|number::four, number::one)); + REQUIRE_FALSE(enum_flags_test(number::one|number::two|number::four, number::three)); + REQUIRE_FALSE(enum_flags_test(number::one|number::two|number::four, number::no_number)); +} + +TEST_CASE("enum_flags_test_any") { + REQUIRE(enum_flags_test_any(Color::RED|Color::GREEN, Color::RED)); + REQUIRE_FALSE(enum_flags_test_any(Color::RED|Color::GREEN, Color::BLUE)); + + REQUIRE_FALSE(enum_flags_test_any(Numbers::none, Numbers::none)); + REQUIRE_FALSE(enum_flags_test_any(Numbers::none, Numbers::one)); + REQUIRE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::many)); + REQUIRE_FALSE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::three)); + REQUIRE_FALSE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::none)); + + REQUIRE_FALSE(enum_flags_test_any(Left|Right, NoDirection)); + REQUIRE(enum_flags_test_any(Left|Right|Up|Down, Right)); + REQUIRE_FALSE(enum_flags_test_any(Left|Up|Down, Right)); + + REQUIRE(enum_flags_test_any(number::one|number::two|number::four, number::one)); + REQUIRE_FALSE(enum_flags_test_any(number::one|number::two|number::four, number::three)); + REQUIRE_FALSE(enum_flags_test_any(number::one|number::two|number::four, number::no_number)); + + REQUIRE(enum_flags_test(Numbers::none, Numbers::none) == enum_flags_test_any(Numbers::none, Numbers::none)); + REQUIRE(enum_flags_test(Numbers::one, Numbers::none) == enum_flags_test_any(Numbers::one, Numbers::none)); + REQUIRE(enum_flags_test(Numbers::none, Numbers::one) == enum_flags_test_any(Numbers::none, Numbers::one)); +}