From 7671c2974456a5909df74da096d8deaa9463e7d8 Mon Sep 17 00:00:00 2001 From: PragmaTwice Date: Sat, 5 Jul 2025 14:44:21 +0800 Subject: [PATCH] [FFI] Replace Arg2Str with a more powerful for_each --- ffi/include/tvm/ffi/base_details.h | 21 +++++++++++++++++++- ffi/include/tvm/ffi/function_details.h | 27 ++++++++------------------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/ffi/include/tvm/ffi/base_details.h b/ffi/include/tvm/ffi/base_details.h index fb7be1a955ba..d078a5963ab7 100644 --- a/ffi/include/tvm/ffi/base_details.h +++ b/ffi/include/tvm/ffi/base_details.h @@ -29,6 +29,7 @@ #include #include +#include #include #if defined(_MSC_VER) @@ -135,14 +136,32 @@ namespace tvm { namespace ffi { namespace details { +// a dependent-name version of false, for static_assert +template +inline constexpr bool always_false = false; + // for each iterator struct for_each_dispatcher { template static void run(std::index_sequence, const F& f, Args&&... args) { // NOLINT(*) - (f(I, std::forward(args)), ...); + if constexpr (std::conjunction_v< + std::is_invocable, Args>...>) { + (f(std::integral_constant{}, std::forward(args)), ...); + } else if constexpr (std::conjunction_v...>) { + (f(I, std::forward(args)), ...); + } else if constexpr (std::conjunction_v...>) { + (f(std::forward(args)), ...); + } else { + static_assert(always_false, "The function is not invocable with the provided arguments"); + } } }; +// Three kinds of function F are acceptable in `for_each`: +// 1. F(size_t, Arg): argument with its index +// 2. F(Arg): just the argument +// 3. F(std::integral_constant, Arg): argument with its constexpr index +// The third one can make the index available in template arguments and `if constexpr`. template void for_each(const F& f, Args&&... args) { // NOLINT(*) for_each_dispatcher::run(std::index_sequence_for{}, f, std::forward(args)...); diff --git a/ffi/include/tvm/ffi/function_details.h b/ffi/include/tvm/ffi/function_details.h index d029c19dd107..34e9979d5d56 100644 --- a/ffi/include/tvm/ffi/function_details.h +++ b/ffi/include/tvm/ffi/function_details.h @@ -36,23 +36,6 @@ namespace tvm { namespace ffi { namespace details { -template -struct Arg2Str { - template - TVM_FFI_INLINE static void Apply(std::ostream& os) { - using Arg = std::tuple_element_t; - if constexpr (i != 0) { - os << ", "; - } - os << i << ": " << Type2Str::v(); - } - template - TVM_FFI_INLINE static void Run(std::ostream& os, std::index_sequence) { - using TExpander = int[]; - (void)TExpander{0, (Apply(os), 0)...}; - } -}; - template static constexpr bool ArgSupported = (std::is_same_v>, Any> || @@ -78,10 +61,16 @@ struct FuncFunctorImpl { #endif TVM_FFI_INLINE static std::string Sig() { - using IdxSeq = std::make_index_sequence; std::ostringstream ss; ss << "("; - Arg2Str>::Run(ss, IdxSeq{}); + for_each( + [&ss](auto i, const auto& v) { + if constexpr (i() != 0) { + ss << ", "; + } + ss << i() << ": " << v; + }, + Type2Str::v()...); ss << ") -> " << Type2Str::v(); return ss.str(); }