make_tt.h
Go to the documentation of this file.
1 // to be #include'd within runtime::ttg namespace
2 
3 #ifndef TTG_MAKE_TT_H
4 #define TTG_MAKE_TT_H
5 
6 // Class to wrap a callable with signature
7 //
8 // case 1 (keyT != void): void op(auto&& key, std::tuple<input_valuesT...>&&, std::tuple<output_terminalsT...>&)
9 // case 2 (keyT == void): void op(std::tuple<input_valuesT...>&&, std::tuple<output_terminalsT...>&)
10 //
11 template <typename funcT, bool funcT_receives_outterm_tuple,
12  typename keyT, typename output_terminalsT,
13  typename... input_valuesT>
15  : public TT<keyT, output_terminalsT,
16  CallableWrapTT<funcT, funcT_receives_outterm_tuple, keyT, output_terminalsT, input_valuesT...>,
17  ttg::typelist<input_valuesT...>> {
18  using baseT = typename CallableWrapTT::ttT;
19 
20  using input_values_tuple_type = typename baseT::input_values_tuple_type;
21  using input_refs_tuple_type = typename baseT::input_refs_tuple_type;
22  using input_edges_type = typename baseT::input_edges_type;
23  using output_edges_type = typename baseT::output_edges_type;
24 
25  using noref_funcT = std::remove_reference_t<funcT>;
26  std::conditional_t<std::is_function_v<noref_funcT>, std::add_pointer_t<noref_funcT>, noref_funcT> func;
27 
28  template <typename Key, typename Tuple>
29  void call_func(Key &&key, Tuple &&args, output_terminalsT &out) {
30  if constexpr (funcT_receives_outterm_tuple)
31  func(std::forward<Key>(key), std::forward<Tuple>(args), out);
32  else {
33  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
34  this->set_outputs_tls_ptr();
35  func(std::forward<Key>(key), std::forward<Tuple>(args));
36  this->set_outputs_tls_ptr(old_output_tls_ptr);
37  }
38  }
39 
40  template <typename TupleOrKey>
41  void call_func(TupleOrKey &&args, output_terminalsT &out) {
42  if constexpr (funcT_receives_outterm_tuple)
43  func(std::forward<TupleOrKey>(args), out);
44  else {
45  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
46  this->set_outputs_tls_ptr();
47  func(std::forward<TupleOrKey>(args));
48  this->set_outputs_tls_ptr(old_output_tls_ptr);
49  }
50  }
51 
52  void call_func(output_terminalsT &out) {
53  if constexpr (funcT_receives_outterm_tuple)
54  func(std::tuple<>(), out);
55  else {
56  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
57  this->set_outputs_tls_ptr();
58  func(std::tuple<>());
59  this->set_outputs_tls_ptr(old_output_tls_ptr);
60  }
61  }
62 
63  public:
64  template <typename funcT_>
65  CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const output_edges_type &outedges,
66  const std::string &name, const std::vector<std::string> &innames,
67  const std::vector<std::string> &outnames)
68  : baseT(inedges, outedges, name, innames, outnames), func(std::forward<funcT_>(f)) {}
69 
70  template <typename funcT_>
71  CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector<std::string> &innames,
72  const std::vector<std::string> &outnames)
73  : baseT(name, innames, outnames), func(std::forward<funcT_>(f)) {}
74 
75  template <typename Key, typename ArgsTuple>
76  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> && !ttg::meta::is_empty_tuple_v<ArgsTuple> &&
77  !ttg::meta::is_void_v<Key>,
78  void>
79  op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) {
80  call_func(std::forward<Key>(key), std::forward<ArgsTuple>(args_tuple), out);
81  }
82 
83  template <typename ArgsTuple, typename Key = keyT>
84  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> && !ttg::meta::is_empty_tuple_v<ArgsTuple> &&
85  ttg::meta::is_void_v<Key>,
86  void>
87  op(ArgsTuple &&args_tuple, output_terminalsT &out) {
88  call_func(std::forward<ArgsTuple>(args_tuple), out);
89  }
90 
91  template <typename Key, typename ArgsTuple = input_values_tuple_type>
92  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && !ttg::meta::is_void_v<Key>, void> op(
93  Key &&key, output_terminalsT &out) {
94  call_func(std::forward<Key>(key), out);
95  }
96 
97  template <typename Key = keyT, typename ArgsTuple = input_values_tuple_type>
98  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && ttg::meta::is_void_v<Key>, void> op(
99  output_terminalsT &out) {
100  call_func(out);
101  }
102 };
103 
104 template <typename funcT, bool funcT_receives_outterm_tuple,
105  typename keyT, typename output_terminalsT,
106  typename input_values_tupleT>
108 
109 template <typename funcT, bool funcT_receives_outterm_tuple,
110  typename keyT, typename output_terminalsT,
111  typename... input_valuesT>
112 struct CallableWrapTTUnwrapTypelist<funcT, funcT_receives_outterm_tuple,
113  keyT, output_terminalsT,
114  std::tuple<input_valuesT...>> {
115  using type = CallableWrapTT<funcT, funcT_receives_outterm_tuple,
116  keyT, output_terminalsT,
117  std::remove_reference_t<input_valuesT>...>;
118 };
119 
120 template <typename funcT, bool funcT_receives_outterm_tuple, typename keyT, typename output_terminalsT,
121  typename... input_valuesT>
122 struct CallableWrapTTUnwrapTypelist<funcT, funcT_receives_outterm_tuple, keyT, output_terminalsT,
123  ttg::meta::typelist<input_valuesT...>> {
124  using type = CallableWrapTT<funcT, funcT_receives_outterm_tuple, keyT, output_terminalsT,
125  std::remove_reference_t<input_valuesT>...>;
126 };
127 
128 // Class to wrap a callable with signature
129 //
130 // case 1 (keyT != void): returnT op(auto&& key, input_valuesT&&..., std::tuple<output_terminalsT...>&)
131 // case 2 (keyT == void): returnT op(input_valuesT&&..., std::tuple<output_terminalsT...>&)
132 //
133 // returnT is void for funcT = synchronous (ordinary) function and the appropriate return type for funcT=coroutine
134 template <typename funcT, typename returnT, bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
135  typename keyT, typename output_terminalsT, typename... input_valuesT>
137  : public TT<
138  keyT, output_terminalsT,
139  CallableWrapTTArgs<funcT, returnT, funcT_receives_outterm_tuple, space, keyT, output_terminalsT, input_valuesT...>,
140  ttg::typelist<input_valuesT...>> {
141  using baseT = typename CallableWrapTTArgs::ttT;
142 
143  using input_values_tuple_type = typename baseT::input_values_tuple_type;
144  using input_refs_tuple_type = typename baseT::input_refs_tuple_type;
145  using input_edges_type = typename baseT::input_edges_type;
146  using output_edges_type = typename baseT::output_edges_type;
147 
148  using noref_funcT = std::remove_reference_t<funcT>;
149  std::conditional_t<std::is_function_v<noref_funcT>, std::add_pointer_t<noref_funcT>, noref_funcT> func;
150 
151  using op_return_type =
152 #ifdef TTG_HAVE_COROUTINE
153  std::conditional_t<std::is_same_v<returnT, ttg::resumable_task>,
155 #ifdef TTG_HAVE_DEVICE
156  std::conditional_t<std::is_same_v<returnT, ttg::device::Task>,
157  ttg::device::Task::base_type,
158  void>
159 #else // TTG_HAVE_DEVICE
160  void
161 #endif // TTG_HAVE_DEVICE
162  >;
163 #else // TTG_HAVE_COROUTINE
164  void;
165 #endif // TTG_HAVE_COROUTINE
166 
167 public:
168  static constexpr bool have_cuda_op = (space == ttg::ExecutionSpace::CUDA);
169  static constexpr bool have_hip_op = (space == ttg::ExecutionSpace::HIP);
170  static constexpr bool have_level_zero_op = (space == ttg::ExecutionSpace::L0);
171 
172 protected:
173 
174  template<typename ReturnT>
175  auto process_return(ReturnT&& ret, output_terminalsT &out) {
176  static_assert(std::is_same_v<std::remove_reference_t<decltype(ret)>, returnT>,
177  "CallableWrapTTArgs<funcT,returnT,...>: returnT does not match the actual return type of funcT");
178  if constexpr (!std::is_void_v<returnT>) { // protect from compiling for void returnT
179 #ifdef TTG_HAVE_COROUTINE
180  if constexpr (std::is_same_v<returnT, ttg::resumable_task>) {
182  // if task completed destroy it
183  if (ret.completed()) {
184  ret.destroy();
185  } else { // if task is suspended return the coroutine promise ptr
186  coro_handle = ret;
187  }
188  return coro_handle;
189  } else
190 #ifdef TTG_HAVE_DEVICE
191  if constexpr (std::is_same_v<returnT, ttg::device::Task>) {
192  ttg::device::Task::base_type coro_handle = ret;
193  return coro_handle;
194  }
195 #else // TTG_HAVE_DEVICE
196  ttg::abort(); // should not happen
197 #endif // TTG_HAVE_DEVICE
198  if constexpr (!(std::is_same_v<returnT, ttg::resumable_task>
199 #ifdef TTG_HAVE_DEVICE
200  || std::is_same_v<returnT, ttg::device::Task>
201 #endif // TTG_HAVE_DEVICE
202  ))
203 #endif
204  {
205  static_assert(std::tuple_size_v<std::remove_reference_t<decltype(out)>> == 1,
206  "CallableWrapTTArgs<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
207  "value only if there is only 1 out terminal");
208  static_assert(std::tuple_size_v<returnT> <= 2,
209  "CallableWrapTTArgs<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
210  "value only if it is a plain value (then sent with null key), a tuple-like containing a single "
211  "key (hence value is void), or a tuple-like containing a key and a value");
212  if constexpr (std::tuple_size_v<returnT> == 0)
213  std::get<0>(out).sendv(std::move(ret));
214  else if constexpr (std::tuple_size_v<returnT> == 1)
215  std::get<0>(out).sendk(std::move(std::get<0>(ret)));
216  else if constexpr (std::tuple_size_v<returnT> == 2)
217  std::get<0>(out).send(std::move(std::get<0>(ret)), std::move(std::get<1>(ret)));
218  return;
219  }
220  }
221  }
222 
224  template <typename Key, typename Tuple, std::size_t... S>
225  auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
226  using func_args_t = ttg::meta::tuple_concat_t<std::tuple<const Key &>, input_refs_tuple_type, output_edges_type>;
227 
228  if constexpr (funcT_receives_outterm_tuple) {
229  if constexpr (std::is_void_v<returnT>) {
230  func(std::forward<Key>(key),
231  baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))..., out);
232  return;
233  } else {
234  auto ret = func(
235  std::forward<Key>(key),
236  baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))..., out);
237 
238  return process_return(std::move(ret), out);
239  }
240  } else {
241  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
242  this->set_outputs_tls_ptr();
243  if constexpr (std::is_void_v<returnT>) {
244  func(std::forward<Key>(key),
245  baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))...);
246  this->set_outputs_tls_ptr(old_output_tls_ptr);
247  return;
248  } else {
249  auto ret =
250  func(std::forward<Key>(key),
251  baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))...);
252  this->set_outputs_tls_ptr(old_output_tls_ptr);
253  return process_return(std::move(ret), out);
254  }
255  }
256  }
257 
258  template <typename Tuple, std::size_t... S>
259  auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
261  if constexpr (funcT_receives_outterm_tuple) {
262  if constexpr (std::is_void_v<returnT>) {
263  func(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))..., out);
264  } else {
265  auto ret = func(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))..., out);
266  return process_return(std::move(ret), out);
267  }
268  } else {
269  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
270  this->set_outputs_tls_ptr();
271  if constexpr (std::is_void_v<returnT>) {
272  func(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))...);
273  this->set_outputs_tls_ptr(old_output_tls_ptr);
274  } else {
275  auto ret = func(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))...);
276  this->set_outputs_tls_ptr(old_output_tls_ptr);
277  return process_return(std::move(ret), out);
278  }
279  }
280  }
281 
282  template <typename Key>
283  auto call_func(Key &&key, output_terminalsT &out) {
284  if constexpr (funcT_receives_outterm_tuple) {
285  if constexpr (std::is_void_v<returnT>) {
286  func(std::forward<Key>(key), out);
287  } else {
288  auto ret = func(std::forward<Key>(key), out);
289  return process_return(std::move(ret), out);
290  }
291  } else {
292  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
293  this->set_outputs_tls_ptr();
294  if constexpr (std::is_void_v<returnT>) {
295  func(std::forward<Key>(key));
296  this->set_outputs_tls_ptr(old_output_tls_ptr);
297  } else {
298  auto ret = func(std::forward<Key>(key));
299  this->set_outputs_tls_ptr(old_output_tls_ptr);
300  return process_return(std::move(ret), out);
301  }
302  }
303  }
304 
305  template <typename OutputTerminals>
306  auto call_func(OutputTerminals &out) {
307  if constexpr (funcT_receives_outterm_tuple) {
308  if constexpr (std::is_void_v<returnT>) {
309  func(out);
310  } else {
311  auto ret = func(out);
312  return process_return(std::move(ret), out);
313  }
314  } else {
315  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
316  this->set_outputs_tls_ptr();
317  if constexpr (std::is_void_v<returnT>) {
318  func();
319  this->set_outputs_tls_ptr(old_output_tls_ptr);
320  } else {
321  auto ret = func(out);
322  this->set_outputs_tls_ptr(old_output_tls_ptr);
323  return process_return(std::move(ret), out);
324  }
325  }
326  }
327 
328  template <typename Tuple, std::size_t... I>
329  static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence<I...>) {
330  return std::array<ttg::TerminalBase *, sizeof...(I)>{
331  {static_cast<ttg::TerminalBase *>(&std::get<I>(output_terminals))...}};
332  }
333 
334  public:
335  template <typename funcT_>
336  CallableWrapTTArgs(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges,
337  const std::string &name, const std::vector<std::string> &innames,
338  const std::vector<std::string> &outnames)
339  : baseT(inedges, outedges, name, innames, outnames), func(std::forward<funcT_>(f)) {}
340 
341  template <typename funcT_>
342  CallableWrapTTArgs(funcT_ &&f, const std::string &name, const std::vector<std::string> &innames,
343  const std::vector<std::string> &outnames)
344  : baseT(name, innames, outnames), func(std::forward<funcT_>(f)) {}
345 
346  template <typename Key, typename ArgsTuple>
347  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
348  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && !ttg::meta::is_void_v<Key>,
349  op_return_type>
350  op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) {
351  assert(&out == &baseT::get_output_terminals());
352  return call_func(std::forward<Key>(key), std::forward<ArgsTuple>(args_tuple), out,
353  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
354  };
355 
356  template <typename ArgsTuple, typename Key = keyT>
357  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
358  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && ttg::meta::is_void_v<Key>,
359  op_return_type>
360  op(ArgsTuple &&args_tuple, output_terminalsT &out) {
361  assert(&out == &baseT::get_output_terminals());
362  return call_func(std::forward<ArgsTuple>(args_tuple), out,
363  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
364  };
365 
366  template <typename Key, typename ArgsTuple = input_refs_tuple_type>
367  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && !ttg::meta::is_void_v<Key>, op_return_type> op(
368  Key &&key, output_terminalsT &out) {
369  assert(&out == &baseT::get_output_terminals());
370  return call_func(std::forward<Key>(key), out);
371  };
372 
373  template <typename Key = keyT, typename ArgsTuple = input_refs_tuple_type>
374  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && ttg::meta::is_void_v<Key>, op_return_type> op(
375  output_terminalsT &out) {
376  assert(&out == &baseT::get_output_terminals());
377  return call_func(out);
378  };
379 };
380 
381 template <typename funcT, typename returnT, bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
382  typename keyT, typename output_terminalsT, typename input_values_typelistT>
384 
385 template <typename funcT, typename returnT, bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
386  typename keyT, typename output_terminalsT, typename... input_valuesT>
387 struct CallableWrapTTArgsAsTypelist<funcT, returnT, funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
388  std::tuple<input_valuesT...>> {
389  using type = CallableWrapTTArgs<funcT, returnT, funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
390  std::remove_reference_t<input_valuesT>...>;
391 };
392 
393 template <typename funcT, typename returnT, bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
394  typename keyT, typename output_terminalsT, typename... input_valuesT>
395 struct CallableWrapTTArgsAsTypelist<funcT, returnT, funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
396  ttg::meta::typelist<input_valuesT...>> {
397  using type = CallableWrapTTArgs<funcT, returnT, funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
398  std::remove_reference_t<input_valuesT>...>;
399 };
400 
401 // clang-format off
427 // clang-format on
428 template <typename keyT = void, typename funcT, typename... input_edge_valuesT, typename... output_edgesT>
429 auto make_tt_tpl(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
430  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
431  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT),
432  "input"),
433  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT),
434  "output")) {
435  // ensure input types do not contain Void
436  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
437  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
438 
439  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
440 
441  // list of base datum types (T or const T)
443 
444  // gross list of candidate argument types
445  using gross_candidate_func_args_t = ttg::meta::typelist<
448  std::tuple<std::add_lvalue_reference_t<typename ttg::Edge<keyT, input_edge_valuesT>::value_type>...>>,
450 
451  // net list of candidate argument types excludes the empty typelists for void arguments
452  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
453 
454  // compute list of argument types with which func can be invoked
455  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
456  using gross_func_args_t = decltype(ttg::meta::compute_arg_binding_types_r<void>(func, candidate_func_args_t{}));
457  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
458  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
459  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
460  "ttd::make_tt_tpl(func, inedges, ...): could not detect how to invoke generic callable func, either "
461  "the signature of func "
462  "is faulty, or inedges does match the expected list of types, or both");
463 
464  // net argument typelist
465  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
466  constexpr auto num_args = std::tuple_size_v<func_args_t>;
467 
468  // if given task id, make sure it's passed via const lvalue ref
469  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
470  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
471  constexpr bool TASK_ID_PASSED_AS_NONREF =
472  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
473  static_assert(
474  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
475  "ttg::make_tt_tpl(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
476 
477  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
478  constexpr bool have_outterm_tuple =
479  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
481  gross_func_args_t>;
482  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
483  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, true, func_args_t> : true;
484  static_assert(
485  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
486  "ttd::make_tt_tpl(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
487 
488  static_assert(num_args == 3 - (void_key ? 1 : 0) - (have_outterm_tuple ? 0 : 1),
489  "ttg::make_tt_tpl(func, ...): func takes wrong number of arguments (2, or 1, if keyT=void + optional "
490  "tuple of output terminals)");
491 
492  // 2. input_args_t = {input_valuesT&&...}
493  using nondecayed_input_args_t = std::tuple_element_t<void_key ? 0 : 1, func_args_t>;
494  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
495  !ttg::meta::is_any_nonconst_lvalue_reference_v<nondecayed_input_args_t>;
496  static_assert(
497  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
498  "ttg::make_tt_tpl(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
499  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
500  using input_args_t = std::decay_t<nondecayed_input_args_t>;
501  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
502  using wrapT =
504  static_assert(std::is_same_v<decayed_input_args_t, std::tuple<input_edge_valuesT...>>,
505  "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func");
506 
507  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
508 }
509 
510 // clang-format off
556 // clang-format on
557 template <ttg::ExecutionSpace space,
558  typename keyT = void, typename funcT,
559  typename... input_edge_valuesT, typename... output_edgesT>
560 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
561  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
562  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
563  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
564  // ensure input types do not contain Void
565  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
566 
567  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
568 
569  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
570 
571  // list of base datum types (T or const T)
573 
574  // gross list of candidate argument types
575  using gross_candidate_func_args_t = ttg::meta::typelist<
579 
580  // net list of candidate argument types excludes the empty typelists for void arguments
581  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
582 
583  // gross argument typelist for invoking func, can include void for optional args
584  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
585  using return_type_typelist_and_gross_func_args_t =
586  decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{}));
587  using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
588  using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
589  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
590  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
591  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
592  "ttd::make_tt(func, inedges, ...): could not detect how to invoke generic callable func, either the "
593  "signature of func "
594  "is faulty, or inedges does match the expected list of types, or both");
595 
596  // net argument typelist
597  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
598  constexpr auto num_args = std::tuple_size_v<func_args_t>;
599 
600  // if given task id, make sure it's passed via const lvalue ref
601  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
602  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
603  constexpr bool TASK_ID_PASSED_AS_NONREF =
604  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
605  static_assert(
606  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
607  "ttg::make_tt(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
608 
609  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
610  constexpr bool have_outterm_tuple =
611  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
612  : ttg::meta::probe_last_v<ttg::meta::decays_to_output_terminal_tuple, false, gross_func_args_t>;
613  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
614  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, false, func_args_t> : true;
615  static_assert(
616  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
617  "ttg::make_tt(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
618 
619  // TT needs actual types of arguments to func ... extract them and pass to CallableWrapTTArgs
620  using input_edge_value_types = ttg::meta::typelist<std::decay_t<input_edge_valuesT>...>;
621  // input_args_t = {input_valuesT&&...}
622  using input_args_t = typename ttg::meta::take_first_n<
623  typename ttg::meta::drop_first_n<func_args_t, std::size_t(void_key ? 0 : 1)>::type,
624  std::tuple_size_v<func_args_t> - (void_key ? 0 : 1) - (have_outterm_tuple ? 1 : 0)>::type;
625  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
626  !ttg::meta::is_any_nonconst_lvalue_reference_v<input_args_t>;
627  static_assert(
628  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
629  "ttg::make_tt(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
630  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
631  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
632  // 3. full_input_args_t = edge-types with non-void types replaced by input_args_t
633  using full_input_args_t = ttg::meta::replace_nonvoid_t<input_edge_value_types, input_args_t>;
634  using wrapT = typename CallableWrapTTArgsAsTypelist<funcT, func_return_t, have_outterm_tuple, space, keyT,
635  output_terminals_type, full_input_args_t>::type;
636 
637  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
638 }
639 
640 template <typename keyT = void, typename funcT,
641  typename... input_edge_valuesT, typename... output_edgesT>
642 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
643  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
644  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
645  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
646  return make_tt<ttg::ExecutionSpace::Host, keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
647 }
648 
649 template <typename keyT, typename funcT, typename... input_valuesT, typename... output_edgesT>
650 [[deprecated("use make_tt_tpl instead")]] inline auto wrapt(
651  funcT &&func, const std::tuple<ttg::Edge<keyT, input_valuesT>...> &inedges,
652  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
653  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_valuesT), "input"),
654  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
655  return make_tt_tpl<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
656 }
657 
658 template <typename keyT, typename funcT, typename... input_edge_valuesT, typename... output_edgesT>
659 [[deprecated("use make_tt instead")]] auto wrap(
660  funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges,
661  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
662  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
663  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
664  return make_tt<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
665 }
666 
667 #endif // TTG_MAKE_TT_H
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&ttg::meta::is_void_v< Key >, op_return_type > op(output_terminalsT &out)
Definition: make_tt.h:374
static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence< I... >)
Definition: make_tt.h:329
CallableWrapTTArgs(funcT_ &&f, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:342
static constexpr bool have_level_zero_op
Definition: make_tt.h:170
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)
Definition: make_tt.h:350
auto call_func(OutputTerminals &out)
Definition: make_tt.h:306
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)
Definition: make_tt.h:367
auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:259
static constexpr bool have_hip_op
Definition: make_tt.h:169
static constexpr bool have_cuda_op
Definition: make_tt.h:168
auto process_return(ReturnT &&ret, output_terminalsT &out)
Definition: make_tt.h:175
CallableWrapTTArgs(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)
Definition: make_tt.h:336
auto call_func(Key &&key, output_terminalsT &out)
Definition: make_tt.h:283
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)
Definition: make_tt.h:360
auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:225
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< ArgsTuple > &&!ttg::meta::is_void_v< Key >, void > op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out)
Definition: make_tt.h:79
CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const output_edges_type &outedges, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:65
std::enable_if_t< std::is_same_v< ArgsTuple, input_refs_tuple_type > &&!ttg::meta::is_empty_tuple_v< ArgsTuple > &&ttg::meta::is_void_v< Key >, void > op(ArgsTuple &&args_tuple, output_terminalsT &out)
Definition: make_tt.h:87
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&ttg::meta::is_void_v< Key >, void > op(output_terminalsT &out)
Definition: make_tt.h:98
std::enable_if_t< ttg::meta::is_empty_tuple_v< ArgsTuple > &&!ttg::meta::is_void_v< Key >, void > op(Key &&key, output_terminalsT &out)
Definition: make_tt.h:92
CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:71
Edge is used to connect In and Out terminals.
Definition: edge.h:25
#define TTG_HAVE_DEVICE
Definition: config.in.h:33
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"))
Definition: make_tt.h:659
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.
Definition: make_tt.h:429
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.
Definition: make_tt.h:560
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"))
Definition: make_tt.h:650
constexpr auto get(span< E, S > s) -> decltype(s[N])
Definition: span.h:492
typename make_index_sequence_t< I... >::type make_index_sequence
constexpr bool probe_last_v
Definition: meta.h:120
auto compute_arg_binding_types(Func &func, typelist< Typelists... > argument_type_lists)
Definition: callable.h:154
typename tuple_concat< TupleTs... >::type tuple_concat_t
Definition: meta.h:60
typename candidate_argument_bindings< T >::type candidate_argument_bindings_t
Definition: callable.h:221
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8
ExecutionSpace
denotes task execution space
Definition: execution.h:17
void abort()
Aborts the TTG program using the default backend's ttg_abort method.
Definition: run.h:62
meta::typelist< Ts... > typelist
Definition: typelist.h:81
TTG_CXX_COROUTINE_NAMESPACE::coroutine_handle< Promise > coroutine_handle
Definition: coroutine.h:24
drops N elements from the front
Definition: meta.h:349
take first N elements of a type list
Definition: meta.h:373
A container for types.
Definition: typelist.h:24