#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include "revng/ADT/Concepts.h" #include "revng/Support/Debug.h" namespace revng::detail { template concept EnumWithCount = requires { requires std::is_enum::type>::value; { std::decay_t::Count } -> std::convertible_to; }; } // namespace revng::detail /// Calls the `operator()()` of the callable `F` object passed /// as the second parameter, where `Enumerator` corresponds to the runtime /// argument passed as the first parameter (`Value`). /// /// This can also be used as a simple way to instantiate a templated object /// or function for every possible value of the specified enumeration. /// /// \note: it requires the enumeration to contain the `Count` element to /// mark the "one-after-the-last" enumerator. /// /// \note: the behaviour is undefined if the enumeration is not continuous. template::Count)> constexpr inline auto enumSwitch(Enum Value, const auto &F) { using Decayed = typename std::decay::type; constexpr Decayed Current = static_cast(From); if (Current == Value) return F.template operator()(); else if constexpr (From + 1 < To) return enumSwitch(Value, F); else revng_abort("Unknown and/or unsupported enum value was encountered"); } /// A specialized version of `enumSwitch` that allows skipping `SkippedCount` /// first enumerators. The most typical use case it so avoid instantiating /// templates for the first `Invalid = 0` enumerator. template constexpr inline auto skippingEnumSwitch(Enum Value, const auto &F) { return enumSwitch(Value, F); }