Files
2023-04-08 08:42:23 +02:00

56 lines
1.9 KiB
C++

#pragma once
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <cstddef>
#include <type_traits>
#include "revng/ADT/Concepts.h"
#include "revng/Support/Debug.h"
namespace revng::detail {
template<typename T>
concept EnumWithCount = requires {
requires std::is_enum<typename std::decay<T>::type>::value;
{ std::decay_t<T>::Count } -> std::convertible_to<size_t>;
};
} // namespace revng::detail
/// Calls the `operator()<Enumerator>()` 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<revng::detail::EnumWithCount Enum,
size_t From = 0,
size_t To = size_t(std::decay_t<Enum>::Count)>
constexpr inline auto enumSwitch(Enum Value, const auto &F) {
using Decayed = typename std::decay<Enum>::type;
constexpr Decayed Current = static_cast<Decayed>(From);
if (Current == Value)
return F.template operator()<Current>();
else if constexpr (From + 1 < To)
return enumSwitch<Enum, From + 1>(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<size_t SkippedCount, revng::detail::EnumWithCount Enum>
constexpr inline auto skippingEnumSwitch(Enum Value, const auto &F) {
return enumSwitch<Enum, SkippedCount>(Value, F);
}