#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include #include // // The concepts from the STL. // TODO: remove these after updating the libc++ version. // template concept equality_comparable = requires(T &&LHS, T &&RHS) { { LHS == RHS } -> std::convertible_to; }; // clang-format off template concept invocable = requires(F&& Function, Args &&...Arguments) { std::invoke(std::forward(Function), std::forward(Arguments)...); }; // NOTE: this is supposed to use `std::regular_invocable`, but the difference // is not major in most cases, so use `invocable` until we update libc++. template concept predicate = invocable && std::is_convertible_v, bool>; // clang-format on /// TODO: Remove after updating to clang-format with concept support. struct ClangFormatPleaseDoNotBreakMyCode; // clang-format off // clang-format on // // 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 std::size_t Size = std::tuple_size_v; return checkTupleElementTypes(std::make_index_sequence()); } } // namespace revng::detail // clang-format off template concept TupleLike = (TupleSizeCompatible and revng::detail::checkAllTupleElementTypes()); // clang-format on 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. /// /// TODO: this requires clang-13+, uncomment it after the update. // template class Ref> // concept SpecializationOf = requires(Type &&Value) { // [](Ref &){}(Value); // }; // // static_assert(SpecializationOf, std::pair>); // static_assert(SpecializationOf, std::pair>); // static_assert(SpecializationOf); // static_assert(SpecializationOf); // static_assert(not SpecializationOf); /// TODO: Remove after updating to clang-format with concept support. struct ClangFormatPleaseDoNotBreakMyCode; // clang-format off // clang-format on 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; static_assert(StrictSpecializationOf, std::pair>); static_assert(StrictSpecializationOf, std::pair>); static_assert(StrictSpecializationOf); static_assert(not StrictSpecializationOf); static_assert(not StrictSpecializationOf); // // Other Miscellaneous concepts. // template concept ConstOrNot = std::is_same_v or std::is_same_v; // clang-format off template concept range_with_value_type = std::ranges::range && std::is_convertible_v; // clang-format on