#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include "llvm/Support/YAMLTraits.h" #include "revng/ADT/Concepts.h" /// Trait to provide name of the tuple-like class and its fields template struct TupleLikeTraits { enum class Fields { }; }; template requires(std::is_const_v) struct TupleLikeTraits : TupleLikeTraits> {}; namespace detail { template using Tuple = typename TupleLikeTraits::tuple; template concept HasTuple = StrictSpecializationOf, std::tuple>; } // namespace detail template concept TraitedTupleLike = requires { { TupleLikeTraits::Name } -> std::convertible_to; { TupleLikeTraits::FullName } -> std::convertible_to; { TupleLikeTraits::FieldNames } -> std::convertible_to>; typename TupleLikeTraits::tuple; typename TupleLikeTraits::Fields; // TODO: this should also check for `get(std::declval())`, but there's // an empty struct in `SerializableGraph.h` for which it's impossible // to instantiate. } && detail::HasTuple && std::is_enum_v::Fields>; // // Implementation of MappingTraits for TupleLikeTraits implementers // /// Tuple-like can implement llvm::yaml::MappingTraits inheriting this class template::Fields... Optionals> struct TupleLikeMappingTraits { using Fields = typename TupleLikeTraits::Fields; template static constexpr bool isOptional() { constexpr size_t Count = sizeof...(Optionals); constexpr std::array OptionalsArray{ Optionals... }; if constexpr (I < Count) { return (OptionalsArray[I] == Index) || isOptional(); } else { return false; } } // Recursive step template static void mapping(llvm::yaml::IO &IO, T &Obj) { if constexpr (I < std::tuple_size_v) { auto Name = TupleLikeTraits::FieldNames[I]; constexpr Fields Field = static_cast(I); auto &Element = get(Obj); if constexpr (isOptional()) IO.mapOptional(Name.data(), Element, std::tuple_element_t{}); else IO.mapRequired(Name.data(), Element); // Recur mapping(IO, Obj); } } }; template struct std::tuple_element { using type = std::tuple_element_t::tuple>; }; template using TupleLikeTraitsTuple = typename TupleLikeTraits::tuple; template struct std::tuple_size : std::integral_constant>> { };