#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include #include // // Concepts to simplify working with tuples. // template concept TupleSizeCompatible = requires { std::tuple_size::value; { std::tuple_size_v } -> std::convertible_to; }; static_assert(TupleSizeCompatible>); static_assert(!TupleSizeCompatible>); static_assert(!TupleSizeCompatible); namespace revng::detail { template concept TupleElementCompatibleHelper = requires(T Value) { typename std::tuple_element_t>; { get(Value) } -> std::convertible_to &>; }; template constexpr auto checkTupleElementTypes(std::index_sequence) { return (TupleElementCompatibleHelper && ...); } template constexpr auto checkAllTupleElementTypes() { constexpr size_t Size = std::tuple_size_v; return checkTupleElementTypes(std::make_index_sequence()); } } // namespace revng::detail template concept TupleLike = (TupleSizeCompatible and revng::detail::checkAllTupleElementTypes()); static_assert(TupleLike>); static_assert(TupleLike>); static_assert(TupleLike>); static_assert(TupleLike>); static_assert(not TupleLike>); // // Concepts to simplify working with specializations of templates. // /// A concept that helps determine whether a given object is a specialization /// (or is inheriting a specialization) of a given template. /// /// This lets us cut down on the number of `IsX` (e.g. `IsGenericGraph`, /// `IsRank`) concepts needed since we can now just say /// `SpecializationOf` on the interface boundaries and get /// the expected check. template class Ref> concept SpecializationOf = requires(Type &Value) { [](Ref &) { }(const_cast &>(Value)); }; template concept NonBaseDerived = std::derived_from and not std::is_same_v; namespace revng::detail { template class Ref> struct StrictSpecializationHelper : std::false_type {}; template class Ref, typename... Args> struct StrictSpecializationHelper, Ref> : std::true_type {}; template class Ref, typename... Args> struct StrictSpecializationHelper, Ref> : std::true_type {}; template class Ref> constexpr bool StrictSpecialization = StrictSpecializationHelper::value; } // namespace revng::detail /// A more strict version of the `SpecializationOf` concept. This one only /// allows direct specializations (and aliases) - no inheritance. /// /// It's useful in the cases when template parameter deduction is important, /// e.g. when instantiating traits. template class Ref> concept StrictSpecializationOf = revng::detail::StrictSpecialization; // // Other Miscellaneous concepts. // template concept ConstOrNot = std::is_same_v or std::is_same_v; template constexpr bool IsConstReference = std::is_const_v>; template using ConstPtrIfConst = std::conditional_t, const T *, T *>; template concept RangeOf = std::ranges::range and std::is_convertible_v, ValueType>; template requires(sizeof...(Types) > 0) inline constexpr bool anyOf() { return (std::is_same_v || ...); }