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 
7 // Class to wrap a callable with signature
8 //
9 // case 1 (keyT != void): returnT op(auto&& key, input_valuesT&&..., std::tuple<output_terminalsT...>&)
10 // case 2 (keyT == void): returnT op(input_valuesT&&..., std::tuple<output_terminalsT...>&)
11 //
12 // returnT is void for funcT = synchronous (ordinary) function and the appropriate return type for funcT=coroutine
13 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
14  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
15  typename keyT, typename output_terminalsT, typename... input_valuesT>
17  : public TT<
18  keyT, output_terminalsT,
19  CallableWrapTT<funcT, returnT, funcT_receives_input_tuple, funcT_receives_outterm_tuple, space, keyT, output_terminalsT, input_valuesT...>,
20  ttg::typelist<input_valuesT...>, space> {
21  using baseT = typename CallableWrapTT::ttT;
22 
23  using input_values_tuple_type = typename baseT::input_values_tuple_type;
24  using input_refs_tuple_type = typename baseT::input_refs_tuple_type;
25  using input_edges_type = typename baseT::input_edges_type;
26  using output_edges_type = typename baseT::output_edges_type;
27 
28  using noref_funcT = std::remove_reference_t<funcT>;
29  std::conditional_t<std::is_function_v<noref_funcT>, std::add_pointer_t<noref_funcT>, noref_funcT> func;
30 
31  using op_return_type =
32 #ifdef TTG_HAVE_COROUTINE
33  std::conditional_t<std::is_same_v<returnT, ttg::resumable_task>,
35 #ifdef TTG_HAVE_DEVICE
36  std::conditional_t<std::is_same_v<returnT, ttg::device::Task>,
37  ttg::device::Task::base_type,
38  void>
39 #else // TTG_HAVE_DEVICE
40  void
41 #endif // TTG_HAVE_DEVICE
42  >;
43 #else // TTG_HAVE_COROUTINE
44  void;
45 #endif // TTG_HAVE_COROUTINE
46 
47 protected:
48 
49  template<typename ReturnT>
50  auto process_return(ReturnT&& ret, output_terminalsT &out) {
51  static_assert(std::is_same_v<std::remove_reference_t<decltype(ret)>, returnT>,
52  "CallableWrapTT<funcT,returnT,...>: returnT does not match the actual return type of funcT");
53  if constexpr (!std::is_void_v<returnT>) { // protect from compiling for void returnT
54 #ifdef TTG_HAVE_COROUTINE
55  if constexpr (std::is_same_v<returnT, ttg::resumable_task>) {
57  // if task completed destroy it
58  if (ret.completed()) {
59  ret.destroy();
60  } else { // if task is suspended return the coroutine promise ptr
61  coro_handle = ret;
62  }
63  return coro_handle;
64  } else
65 #ifdef TTG_HAVE_DEVICE
66  if constexpr (std::is_same_v<returnT, ttg::device::Task>) {
67  ttg::device::Task::base_type coro_handle = ret;
68  return coro_handle;
69  }
70 #else // TTG_HAVE_DEVICE
71  ttg::abort(); // should not happen
72 #endif // TTG_HAVE_DEVICE
73  if constexpr (!(std::is_same_v<returnT, ttg::resumable_task>
74 #ifdef TTG_HAVE_DEVICE
75  || std::is_same_v<returnT, ttg::device::Task>
76 #endif // TTG_HAVE_DEVICE
77  ))
78 #endif
79  {
80  static_assert(std::tuple_size_v<std::remove_reference_t<decltype(out)>> == 1,
81  "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
82  "value only if there is only 1 out terminal");
83  static_assert(std::tuple_size_v<returnT> <= 2,
84  "CallableWrapTT<funcT,returnT,funcT_receives_outterm_tuple=true,...): funcT can return a "
85  "value only if it is a plain value (then sent with null key), a tuple-like containing a single "
86  "key (hence value is void), or a tuple-like containing a key and a value");
87  if constexpr (std::tuple_size_v<returnT> == 0)
88  std::get<0>(out).sendv(std::move(ret));
89  else if constexpr (std::tuple_size_v<returnT> == 1)
90  std::get<0>(out).sendk(std::move(std::get<0>(ret)));
91  else if constexpr (std::tuple_size_v<returnT> == 2)
92  std::get<0>(out).send(std::move(std::get<0>(ret)), std::move(std::get<1>(ret)));
93  return;
94  }
95  }
96  }
97 
99  template <typename Key, typename Tuple, std::size_t... S>
100  auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
101  using func_args_t = ttg::meta::tuple_concat_t<std::tuple<const Key &>, input_refs_tuple_type, output_edges_type>;
102  auto invoke_func_handle_ret = [&](auto&&... args){
103  if constexpr (std::is_void_v<returnT>) {
104  func(std::forward<Key>(key), std::forward<decltype(args)>(args)...);
105  } else {
106  return process_return(func(std::forward<Key>(key), std::forward<decltype(args)>(args)...), out);
107  }
108  };
109  auto unpack_input_tuple_if_needed = [&](auto&&... args){
110  if constexpr (funcT_receives_input_tuple) {
111  return invoke_func_handle_ret(std::forward<Tuple>(args_tuple), std::forward<decltype(args)>(args)...);
112  } else {
113  return invoke_func_handle_ret(baseT::template get<S, std::tuple_element_t<S + 1, func_args_t>>(std::forward<Tuple>(args_tuple))...,
114  std::forward<decltype(args)>(args)...);
115  }
116  };
117 
118  if constexpr (funcT_receives_outterm_tuple) {
119  return unpack_input_tuple_if_needed(out);
120  } else {
121  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
122  this->set_outputs_tls_ptr();
123  // make sure the output tls is reset
124  auto _ = ttg::detail::scope_exit(
125  [this, old_output_tls_ptr](){
126  this->set_outputs_tls_ptr(old_output_tls_ptr);
127  });
128  return unpack_input_tuple_if_needed();
129  }
130  }
131 
132  template <typename Tuple, std::size_t... S>
133  auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence<S...>) {
135 
136  auto invoke_func_handle_ret = [&](auto&&... args){
137  if constexpr (std::is_void_v<returnT>) {
138  func(std::forward<decltype(args)>(args)...);
139  } else {
140  return process_return(func(std::forward<decltype(args)>(args)...), out);
141  }
142  };
143  auto unpack_input_tuple_if_needed = [&](auto&& fn, auto&&... args){
144  if constexpr (funcT_receives_input_tuple) {
145  return fn(std::forward<Tuple>(args_tuple), std::forward<decltype(args)>(args)...);
146  } else {
147  return fn(baseT::template get<S, std::tuple_element_t<S, func_args_t>>(std::forward<Tuple>(args_tuple))...,
148  std::forward<decltype(args)>(args)...);
149  }
150  };
151 
152  if constexpr (funcT_receives_outterm_tuple) {
153  return unpack_input_tuple_if_needed(invoke_func_handle_ret, out);
154  } else {
155  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
156  this->set_outputs_tls_ptr();
157  // make sure the output tls is reset
158  auto _ = ttg::detail::scope_exit(
159  [this, old_output_tls_ptr](){
160  this->set_outputs_tls_ptr(old_output_tls_ptr);
161  });
162  return unpack_input_tuple_if_needed(invoke_func_handle_ret);
163  }
164  }
165 
166  template <typename Key>
167  auto call_func(Key &&key, output_terminalsT &out) {
168  auto invoke_func_handle_ret = [&](auto&&... args){
169  if constexpr (std::is_void_v<returnT>) {
170  func(std::forward<Key>(key), std::forward<decltype(args)>(args)...);
171  } else {
172  return process_return(func(std::forward<Key>(key), std::forward<decltype(args)>(args)...), out);
173  }
174  };
175 
176  auto invoke_func_empty_tuple = [&](auto&&... args){
177  if constexpr(funcT_receives_input_tuple) {
178  invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
179  } else {
180  invoke_func_handle_ret(std::forward<decltype(args)>(args)...);
181  }
182  };
183 
184  if constexpr (funcT_receives_outterm_tuple) {
185  invoke_func_handle_ret(out);
186  } else {
187  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
188  this->set_outputs_tls_ptr();
189  // make sure the output tls is reset
190  auto _ = ttg::detail::scope_exit(
191  [this, old_output_tls_ptr](){
192  this->set_outputs_tls_ptr(old_output_tls_ptr);
193  });
194  return invoke_func_handle_ret();
195  }
196  }
197 
198  template <typename OutputTerminals>
199  auto call_func(OutputTerminals &out) {
200 
201  auto invoke_func_handle_ret = [&](auto&&... args){
202  if constexpr (std::is_void_v<returnT>) {
203  func(std::forward<decltype(args)>(args)...);
204  } else {
205  return process_return(func(std::forward<decltype(args)>(args)...), out);
206  }
207  };
208 
209  auto invoke_func_empty_tuple = [&](auto&&... args){
210  if constexpr(funcT_receives_input_tuple) {
211  return invoke_func_handle_ret(std::tuple<>{}, std::forward<decltype(args)>(args)...);
212  } else {
213  return invoke_func_handle_ret(std::forward<decltype(args)>(args)...);
214  }
215  };
216 
217  if constexpr (funcT_receives_outterm_tuple) {
218  return invoke_func_empty_tuple(out);
219  } else {
220  auto old_output_tls_ptr = this->outputs_tls_ptr_accessor();
221  this->set_outputs_tls_ptr();
222  // make sure the output tls is reset
223  auto _ = ttg::detail::scope_exit(
224  [this, old_output_tls_ptr](){
225  this->set_outputs_tls_ptr(old_output_tls_ptr);
226  });
227  return invoke_func_empty_tuple();
228  }
229  }
230 
231  template <typename Tuple, std::size_t... I>
232  static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence<I...>) {
233  return std::array<ttg::TerminalBase *, sizeof...(I)>{
234  {static_cast<ttg::TerminalBase *>(&std::get<I>(output_terminals))...}};
235  }
236 
237  public:
238  template <typename funcT_>
239  CallableWrapTT(funcT_ &&f, const input_edges_type &inedges, const typename baseT::output_edges_type &outedges,
240  const std::string &name, const std::vector<std::string> &innames,
241  const std::vector<std::string> &outnames)
242  : baseT(inedges, outedges, name, innames, outnames), func(std::forward<funcT_>(f)) {}
243 
244  template <typename funcT_>
245  CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector<std::string> &innames,
246  const std::vector<std::string> &outnames)
247  : baseT(name, innames, outnames), func(std::forward<funcT_>(f)) {}
248 
249  template <typename Key, typename ArgsTuple>
250  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
251  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && !ttg::meta::is_void_v<Key>,
252  op_return_type>
253  op(Key &&key, ArgsTuple &&args_tuple, output_terminalsT &out) {
254  assert(&out == &baseT::get_output_terminals());
255  return call_func(std::forward<Key>(key), std::forward<ArgsTuple>(args_tuple), out,
256  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
257  };
258 
259  template <typename ArgsTuple, typename Key = keyT>
260  std::enable_if_t<std::is_same_v<ArgsTuple, input_refs_tuple_type> &&
261  !ttg::meta::is_empty_tuple_v<input_refs_tuple_type> && ttg::meta::is_void_v<Key>,
262  op_return_type>
263  op(ArgsTuple &&args_tuple, output_terminalsT &out) {
264  assert(&out == &baseT::get_output_terminals());
265  return call_func(std::forward<ArgsTuple>(args_tuple), out,
266  std::make_index_sequence<std::tuple_size_v<ArgsTuple>>{});
267  };
268 
269  template <typename Key, typename ArgsTuple = input_refs_tuple_type>
270  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && !ttg::meta::is_void_v<Key>, op_return_type> op(
271  Key &&key, output_terminalsT &out) {
272  assert(&out == &baseT::get_output_terminals());
273  return call_func(std::forward<Key>(key), out);
274  };
275 
276  template <typename Key = keyT, typename ArgsTuple = input_refs_tuple_type>
277  std::enable_if_t<ttg::meta::is_empty_tuple_v<ArgsTuple> && ttg::meta::is_void_v<Key>, op_return_type> op(
278  output_terminalsT &out) {
279  assert(&out == &baseT::get_output_terminals());
280  return call_func(out);
281  };
282 };
283 
284 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
285  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
286  typename keyT, typename output_terminalsT, typename input_values_typelistT>
288 
289 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
290  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
291  typename keyT, typename output_terminalsT, typename... input_valuesT>
292 struct CallableWrapTTAsTypelist<funcT, returnT, funcT_receives_input_tuple,
293  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
294  std::tuple<input_valuesT...>> {
295  using type = CallableWrapTT<funcT, returnT, funcT_receives_input_tuple,
296  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
297  std::remove_reference_t<input_valuesT>...>;
298 };
299 
300 template <typename funcT, typename returnT, bool funcT_receives_input_tuple,
301  bool funcT_receives_outterm_tuple, ttg::ExecutionSpace space,
302  typename keyT, typename output_terminalsT, typename... input_valuesT>
303 struct CallableWrapTTAsTypelist<funcT, returnT, funcT_receives_input_tuple,
304  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
305  ttg::meta::typelist<input_valuesT...>> {
306  using type = CallableWrapTT<funcT, returnT, funcT_receives_input_tuple,
307  funcT_receives_outterm_tuple, space, keyT, output_terminalsT,
308  std::remove_reference_t<input_valuesT>...>;
309 };
310 
311 // clang-format off
337 // clang-format on
338 template <ttg::ExecutionSpace space,
339  typename keyT = void,
340  typename funcT,
341  typename... input_edge_valuesT,
342  typename... output_edgesT>
343 auto make_tt_tpl(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
344  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
345  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT),
346  "input"),
347  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT),
348  "output")) {
349  // ensure input types do not contain Void
350  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
351  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
352 
353  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
354 
355  // list of base datum types (T or const T)
357 
358  // gross list of candidate argument types
359  using gross_candidate_func_args_t = ttg::meta::typelist<
362  std::tuple<std::add_lvalue_reference_t<typename ttg::Edge<keyT, input_edge_valuesT>::value_type>...>>,
364 
365  // net list of candidate argument types excludes the empty typelists for void arguments
366  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
367 
368  // compute list of argument types with which func can be invoked
369  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
370  using return_type_typelist_and_gross_func_args_t =
371  decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{}));
372  using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
373  using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
374  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
375  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
376  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
377  "ttd::make_tt_tpl(func, inedges, ...): could not detect how to invoke generic callable func, either "
378  "the signature of func "
379  "is faulty, or inedges does match the expected list of types, or both");
380 
381  // net argument typelist
382  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
383  constexpr auto num_args = std::tuple_size_v<func_args_t>;
384 
385  // if given task id, make sure it's passed via const lvalue ref
386  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
387  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
388  constexpr bool TASK_ID_PASSED_AS_NONREF =
389  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
390  static_assert(
391  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
392  "ttg::make_tt_tpl(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
393 
394  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
395  constexpr bool have_outterm_tuple =
396  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
398  gross_func_args_t>;
399  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
400  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, true, func_args_t> : true;
401  static_assert(
402  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
403  "ttd::make_tt_tpl(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
404 
405  static_assert(num_args == 3 - (void_key ? 1 : 0) - (have_outterm_tuple ? 0 : 1),
406  "ttg::make_tt_tpl(func, ...): func takes wrong number of arguments (2, or 1, if keyT=void + optional "
407  "tuple of output terminals)");
408 
409  // 2. input_args_t = {input_valuesT&&...}
410  using nondecayed_input_args_t = std::tuple_element_t<void_key ? 0 : 1, func_args_t>;
411  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
412  !ttg::meta::is_any_nonconst_lvalue_reference_v<nondecayed_input_args_t>;
413  static_assert(
414  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
415  "ttg::make_tt_tpl(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
416  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
417  using input_args_t = std::decay_t<nondecayed_input_args_t>;
418  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
419  using wrapT = typename CallableWrapTTAsTypelist<funcT, func_return_t, true, have_outterm_tuple, space, keyT,
420  output_terminals_type, input_args_t>::type;
421  static_assert(std::is_same_v<decayed_input_args_t, std::tuple<input_edge_valuesT...>>,
422  "ttg::make_tt_tpl(func, inedges, outedges): inedges value types do not match argument types of func");
423 
424  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
425 }
426 
427 template <typename keyT = void,
428  typename funcT,
429  typename... input_edge_valuesT,
430  typename... output_edgesT>
431 auto make_tt_tpl(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
432  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
433  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT),
434  "input"),
435  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT),
436  "output"))
437 {
438  return make_tt_tpl<ttg::ExecutionSpace::Host, keyT>(
439  std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
440 }
441 // clang-format off
487 // clang-format on
488 template <ttg::ExecutionSpace space,
489  typename keyT = void, typename funcT,
490  typename... input_edge_valuesT, typename... output_edgesT>
491 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
492  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
493  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
494  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
495  // ensure input types do not contain Void
496  static_assert(ttg::meta::is_none_Void_v<input_edge_valuesT...>, "ttg::Void is for internal use only, do not use it");
497 
498  using output_terminals_type = typename ttg::edges_to_output_terminals<std::tuple<output_edgesT...>>::type;
499 
500  constexpr auto void_key = ttg::meta::is_void_v<keyT>;
501 
502  // list of base datum types (T or const T)
504 
505  // gross list of candidate argument types
506  using gross_candidate_func_args_t = ttg::meta::typelist<
510 
511  // net list of candidate argument types excludes the empty typelists for void arguments
512  using candidate_func_args_t = ttg::meta::filter_t<gross_candidate_func_args_t, ttg::meta::typelist_is_not_empty>;
513 
514  // gross argument typelist for invoking func, can include void for optional args
515  constexpr static auto func_is_generic = ttg::meta::is_generic_callable_v<funcT>;
516  using return_type_typelist_and_gross_func_args_t =
517  decltype(ttg::meta::compute_arg_binding_types(func, candidate_func_args_t{}));
518  using func_return_t = std::tuple_element_t<0, std::tuple_element_t<0, return_type_typelist_and_gross_func_args_t>>;
519  using gross_func_args_t = std::tuple_element_t<1, return_type_typelist_and_gross_func_args_t>;
520  constexpr auto DETECTED_HOW_TO_INVOKE_GENERIC_FUNC =
521  func_is_generic ? !std::is_same_v<gross_func_args_t, ttg::typelist<>> : true;
522  static_assert(DETECTED_HOW_TO_INVOKE_GENERIC_FUNC,
523  "ttd::make_tt(func, inedges, ...): could not detect how to invoke generic callable func, either the "
524  "signature of func "
525  "is faulty, or inedges does match the expected list of types, or both");
526 
527  // net argument typelist
528  using func_args_t = ttg::meta::drop_void_t<gross_func_args_t>;
529  constexpr auto num_args = std::tuple_size_v<func_args_t>;
530 
531  // if given task id, make sure it's passed via const lvalue ref
532  constexpr bool TASK_ID_PASSED_AS_CONST_LVALUE_REF =
533  !void_key ? ttg::meta::probe_first_v<ttg::meta::is_const_lvalue_reference, true, func_args_t> : true;
534  constexpr bool TASK_ID_PASSED_AS_NONREF =
535  !void_key ? !ttg::meta::probe_first_v<std::is_reference, true, func_args_t> : true;
536  static_assert(
537  TASK_ID_PASSED_AS_CONST_LVALUE_REF || TASK_ID_PASSED_AS_NONREF,
538  "ttg::make_tt(func, ...): if given to func, the task id must be passed by const lvalue ref or by value");
539 
540  // if given out-terminal tuple, make sure it's passed via nonconst lvalue ref
541  constexpr bool have_outterm_tuple =
542  func_is_generic ? !ttg::meta::is_last_void_v<gross_func_args_t>
543  : ttg::meta::probe_last_v<ttg::meta::decays_to_output_terminal_tuple, false, gross_func_args_t>;
544  constexpr bool OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF =
545  have_outterm_tuple ? ttg::meta::probe_last_v<ttg::meta::is_nonconst_lvalue_reference, false, func_args_t> : true;
546  static_assert(
547  OUTTERM_TUPLE_PASSED_AS_NONCONST_LVALUE_REF,
548  "ttg::make_tt(func, ...): if given to func, the output terminal tuple must be passed by nonconst lvalue ref");
549 
550  // TT needs actual types of arguments to func ... extract them and pass to CallableWrapTT
551  using input_edge_value_types = ttg::meta::typelist<std::decay_t<input_edge_valuesT>...>;
552  // input_args_t = {input_valuesT&&...}
553  using input_args_t = typename ttg::meta::take_first_n<
554  typename ttg::meta::drop_first_n<func_args_t, std::size_t(void_key ? 0 : 1)>::type,
555  std::tuple_size_v<func_args_t> - (void_key ? 0 : 1) - (have_outterm_tuple ? 1 : 0)>::type;
556  constexpr auto NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF =
557  !ttg::meta::is_any_nonconst_lvalue_reference_v<input_args_t>;
558  static_assert(
559  NO_ARGUMENTS_PASSED_AS_NONCONST_LVALUE_REF,
560  "ttg::make_tt(func, inedges, outedges): one or more arguments to func can only be passed by nonconst lvalue "
561  "ref; this is illegal, should only pass arguments as const lvalue ref or (nonconst) rvalue ref");
562  using decayed_input_args_t = ttg::meta::decayed_typelist_t<input_args_t>;
563  // 3. full_input_args_t = edge-types with non-void types replaced by input_args_t
564  using full_input_args_t = ttg::meta::replace_nonvoid_t<input_edge_value_types, input_args_t>;
565  using wrapT = typename CallableWrapTTAsTypelist<funcT, func_return_t, false, have_outterm_tuple, space, keyT,
566  output_terminals_type, full_input_args_t>::type;
567 
568  return std::make_unique<wrapT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
569 }
570 
571 template <typename keyT = void, typename funcT,
572  typename... input_edge_valuesT, typename... output_edgesT>
573 auto make_tt(funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges = std::tuple<>{},
574  const std::tuple<output_edgesT...> &outedges = std::tuple<>{}, const std::string &name = "wrapper",
575  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
576  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
577  return make_tt<ttg::ExecutionSpace::Host, keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
578 }
579 
580 template <typename keyT, typename funcT, typename... input_valuesT, typename... output_edgesT>
581 [[deprecated("use make_tt_tpl instead")]] inline auto wrapt(
582  funcT &&func, const std::tuple<ttg::Edge<keyT, input_valuesT>...> &inedges,
583  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
584  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_valuesT), "input"),
585  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
586  return make_tt_tpl<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
587 }
588 
589 template <typename keyT, typename funcT, typename... input_edge_valuesT, typename... output_edgesT>
590 [[deprecated("use make_tt instead")]] auto wrap(
591  funcT &&func, const std::tuple<ttg::Edge<keyT, input_edge_valuesT>...> &inedges,
592  const std::tuple<output_edgesT...> &outedges, const std::string &name = "wrapper",
593  const std::vector<std::string> &innames = std::vector<std::string>(sizeof...(input_edge_valuesT), "input"),
594  const std::vector<std::string> &outnames = std::vector<std::string>(sizeof...(output_edgesT), "output")) {
595  return make_tt<keyT>(std::forward<funcT>(func), inedges, outedges, name, innames, outnames);
596 }
597 
598 #endif // TTG_MAKE_TT_H
CallableWrapTT(funcT_ &&f, const std::string &name, const std::vector< std::string > &innames, const std::vector< std::string > &outnames)
Definition: make_tt.h:245
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:277
auto call_func(Key &&key, Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:100
auto call_func(Tuple &&args_tuple, output_terminalsT &out, std::index_sequence< S... >)
Definition: make_tt.h:133
auto call_func(Key &&key, output_terminalsT &out)
Definition: make_tt.h:167
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:263
auto call_func(OutputTerminals &out)
Definition: make_tt.h:199
static auto make_output_terminal_ptrs(const Tuple &output_terminals, std::index_sequence< I... >)
Definition: make_tt.h:232
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:253
auto process_return(ReturnT &&ret, output_terminalsT &out)
Definition: make_tt.h:50
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)
Definition: make_tt.h:239
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:270
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:590
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:343
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:491
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:581
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:117
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:57
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:333
take first N elements of a type list
Definition: meta.h:357
A container for types.
Definition: typelist.h:24