diff --git a/BUILD.bazel b/BUILD.bazel index 41554d2..2e08379 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -6,7 +6,7 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "magic_enum", - hdrs = ["include/magic_enum.hpp"], + hdrs = ["include/magic_enum.hpp", "include/magic_enum_fuse.hpp"], includes = ["include"], ) diff --git a/doc/reference.md b/doc/reference.md index 6759e3c..4ebdbf6 100644 --- a/doc/reference.md +++ b/doc/reference.md @@ -350,6 +350,8 @@ template [[nodiscard]] constexpr optional enum_fuse(Es... values) noexcept; ``` +* You should add the required file ``. + * Returns a typesafe bijective mix of several enum values. This can be used to emulate 2D switch/case statements. * Return type is `optional` where `enum_fuse_t` is an incomplete enum, it is unique for any given combination of `Es...`. diff --git a/include/magic_enum.hpp b/include/magic_enum.hpp index 5c763a7..118b392 100644 --- a/include/magic_enum.hpp +++ b/include/magic_enum.hpp @@ -1277,54 +1277,6 @@ constexpr auto enum_for_each(Lambda&& lambda) { return detail::for_each(std::forward(lambda), std::make_index_sequence>{}); } -namespace detail { - -template -constexpr optional fuse_one_enum(optional hash, E value) noexcept { - if (hash) { - if (const auto index = enum_index(value)) { - return (*hash << log2(enum_count() + 1)) | *index; - } - } - return {}; -} - -template -constexpr optional fuse_enum(E value) noexcept { - return fuse_one_enum(0, value); -} - -template -constexpr optional fuse_enum(E head, Es... tail) noexcept { - return fuse_one_enum(fuse_enum(tail...), head); -} - -template -constexpr auto typesafe_fuse_enum(Es... values) noexcept { - enum class enum_fuse_t : std::uintmax_t; - const auto fuse = fuse_enum(values...); - if (fuse) { - return optional{static_cast(*fuse)}; - } - return optional{}; -} - -} // namespace magic_enum::detail - -// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. -template -[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { - static_assert((std::is_enum_v> && ...), "magic_enum::enum_fuse requires enum type."); - static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values."); - static_assert((detail::log2(enum_count() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums"); -#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE) - const auto fuse = detail::fuse_enum...>(values...); -#else - const auto fuse = detail::typesafe_fuse_enum...>(values...); -#endif - return assert(fuse), fuse; -} - namespace ostream_operators { template = 0> diff --git a/include/magic_enum_fuse.hpp b/include/magic_enum_fuse.hpp new file mode 100644 index 0000000..16f4834 --- /dev/null +++ b/include/magic_enum_fuse.hpp @@ -0,0 +1,89 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.8.0 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2022 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_FUSE_HPP +#define NEARGYE_MAGIC_ENUM_FUSE_HPP + +#include "magic_enum.hpp" + +namespace magic_enum { + +namespace detail { + +template +constexpr optional fuse_one_enum(optional hash, E value) noexcept { + if (hash) { + if (const auto index = enum_index(value)) { + return (*hash << log2(enum_count() + 1)) | *index; + } + } + return {}; +} + +template +constexpr optional fuse_enum(E value) noexcept { + return fuse_one_enum(0, value); +} + +template +constexpr optional fuse_enum(E head, Es... tail) noexcept { + return fuse_one_enum(fuse_enum(tail...), head); +} + +template +constexpr auto typesafe_fuse_enum(Es... values) noexcept { + enum class enum_fuse_t : std::uintmax_t; + const auto fuse = fuse_enum(values...); + if (fuse) { + return optional{static_cast(*fuse)}; + } + return optional{}; +} + +} // namespace magic_enum::detail + +// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. +template +[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { + static_assert((std::is_enum_v> && ...), "magic_enum::enum_fuse requires enum type."); + static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values."); + static_assert((detail::log2(enum_count>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums"); +#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE) + const auto fuse = detail::fuse_enum...>(values...); +#else + const auto fuse = detail::typesafe_fuse_enum...>(values...); +#endif + return assert(fuse), fuse; +} + +} // namespace magic_enum + +#endif // NEARGYE_MAGIC_ENUM_FUSE_HPP diff --git a/test/test.cpp b/test/test.cpp index cf79c02..84967c3 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -28,6 +28,7 @@ #undef MAGIC_ENUM_RANGE_MAX #define MAGIC_ENUM_RANGE_MAX 120 #include +#include #include #include diff --git a/test/test_flags.cpp b/test/test_flags.cpp index aa7a9bc..0c14a5d 100644 --- a/test/test_flags.cpp +++ b/test/test_flags.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include