#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include "llvm/ADT/StringRef.h" #include "revng/ADT/TypeList.h" #include "revng/PipeboxCommon/Common.h" #include "revng/PipeboxCommon/Model.h" #include "revng/PipeboxCommon/ObjectID.h" template concept HasName = requires { { T::Name } -> std::same_as; requires not T::Name.empty(); }; // // IsContainer // template concept IsContainer = requires(T &A, const T &AConst) { requires HasName; { T() } -> std::same_as; { T::Kind } -> std::same_as; { T::MimeType } -> std::same_as; { AConst.objects() } -> std::same_as>; { AConst.verify() } -> std::same_as; { A.deserialize(std::declval< const std::map>>()) } -> std::same_as; { AConst.serialize(std::declval>()) } -> std::same_as>; }; namespace detail { template constexpr bool IsContainerArgument = IsContainer; template constexpr bool IsContainerArgument = IsContainer; template constexpr bool IsContainerReference = false; template constexpr bool IsContainerReference = IsContainerArgument; } // namespace detail // // IsAnalysis // namespace detail { template struct AnalysisRunTraits {}; template requires(IsContainerReference and ...) struct AnalysisRunTraits { using ContainerTypes = TypeList...>; static constexpr size_t ContainerCount = sizeof...(Args); }; } // namespace detail template using AnalysisRunTraits = detail::AnalysisRunTraits; template concept IsAnalysis = requires(T &A) { requires HasName; { T() } -> std::same_as; requires AnalysisRunTraits::ContainerCount >= 0; }; /// Optional method that an analysis can implement template concept HasIsAvailable = requires(const T &A) { { A.isAvailable() } -> std::same_as; }; // // IsPipe // namespace detail { template concept HasContainerTypes = SpecializationOf; template struct PipeRunTraitsHelper {}; template requires(not HasContainerTypes) and (IsContainerReference and ...) struct PipeRunTraitsHelper< revng::pypeline::PipeOutput (C::*)(const Model &, const revng::pypeline::Request &, const revng::pypeline::Request &, llvm::StringRef, Args...)> { using ContainerTypes = TypeList...>; }; template struct PipeRunTraits {}; template struct PipeRunTraits { using ContainerTypes = T::ContainerTypes; static constexpr size_t ContainerCount = std::tuple_size_v; }; template requires(not HasContainerTypes) struct PipeRunTraits { using ContainerTypes = PipeRunTraitsHelper::ContainerTypes; static constexpr size_t ContainerCount = std::tuple_size_v; }; template concept IsPipeArgument = requires { { T::Access } -> std::same_as; { T::Name } -> std::same_as; { T::HelpText } -> std::same_as; }; template List> inline constexpr bool checkArguments() { constexpr bool Size = std::tuple_size_v; return compile_time::repeatAnd([]() { return IsPipeArgument>; }); } template inline constexpr size_t ArgSize = std::tuple_size_v; } // namespace detail template concept HasArguments = requires { requires StrictSpecializationOf; requires detail::checkArguments(); }; template using PipeRunTraits = detail::PipeRunTraits; template concept IsPipe = requires(T &A, llvm::StringRef StaticConfig) { requires HasName; { T(StaticConfig) } -> std::same_as; { A.StaticConfiguration } -> std::same_as; requires HasArguments; requires PipeRunTraits::ContainerCount == detail::ArgSize; }; /// Optional method that a pipe can implement template concept HasCheckPrecondition = requires(const T &A, const Model &Model) { { A.checkPrecondition(Model) } -> std::same_as; }; /// Optional method that a pipe can implement template concept HasInvalidate = requires(const T &A, const revng::pypeline::InvalidationData &ID, const ModelDiff &Diff) { { A.invalidate(ID, Diff) } -> std::same_as>>; }; // // Generic helpers // /// Helper struct that dispatches to PipeRunTraits or AnalysisRunTraits as /// needed. template struct GenericRunTraits {}; template struct GenericRunTraits : public PipeRunTraits {}; template struct GenericRunTraits : public AnalysisRunTraits {};