14template <
typename funcT,
typename returnT,
bool funcT_receives_input_tuple,
16 typename keyT,
typename output_terminalsT,
typename... input_valuesT>
19 keyT, output_terminalsT,
20 CallableWrapTT<funcT, returnT, funcT_receives_input_tuple, funcT_receives_outterm_tuple, space, keyT, output_terminalsT, input_valuesT...>,
21 ttg::typelist<input_valuesT...>, space> {
22 using baseT =
typename CallableWrapTT::ttT;
24 using input_values_tuple_type =
typename baseT::input_values_tuple_type;
25 using input_refs_tuple_type =
typename baseT::input_refs_tuple_type;
26 using input_edges_type =
typename baseT::input_edges_type;
27 using output_edges_type =
typename baseT::output_edges_type;
29 using noref_funcT = std::remove_reference_t<funcT>;
30 std::conditional_t<std::is_function_v<noref_funcT>, std::add_pointer_t<noref_funcT>, noref_funcT> func;
32 using op_return_type =
33#ifdef TTG_HAVE_COROUTINE
34 std::conditional_t<std::is_same_v<returnT, ttg::resumable_task>,
37 std::conditional_t<std::is_same_v<returnT, ttg::device::Task>,
38 ttg::device::Task::base_type,
50 template<
typename ReturnT>
52 static_assert(std::is_same_v<std::remove_reference_t<
decltype(ret)>, returnT>,
53 "CallableWrapTT<funcT,returnT,...>: returnT does not match the actual return type of funcT");
54 if constexpr (!std::is_void_v<returnT>) {
55#ifdef TTG_HAVE_COROUTINE
56 if constexpr (std::is_same_v<returnT, ttg::resumable_task>) {
59 if (ret.completed()) {
67 if constexpr (std::is_same_v<returnT, ttg::device::Task>) {
68 ttg::device::Task::base_type coro_handle = ret;
74 if constexpr (!(std::is_same_v<returnT, ttg::resumable_task>
76 || std::is_same_v<returnT, ttg::device::Task>
81 static_assert(std::tuple_size_v<std::remove_reference_t<
decltype(out)>> == 1,
82 "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
83 "value only if there is only 1 out terminal");
84 static_assert(std::tuple_size_v<returnT> <= 2,
85 "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
86 "value only if it is a plain value (then sent with null key), a tuple-like containing a single "
87 "key (hence value is void), or a tuple-like containing a key and a value");
88 if constexpr (std::tuple_size_v<returnT> == 0)
89 std::get<0>(out).sendv(std::move(ret));
90 else if constexpr (std::tuple_size_v<returnT> == 1)
91 std::get<0>(out).sendk(std::move(std::get<0>(ret)));
92 else if constexpr (std::tuple_size_v<returnT> == 2)
93 std::get<0>(out).send(std::move(std::get<0>(ret)), std::move(std::get<1>(ret)));
100 template <
typename Key,
typename Tuple, std::size_t... S>
101 auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
103 auto invoke_func_handle_ret = [&](
auto&&... args){
104 if constexpr (std::is_void_v<returnT>) {
105 func(std::forward<Key>(key), std::forward<
decltype(args)>(args)...);
107 return process_return(func(std::forward<Key>(key), std::forward<
decltype(args)>(args)...), out);
110 auto unpack_input_tuple_if_needed = [&](
auto&&... args){
111 if constexpr (funcT_receives_input_tuple) {
112 return invoke_func_handle_ret(std::forward<Tuple>(args_tuple), std::forward<
decltype(args)>(args)...);
114 return invoke_func_handle_ret(baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))...,
115 std::forward<
decltype(args)>(args)...);
119 if constexpr (funcT_receives_outterm_tuple) {
120 return unpack_input_tuple_if_needed(out);
122 auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
123 this->set_outputs_tls_ptr();
126 [
this, old_output_tls_ptr](){
127 this->set_outputs_tls_ptr(old_output_tls_ptr);
129 return unpack_input_tuple_if_needed();
133 template <
typename Tuple, std::size_t... S>
134 auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
137 auto invoke_func_handle_ret = [&](
auto&&... args){
138 if constexpr (std::is_void_v<returnT>) {
139 func(std::forward<
decltype(args)>(args)...);
141 return process_return(func(std::forward<
decltype(args)>(args)...), out);
144 auto unpack_input_tuple_if_needed = [&](
auto&& fn,
auto&&... args){
145 if constexpr (funcT_receives_input_tuple) {
146 return fn(std::forward<Tuple>(args_tuple), std::forward<
decltype(args)>(args)...);
148 return fn(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))...,
149 std::forward<
decltype(args)>(args)...);
153 if constexpr (funcT_receives_outterm_tuple) {
154 return unpack_input_tuple_if_needed(invoke_func_handle_ret, out);
156 auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
157 this->set_outputs_tls_ptr();
160 [
this, old_output_tls_ptr](){
161 this->set_outputs_tls_ptr(old_output_tls_ptr);
163 return unpack_input_tuple_if_needed(invoke_func_handle_ret);
167 template <
typename Key>
169 auto invoke_func_handle_ret = [&](
auto&&... args){
170 if constexpr (std::is_void_v<returnT>) {
171 func(std::forward<Key>(key), std::forward<
decltype(args)>(args)...);
173 return process_return(func(std::forward<Key>(key), std::forward<
decltype(args)>(args)...), out);
177 auto invoke_func_empty_tuple = [&](
auto&&... args){
178 if constexpr(funcT_receives_input_tuple) {
179 invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
181 invoke_func_handle_ret(std::forward<
decltype(args)>(args)...);
185 if constexpr (funcT_receives_outterm_tuple) {
186 invoke_func_handle_ret(out);
188 auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
189 this->set_outputs_tls_ptr();
192 [
this, old_output_tls_ptr](){
193 this->set_outputs_tls_ptr(old_output_tls_ptr);
195 return invoke_func_handle_ret();
199 template <
typename OutputTerminals>
202 auto invoke_func_handle_ret = [&](
auto&&... args){
203 if constexpr (std::is_void_v<returnT>) {
204 func(std::forward<
decltype(args)>(args)...);
206 return process_return(func(std::forward<
decltype(args)>(args)...), out);
210 auto invoke_func_empty_tuple = [&](
auto&&... args){
211 if constexpr(funcT_receives_input_tuple) {
212 return invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
214 return invoke_func_handle_ret(std::forward<
decltype(args)>(args)...);
218 if constexpr (funcT_receives_outterm_tuple) {
219 return invoke_func_empty_tuple(out);
221 auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
222 this->set_outputs_tls_ptr();
225 [
this, old_output_tls_ptr](){
226 this->set_outputs_tls_ptr(old_output_tls_ptr);
228 return invoke_func_empty_tuple();
232 template <
typename Tuple, std::size_t... I>
239 template <
typename funcT_>
240 CallableWrapTT(funcT_ &&f,
const input_edges_type &inedges,
const typename baseT::output_edges_type &outedges,
241 const std::string &name,
const std::vector<std::string> &innames,
242 const std::vector<std::string> &outnames)
243 : baseT(inedges, outedges, name, innames, outnames), func(
std::forward<funcT_>(f)) {}
245 template <
typename funcT_>
246 CallableWrapTT(funcT_ &&f,
const std::string &name,
const std::vector<std::string> &innames,
247 const std::vector<std::string> &outnames)
248 : baseT(name, innames, outnames), func(
std::forward<funcT_>(f)) {}
250 template <
typename Key,
typename ArgsTuple>
251 std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
254 op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) {
255 assert(&out == &baseT::get_output_terminals());
256 return call_func(std::forward<Key>(key), std::forward<ArgsTuple>(args_tuple), out,
257 std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
260 template <
typename ArgsTuple,
typename Key = keyT>
261 std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
264 op(ArgsTuple &&args_tuple, output_terminalsT &out) {
265 assert(&out == &baseT::get_output_terminals());
266 return call_func(std::forward<ArgsTuple>(args_tuple), out,
267 std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
270 template <
typename Key,
typename ArgsTuple = input_refs_tuple_type>
272 Key &&key, output_terminalsT &out) {
273 assert(&out == &baseT::get_output_terminals());
274 return call_func(std::forward<Key>(key), out);
277 template <
typename Key = keyT,
typename ArgsTuple = input_refs_tuple_type>
279 output_terminalsT &out) {
280 assert(&out == &baseT::get_output_terminals());
285template <
typename funcT,
typename returnT,
bool funcT_receives_input_tuple,
287 typename keyT,
typename output_terminalsT,
typename input_values_typelistT>
290template <
typename funcT,
typename returnT,
bool funcT_receives_input_tuple,
292 typename keyT,
typename output_terminalsT,
typename... input_valuesT>
294 funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
295 std::tuple<input_valuesT...>> {
297 funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
298 std::remove_reference_t<input_valuesT>...>;
301template <
typename funcT,
typename returnT,
bool funcT_receives_input_tuple,
303 typename keyT,
typename output_terminalsT,
typename... input_valuesT>
305 funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
306 ttg::meta::typelist<input_valuesT...>> {
308 funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
309 std::remove_reference_t<input_valuesT>...>;
340 typename keyT = void,
342 typename... input_edge_valuesT,
343 typename... output_edgesT>
345 const std::tuple<output_edgesT...> &outedges = std::tuple<>{},
const std::string &name =
"wrapper",
346 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_edge_valuesT),
348 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
363 std::tuple<std::add_lvalue_reference_t<typename ttg::Edge<keyT, input_edge_valuesT>::value_type>...>>,
371 using return_type_typelist_and_gross_func_args_t =
373 using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
374 using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
375 constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
376 func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> :
true;
377 static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
378 "ttd::make_tt_tpl(func, inedges, ...): could not detect how to invoke generic callable func, either "
379 "the signature of func "
380 "is faulty, or inedges does match the expected list of types, or both");
384 constexpr auto num_args = std::tuple_size_v<func_args_t>;
387 constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
389 constexpr bool TASK_ID_PASSED_AS_NONREF =
392 TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
393 "ttg::make_tt_tpl(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
396 constexpr bool have_outterm_tuple =
400 constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
403 OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
404 "ttd::make_tt_tpl(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
406 static_assert(num_args == 3 - (void_key ? 1 : 0) - (have_outterm_tuple ? 0 : 1),
407 "ttg::make_tt_tpl(func, ...): func takes wrong number of arguments (2, or 1, if keyT=void + optional "
408 "tuple of output terminals)");
411 using nondecayed_input_args_t = std::tuple_element_t<void_key ? 0 : 1, func_args_t>;
412 constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
415 NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
416 "ttg::make_tt_tpl(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
417 "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
418 using input_args_t = std::decay_t<nondecayed_input_args_t>;
421 output_terminals_type, input_args_t>::type;
422 static_assert(std::is_same_v<decayed_input_args_t, std::tuple<input_edge_valuesT...>>,
423 "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func");
425 return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
428template <
typename keyT = void,
430 typename... input_edge_valuesT,
431 typename... output_edgesT>
433 const std::tuple<output_edgesT...> &outedges = std::tuple<>{},
const std::string &name =
"wrapper",
434 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_edge_valuesT),
436 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
439 return make_tt_tpl<ttg::ExecutionSpace::Host, keyT>(
440 std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
490 typename keyT = void,
typename funcT,
491 typename... input_edge_valuesT,
typename... output_edgesT>
493 const std::tuple<output_edgesT...> &outedges = std::tuple<>{},
const std::string &name =
"wrapper",
494 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_edge_valuesT),
"input"),
495 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
"output")) {
517 using return_type_typelist_and_gross_func_args_t =
519 using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
520 using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
521 constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
522 func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> :
true;
523 static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
524 "ttd::make_tt(func, inedges, ...): could not detect how to invoke generic callable func, either the "
526 "is faulty, or inedges does match the expected list of types, or both");
530 constexpr auto num_args = std::tuple_size_v<func_args_t>;
533 constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
535 constexpr bool TASK_ID_PASSED_AS_NONREF =
538 TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
539 "ttg::make_tt(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
542 constexpr bool have_outterm_tuple =
545 constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
548 OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
549 "ttg::make_tt(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
556 std::tuple_size_v<func_args_t> - (void_key ? 0 : 1) - (have_outterm_tuple ? 1 : 0)>::type;
557 constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
560 NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
561 "ttg::make_tt(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
562 "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
567 output_terminals_type, full_input_args_t>::type;
569 return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
572template <
typename keyT = void,
typename funcT,
573 typename... input_edge_valuesT,
typename... output_edgesT>
575 const std::tuple<output_edgesT...> &outedges = std::tuple<>{},
const std::string &name =
"wrapper",
576 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_edge_valuesT),
"input"),
577 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
"output")) {
578 return make_tt<ttg::ExecutionSpace::Host, keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
581template <
typename keyT,
typename funcT,
typename... input_valuesT,
typename... output_edgesT>
582[[deprecated(
"use make_tt_tpl instead")]]
inline auto wrapt(
584 const std::tuple<output_edgesT...> &outedges,
const std::string &name =
"wrapper",
585 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_valuesT),
"input"),
586 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
"output")) {
587 return make_tt_tpl<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
590template <
typename keyT,
typename funcT,
typename... input_edge_valuesT,
typename... output_edgesT>
591[[deprecated(
"use make_tt instead")]]
auto wrap(
593 const std::tuple<output_edgesT...> &outedges,
const std::string &name =
"wrapper",
594 const std::vector<std::string> &innames = std::vector<std::string>(
sizeof...(input_edge_valuesT),
"input"),
595 const std::vector<std::string> &outnames = std::vector<std::string>(
sizeof...(output_edgesT),
"output")) {
596 return make_tt<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
auto call_func(Key &&key, output_terminalsT &out)
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< input_refs_tuple_type > &&!ttg::meta::is_void_v< Key >, op_return_type > op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out)
auto call_func(OutputTerminals &out)
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&ttg::meta::is_void_v< Key >, op_return_type > op(output_terminalsT &out)
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&!ttg::meta::is_void_v< Key >, op_return_type > op(Key &&key, output_terminalsT &out)
static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence< I... >)
auto process_return(ReturnT &&ret, output_terminalsT &out)
CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< input_refs_tuple_type > &&ttg::meta::is_void_v< Key >, op_return_type > op(ArgsTuple &&args_tuple, output_terminalsT &out)
Edge is used to connect In and Out terminals.
auto wrap(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges, const std::tuple< output_edgesT... > &outedges, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
auto make_tt_tpl(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges=std::tuple<>{}, const std::tuple< output_edgesT... > &outedges=std::tuple<>{}, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Factory function to assist in wrapping a callable with signature.
auto make_tt(funcT &&func, const std::tuple< ttg::Edge< keyT, input_edge_valuesT >... > &inedges=std::tuple<>{}, const std::tuple< output_edgesT... > &outedges=std::tuple<>{}, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_edge_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
Factory function to assist in wrapping a callable with signature.
auto wrapt(funcT &&func, const std::tuple< ttg::Edge< keyT, input_valuesT >... > &inedges, const std::tuple< output_edgesT... > &outedges, const std::string &name="wrapper", const std::vector< std::string > &innames=std::vector< std::string >(sizeof...(input_valuesT), "input"), const std::vector< std::string > &outnames=std::vector< std::string >(sizeof...(output_edgesT), "output"))
top-level TTG namespace contains runtime-neutral functionality
ExecutionSpace
denotes task execution space
void abort()
Aborts the TTG program using the default backend's ttg_abort method.
TTG_CXX_COROUTINE_NAMESPACE::coroutine_handle< Promise > coroutine_handle