terminal.h
Go to the documentation of this file.
1 #ifndef TTG_TERMINALS_H
2 #define TTG_TERMINALS_H
3 
4 #include <exception>
5 #include <stdexcept>
6 #include <type_traits>
7 
8 #include "ttg/base/terminal.h"
9 #include "ttg/fwd.h"
10 #include "ttg/util/demangle.h"
11 #include "ttg/util/meta.h"
12 #include "ttg/util/trace.h"
13 #include "ttg/world.h"
14 #include "ttg/run.h"
15 
16 namespace ttg {
17  namespace detail {
18 
19  /* Wraps any key,value data structure.
20  * Elements of the data structure can be accessed using get method, which calls the at method of the Container.
21  * keyT - taskID
22  * valueT - Value type of the Container
23  */
24  template<typename keyT, typename valueT>
26  std::function<valueT (keyT const& key)> get = nullptr;
27  std::function<size_t (keyT const& key)> owner = nullptr;
28 
29  ContainerWrapper() = default;
30  ContainerWrapper(const ContainerWrapper &) = default;
33 
34  template<typename T, typename mapperT, typename keymapT, std::enable_if_t<!std::is_same<std::decay_t<T>,
35  ContainerWrapper>{}, bool> = true>
36  //Store a pointer to the user's container in std::any, no copies
37  ContainerWrapper(T &t, mapperT &&mapper,
38  keymapT &&keymap) : get([&t, mapper = std::forward<mapperT>(mapper)](keyT const &key) {
39  if constexpr (!std::is_class_v<T> && std::is_invocable_v<T, keyT>) {
40  auto k = mapper(key);
41  return t(k); //Call the user-defined lambda function.
42  }
43  else
44  {
45  auto k = mapper(key);
46  //at method returns a const ref to the item.
47  return t.at(k);
48  }
49  }),
50  owner([&t, mapper = std::forward<mapperT>(mapper),
51  keymap = std::forward<keymapT>(keymap)](keyT const &key) {
52  auto idx = mapper(key); //Mapper to map task ID to index of the data structure.
53  return keymap(idx);
54  })
55  {}
56  };
57 
58  template <typename valueT> struct ContainerWrapper<void, valueT> {
59  std::function<valueT ()> get = nullptr;
60  std::function<size_t ()> owner = nullptr;
61  };
62 
63  template <typename keyT> struct ContainerWrapper<keyT, void> {
64  std::function<std::nullptr_t (keyT const& key)> get = nullptr;
65  std::function<size_t (keyT const& key)> owner = nullptr;
66  };
67 
68  template <typename valueT> struct ContainerWrapper<ttg::Void, valueT> {
69  std::function<valueT ()> get = nullptr;
70  std::function<size_t ()> owner = nullptr;
71  };
72 
73  template <> struct ContainerWrapper<void, void> {
74  std::function<std::nullptr_t ()> get = nullptr;
75  std::function<size_t ()> owner = nullptr;
76  };
77  } //namespace detail
78 
81  template <typename keyT = void>
82  class InTerminalBase : public TerminalBase {
83  public:
84  typedef keyT key_type;
85  static_assert(std::is_same_v<keyT, std::decay_t<keyT>>,
86  "InTerminalBase<keyT,valueT> assumes keyT is a non-decayable type");
87  using setsize_callback_type = meta::detail::setsize_callback_t<keyT>;
88  using finalize_callback_type = meta::detail::finalize_callback_t<keyT>;
89  static constexpr bool is_an_input_terminal = true;
90 
91  protected:
93 
96 
99  this->setsize_callback = setsize_callback;
100  this->finalize_callback = finalize_callback;
101  }
102 
103  private:
104  // No moving, copying, assigning permitted
105  InTerminalBase(InTerminalBase &&other) = delete;
106  InTerminalBase(const InTerminalBase &other) = delete;
107  InTerminalBase &operator=(const InTerminalBase &other) = delete;
108  InTerminalBase &operator=(const InTerminalBase &&other) = delete;
109 
110  public:
111  template <typename Key = keyT>
112  std::enable_if_t<!meta::is_void_v<Key>, void> set_size(const Key &key, std::size_t size) {
113  if (!setsize_callback) throw std::runtime_error("set_size callback not initialized");
114  setsize_callback(key, size);
115  }
116 
117  template <typename Key = keyT>
118  std::enable_if_t<meta::is_void_v<Key>, void> set_size(std::size_t size) {
119  if (!setsize_callback) throw std::runtime_error("set_size callback not initialized");
121  }
122 
123  template <typename Key = keyT>
124  std::enable_if_t<!meta::is_void_v<Key>, void> finalize(const Key &key) {
125  // std::cout << "In::finalize::\n";
126  if (!finalize_callback) throw std::runtime_error("finalize callback not initialized");
127  finalize_callback(key);
128  }
129 
130  template <typename Key = keyT>
131  std::enable_if_t<meta::is_void_v<Key>, void> finalize() {
132  if (!finalize_callback) throw std::runtime_error("finalize callback not initialized");
134  }
135  };
136 
141 
142  template <typename keyT = void, typename valueT = void>
143  class In : public InTerminalBase<keyT> {
144  public:
146  typedef valueT value_type;
147  typedef keyT key_type;
148  static_assert(std::is_same_v<keyT, std::decay_t<keyT>>, "In<keyT,valueT> assumes keyT is a non-decayable type");
149  // valueT can be T or const T
150  static_assert(std::is_same_v<std::remove_const_t<valueT>, std::decay_t<valueT>>,
151  "In<keyT,valueT> assumes std::remove_const<T> is a non-decayable type");
153  using send_callback_type = meta::detail::send_callback_t<keyT, std::decay_t<valueT>>;
154  using move_callback_type = meta::detail::move_callback_t<keyT, std::decay_t<valueT>>;
155  using broadcast_callback_type = meta::detail::broadcast_callback_t<keyT, std::decay_t<valueT>>;
158  using prepare_send_callback_type = meta::detail::prepare_send_callback_t<keyT, std::decay_t<valueT>>;
159  static constexpr bool is_an_input_terminal = true;
161 
162  private:
163  send_callback_type send_callback;
164  move_callback_type move_callback;
165  broadcast_callback_type broadcast_callback;
166  prepare_send_callback_type prepare_send_callback;
167 
168  // No moving, copying, assigning permitted
169  In(In &&other) = delete;
170  In(const In &other) = delete;
171  In &operator=(const In &other) = delete;
172  In &operator=(const In &&other) = delete;
173 
174  void connect(TerminalBase *p) override {
175  throw "Edge: to connect terminals use out->connect(in) rather than in->connect(out)";
176  }
177 
178  public:
180  In() : InTerminalBase<keyT>(std::is_const_v<valueT> ? TerminalBase::Type::Read : TerminalBase::Type::Consume){};
181 
192  void set_callback(const send_callback_type &send_callback, const move_callback_type &move_callback,
193  const broadcast_callback_type &bcast_callback = broadcast_callback_type{},
196  const prepare_send_callback_type &prepare_send_callback = prepare_send_callback_type{}) {
197  this->send_callback = send_callback;
198  this->move_callback = move_callback;
199  this->broadcast_callback = bcast_callback;
200  this->prepare_send_callback = prepare_send_callback;
202  }
203 
204  template <typename Key = keyT, typename Value = valueT>
205  std::enable_if_t<meta::is_none_void_v<Key, Value>, void>
206  send(const Key &key, Value &&value) {
207  static_assert(meta::is_none_void_v<keyT, valueT>, "ttg::send<>() sending to a terminal expecting void key and value; use ttg::send<>() instead");
208  static_assert(!meta::is_void_v<keyT>, "ttg::send<>(key,value) sending to a terminal expecting void key; use ttg::sendv(value) instead");
209  static_assert(!meta::is_void_v<valueT>, "ttg::send<>(key,value) sending to a terminal expecting void value; use ttg::sendk(key) instead");
210  constexpr auto value_is_rvref = !std::is_reference_v<Value>;
211  if constexpr (value_is_rvref) {
212  if (!move_callback) throw std::runtime_error("move callback not initialized");
213  move_callback(key, std::move(value));
214  } else {
215  if (!send_callback) throw std::runtime_error("send callback not initialized");
216  send_callback(key, value);
217  }
218  }
219 
220  template <typename Key = keyT>
221  std::enable_if_t<!meta::is_void_v<Key>, void> sendk(const Key &key) {
222  static_assert(!meta::is_void_v<keyT> && meta::is_void_v<valueT>, "ttg::sendk<>(key) sending to a terminal expecting void key and nonvoid value; use ttg::sendv<>(value) instead");
223  static_assert(!meta::is_void_v<keyT>, "ttg::sendk<>(key) sending to a terminal expecting void key; use ttg::send() instead");
224  static_assert(meta::is_void_v<valueT>, "ttg::sendk<>(key) sending to a terminal expecting nonvoid value; use ttg::send(key,value) instead");
225  if (!send_callback) throw std::runtime_error("send callback not initialized");
226  send_callback(key);
227  }
228 
229  template <typename Value = valueT>
230  std::enable_if_t<!meta::is_void_v<Value>, void> sendv(
231  Value &&value) {
232  static_assert(meta::is_void_v<keyT> && !meta::is_void_v<valueT>, "ttg::sendv<>(value) sending to a terminal expecting nonvoid key and void value; use ttg::sendk<>(key) instead");
233  static_assert(meta::is_void_v<keyT>, "ttg::sendv<>(value) sending to a terminal expecting nonvoid key; use ttg::send(key, value) instead");
234  static_assert(!meta::is_void_v<valueT>, "ttg::sendv<>(value) sending to a terminal expecting void value; use ttg::send() instead");
235  constexpr auto value_is_rvref = !std::is_reference_v<Value>;
236  if constexpr (value_is_rvref) {
237  if (!move_callback) throw std::runtime_error("move callback not initialized");
238  move_callback(std::move(value));
239  }
240  else {
241  if (!send_callback) throw std::runtime_error("send callback not initialized");
242  send_callback(value);
243  }
244  }
245 
246  void send() {
247  static_assert(!meta::is_none_void_v<keyT, valueT>, "ttg::send<>() sending to a terminal expecting nonvoid key and value; use ttg::send<>(key,value) instead");
248  static_assert(meta::is_void_v<keyT>, "ttg::send<>() sending to a terminal expecting nonvoid key; use ttg::sendk<>(key) instead");
249  static_assert(meta::is_void_v<valueT>, "ttg::send<>() sending to a terminal expecting nonvoid value; use ttg::sendv<>(value) instead");
250  if (!send_callback) throw std::runtime_error("send callback not initialized");
251  send_callback();
252  }
253 
254  // An optimized implementation will need a separate callback for broadcast
255  // with a specific value for rangeT
256  template <typename rangeT, typename Value>
257  std::enable_if_t<!meta::is_void_v<Value>, void> broadcast(const rangeT &keylist, const Value &value) {
258  if (broadcast_callback) {
259  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
260  broadcast_callback(ttg::span<const keyT>(&(*std::begin(keylist)), std::distance(std::begin(keylist), std::end(keylist))),
261  value);
262  } else {
263  /* got something we cannot iterate over (single element?) so put one element in the span */
264  broadcast_callback(ttg::span<const keyT>(&keylist, 1), value);
265  }
266  } else {
267  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
268  for (auto &&key : keylist) send(key, value);
269  } else {
270  /* single element */
271  send(keylist, value);
272  }
273  }
274  }
275 
276  template <typename rangeT, typename Value>
277  std::enable_if_t<!meta::is_void_v<Value>, void> broadcast(const rangeT &keylist, Value &&value) {
278  const Value &v = value;
279  if (broadcast_callback) {
280  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
281  broadcast_callback(
282  ttg::span<const keyT>(&(*std::begin(keylist)), std::distance(std::begin(keylist), std::end(keylist))), v);
283  } else {
284  /* got something we cannot iterate over (single element?) so put one element in the span */
285  broadcast_callback(ttg::span<const keyT>(&keylist, 1), v);
286  }
287  } else {
288  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
289  for (auto &&key : keylist) send(key, v);
290  } else {
291  /* got something we cannot iterate over (single element?) so put one element in the span */
292  send(ttg::span<const keyT>(&keylist, 1), v);
293  }
294  }
295  }
296 
297  template <typename rangeT, typename Value = valueT>
298  std::enable_if_t<meta::is_void_v<Value>, void> broadcast(const rangeT &keylist) {
299  if (broadcast_callback) {
300  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
301  broadcast_callback(
302  ttg::span<const keyT>(&(*std::begin(keylist)), std::distance(std::begin(keylist), std::end(keylist))));
303  } else {
304  /* got something we cannot iterate over (single element?) so put one element in the span */
305  broadcast_callback(ttg::span<const keyT>(&keylist, 1));
306  }
307  } else {
308  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
309  for (auto &&key : keylist) sendk(key);
310  } else {
311  /* got something we cannot iterate over (single element?) so put one element in the span */
312  sendk(ttg::span<const keyT>(&keylist, 1));
313  }
314  }
315  }
316 
317 
318  template <typename rangeT, typename Value>
319  void prepare_send(const rangeT &keylist, Value &&value) {
320  const std::remove_reference_t<Value> &v = value;
321  if (prepare_send_callback) {
322  if constexpr (ttg::meta::is_iterable_v<rangeT>) {
323  prepare_send_callback(ttg::span<const keyT>(&(*std::begin(keylist)),
324  std::distance(std::begin(keylist), std::end(keylist))),
325  v);
326  } else {
327  /* got something we cannot iterate over (single element?) so put one element in the span */
328  prepare_send_callback(ttg::span<const keyT>(&keylist, 1), v);
329  }
330  }
331  }
332 
333  template <typename Value>
334  void prepare_send(Value &&value) {
335  const std::remove_reference_t<Value> &v = value;
336  if (prepare_send_callback) {
337  prepare_send_callback(v);
338  }
339  }
340  };
341 
342  namespace detail {
343  template <typename keyT, typename... valuesT>
345  using type = std::tuple<ttg::In<keyT, valuesT>...>;
346  };
347 
348  template <typename keyT, typename... valuesT>
349  struct input_terminals_tuple<keyT, std::tuple<valuesT...>> {
350  using type = std::tuple<ttg::In<keyT, valuesT>...>;
351  };
352 
353  template <typename keyT, typename... valuesT>
354  using input_terminals_tuple_t = typename input_terminals_tuple<keyT, valuesT...>::type;
355  } // namespace detail
356 
357  namespace meta {
359  template <typename T>
360  inline constexpr bool is_input_terminal_v = false;
361  template <typename keyT>
362  inline constexpr bool is_input_terminal_v<InTerminalBase<keyT>> = true;
363  template <typename keyT, typename valueT>
364  inline constexpr bool is_input_terminal_v<In<keyT, valueT>> = true;
365 
366  template <typename T>
367  struct is_input_terminal : std::bool_constant<is_input_terminal_v<T>> {};
368  } // namespace meta
369 
372  template <typename keyT = void>
373  class OutTerminalBase : public TerminalBase {
374  public:
375  using key_type = keyT;
376  static_assert(std::is_same_v<keyT, std::decay_t<keyT>>, "Out<keyT,valueT> assumes keyT is a non-decayable type");
377  static constexpr bool is_an_output_terminal = true;
378 
379  private:
380  // No moving, copying, assigning permitted
381  OutTerminalBase(OutTerminalBase &&other) = delete;
382  OutTerminalBase(const OutTerminalBase &other) = delete;
383  OutTerminalBase &operator=(const OutTerminalBase &other) = delete;
384  OutTerminalBase &operator=(const OutTerminalBase &&other) = delete;
385 
386  public:
388 
389  auto nsuccessors() const { return get_connections().size(); }
390  const auto &successors() const { return get_connections(); }
391 
392  template <typename Key = keyT>
393  std::enable_if_t<!meta::is_void_v<Key>, void> set_size(const Key &key, std::size_t size) {
394  for (auto &&successor : successors()) {
395  assert(successor->get_type() != TerminalBase::Type::Write);
396  static_cast<InTerminalBase<keyT> *>(successor)->set_size(key, size);
397  }
398  }
399 
400  template <typename Key = keyT>
401  std::enable_if_t<meta::is_void_v<Key>, void> set_size(std::size_t size) {
402  for (auto &&successor : successors()) {
403  assert(successor->get_type() != TerminalBase::Type::Write);
404  static_cast<InTerminalBase<keyT> *>(successor)->set_size(size);
405  }
406  }
407 
408  template <typename Key = keyT>
409  std::enable_if_t<!meta::is_void_v<Key>, void> finalize(const Key &key) {
410  for (auto &&successor : successors()) {
411  assert(successor->get_type() != TerminalBase::Type::Write);
412  static_cast<InTerminalBase<keyT> *>(successor)->finalize(key);
413  }
414  }
415 
416  template <typename Key = keyT>
417  std::enable_if_t<meta::is_void_v<Key>, void> finalize() {
418  for (auto successor : successors()) {
419  assert(successor->get_type() != TerminalBase::Type::Write);
420  static_cast<InTerminalBase<keyT> *>(successor)->finalize();
421  }
422  }
423  };
424 
428  template <typename keyT = void, typename valueT = void>
429  class Out : public OutTerminalBase<keyT> {
430  public:
431  using value_type = valueT;
433  static_assert(std::is_same_v<valueT, std::decay_t<valueT>>,
434  "Out<keyT,valueT> assumes valueT is a non-decayable type");
436  static constexpr bool is_an_output_terminal = true;
437 
438  private:
439  // No moving, copying, assigning permitted
440  Out(Out &&other) = delete;
441  Out(const Out &other) = delete;
442  Out &operator=(const Out &other) = delete;
443  Out &operator=(const Out &&other) = delete;
444 
445  public:
446  Out() = default;
447 
449  void connect(TerminalBase *in) override {
450 #ifndef NDEBUG
451  if (in->get_type() == TerminalBase::Type::Read) {
452  typedef In<keyT, std::add_const_t<valueT>> input_terminal_type;
453  if (!dynamic_cast<input_terminal_type *>(in))
454  throw std::invalid_argument(
455  std::string("you are trying to connect terminals with incompatible types:\ntype of this Terminal = ") +
456  detail::demangled_type_name(this) + "\ntype of other Terminal" + detail::demangled_type_name(in));
457  } else if (in->get_type() == TerminalBase::Type::Consume) {
458  typedef In<keyT, valueT> input_terminal_type;
459  if (!dynamic_cast<input_terminal_type *>(in))
460  throw std::invalid_argument(
461  std::string("you are trying to connect terminals with incompatible types:\ntype of this Terminal = ") +
462  detail::demangled_type_name(this) + "\ntype of other Terminal" + detail::demangled_type_name(in));
463  } else // successor->type() == TerminalBase::Type::Write
464  throw std::invalid_argument(std::string("you are trying to connect an Out terminal to another Out terminal"));
465  trace(rank(), ": connected Out<> ", this->get_name(), "(ptr=", this, ") to In<> ", in->get_name(), "(ptr=", in,
466  ")");
467 #endif
468  this->connect_base(in);
469  //If I am a pull terminal, add me as (in)'s predecessor
470  if (this->is_pull_terminal)
471  in->connect_pull(this);
472  }
473 
474  template <typename Key = keyT, typename Value = valueT>
475  std::enable_if_t<!meta::is_void_v<Key> && meta::is_void_v<Value>, void> sendk(const Key &key) {
476  for (auto &&successor : this->successors()) {
477  assert(successor->get_type() != TerminalBase::Type::Write);
478  if (successor->get_type() == TerminalBase::Type::Read) {
479  static_cast<In<keyT, std::add_const_t<valueT>> *>(successor)->sendk(key);
480  } else if (successor->get_type() == TerminalBase::Type::Consume) {
481  static_cast<In<keyT, valueT> *>(successor)->sendk(key);
482  }
483  }
484  }
485 
486  template <typename Key = keyT, typename Value = valueT>
487  std::enable_if_t<meta::is_void_v<Key> && !meta::is_void_v<Value>, void> sendv(Value&& value) {
488  const std::size_t N = this->nsuccessors();
489  TerminalBase *move_successor = nullptr;
490  // send copies to every terminal except the one we will move the results to
491  for (std::size_t i = 0; i != N; ++i) {
492  TerminalBase *successor = this->successors().at(i);
493  if (successor->get_type() == TerminalBase::Type::Read) {
494  // if only have 1 successor forward value even if successor is read-only, so we can deal with move-only types
495  auto* read_successor = static_cast<In<keyT, std::add_const_t<valueT>> *>(successor);
496  if (N != 1)
497  read_successor->sendv(value);
498  else
499  read_successor->sendv(std::forward<Value>(value));
500  } else if (successor->get_type() == TerminalBase::Type::Consume) {
501  if (nullptr == move_successor) {
502  move_successor = successor;
503  } else {
504  static_cast<In<keyT, valueT> *>(successor)->sendv(value);
505  }
506  }
507  }
508  if (nullptr != move_successor) {
509  static_cast<In<keyT, valueT> *>(move_successor)->sendv(std::forward<Value>(value));
510  }
511  }
512 
513  template <typename Key = keyT, typename Value = valueT>
514  std::enable_if_t<meta::is_all_void_v<Key, Value>, void> send() {
515  trace(rank(), ": in ", this->get_name(), "(ptr=", this, ") Out<>::send: #successors=", this->successors().size());
516  for (auto &&successor : this->successors()) {
517  assert(successor->get_type() != TerminalBase::Type::Write);
518  if (successor->get_type() == TerminalBase::Type::Read) {
519  static_cast<In<keyT, std::add_const_t<valueT>> *>(successor)->send();
520  } else if (successor->get_type() == TerminalBase::Type::Consume) {
521  static_cast<In<keyT, valueT> *>(successor)->send();
522  } else {
523  throw std::logic_error("Out<>: invalid successor type");
524  }
525  trace("Out<> ", this->get_name(), "(ptr=", this, ") send to In<> ", successor->get_name(), "(ptr=", successor,
526  ")");
527  }
528  }
529 
530  template <typename Key = keyT, typename Value = valueT>
531  std::enable_if_t<meta::is_none_void_v<Key, Value>, void>
532  send(const Key &key, Value &&value) {
533  const std::size_t N = this->nsuccessors();
534  TerminalBase *move_successor = nullptr;
535  // send copies to every terminal except the one we will move the results to
536  for (std::size_t i = 0; i != N; ++i) {
537  TerminalBase *successor = this->successors().at(i);
538  if (successor->get_type() == TerminalBase::Type::Read) {
539  // if only have 1 successor forward value even if successor is read-only, so we can deal with move-only types
540  auto* read_successor = static_cast<In<keyT, std::add_const_t<valueT>> *>(successor);
541  if (N != 1)
542  read_successor->send(key, value);
543  else
544  read_successor->send(key, std::forward<Value>(value));
545  } else if (successor->get_type() == TerminalBase::Type::Consume) {
546  if (nullptr == move_successor) {
547  move_successor = successor;
548  } else {
549  static_cast<In<keyT, valueT> *>(successor)->send(key, value);
550  }
551  }
552  }
553  if (nullptr != move_successor) {
554  static_cast<In<keyT, valueT> *>(move_successor)->send(key, std::forward<Value>(value));
555  }
556  }
557 
558  // An optimized implementation will need a separate callback for broadcast
559  // with a specific value for rangeT
560  template <typename rangeT, typename Key = keyT, typename Value = valueT>
561  std::enable_if_t<meta::is_none_void_v<Key, Value>, void> broadcast(const rangeT &keylist,
562  const Value &value) { // NO MOVE YET
563  for (auto &&successor : this->successors()) {
564  assert(successor->get_type() != TerminalBase::Type::Write);
565  if (successor->get_type() == TerminalBase::Type::Read) {
566  static_cast<In<keyT, std::add_const_t<valueT>> *>(successor)->broadcast(keylist, value);
567  } else if (successor->get_type() == TerminalBase::Type::Consume) {
568  static_cast<In<keyT, valueT> *>(successor)->broadcast(keylist, value);
569  }
570  }
571  }
572 
573  template <typename rangeT, typename Key = keyT>
574  std::enable_if_t<meta::is_none_void_v<Key> && meta::is_void_v<valueT>, void> broadcast(const rangeT &keylist) {
575  for (auto &&successor : this->successors()) {
576  assert(successor->get_type() != TerminalBase::Type::Write);
577  if (successor->get_type() == TerminalBase::Type::Read) {
578  static_cast<In<keyT, void> *>(successor)->broadcast(keylist);
579  } else if (successor->get_type() == TerminalBase::Type::Consume) {
580  static_cast<In<keyT, void> *>(successor)->broadcast(keylist);
581  }
582  }
583  }
584 
585  template <typename rangeT, typename Key = keyT, typename Value = valueT>
586  std::enable_if_t<meta::is_none_void_v<Key> && !meta::is_void_v<valueT>, void>
587  prepare_send(const rangeT &keylist, const Value &value) {
588  for (auto &&successor : this->successors()) {
589  assert(successor->get_type() != TerminalBase::Type::Write);
590  if (successor->get_type() == TerminalBase::Type::Read) {
591  return static_cast<In<keyT, std::add_const_t<valueT>> *>(successor)->prepare_send(keylist, value);
592  } else if (successor->get_type() == TerminalBase::Type::Consume) {
593  return static_cast<In<keyT, valueT> *>(successor)->prepare_send(keylist, value);
594  }
595  }
596  }
597 
598  template <typename Key = keyT, typename Value = valueT>
599  std::enable_if_t<meta::is_void_v<Key> && !meta::is_void_v<valueT>, void>
600  prepare_send(const Value &value) {
601  for (auto &&successor : this->successors()) {
602  assert(successor->get_type() != TerminalBase::Type::Write);
603  if (successor->get_type() == TerminalBase::Type::Read) {
604  return static_cast<In<keyT, std::add_const_t<valueT>> *>(successor)->prepare_send(value);
605  } else if (successor->get_type() == TerminalBase::Type::Consume) {
606  return static_cast<In<keyT, valueT> *>(successor)->prepare_send(value);
607  }
608  }
609  }
610  };
611 
612  namespace meta {
614  template <typename T>
615  inline constexpr bool is_output_terminal_v = false;
616  template <typename keyT>
617  inline constexpr bool is_output_terminal_v<OutTerminalBase<keyT>> = true;
618  template <typename keyT, typename valueT>
619  inline constexpr bool is_output_terminal_v<Out<keyT, valueT>> = true;
620 
621  template <typename T>
622  struct is_output_terminal : std::bool_constant<is_output_terminal_v<T>> {};
623 
624  template <typename T>
625  struct is_output_terminal_tuple : std::false_type {};
626  template <typename... Ts>
627  struct is_output_terminal_tuple<std::tuple<Ts...>> : probe_all<is_output_terminal, Ts...> {};
628  template <typename... Ts>
629  inline constexpr bool is_output_terminal_tuple_v = is_output_terminal_tuple<Ts...>::value;
630 
631  template <typename T>
632  inline constexpr bool decays_to_output_terminal_tuple_v = is_output_terminal_tuple_v<std::decay_t<T>>;
633  template <typename T>
634  struct decays_to_output_terminal_tuple : std::bool_constant<decays_to_output_terminal_tuple_v<T>> {};
635 
636  template <typename T>
638  is_output_terminal_tuple_v<std::decay_t<T>> &&std::is_lvalue_reference_v<T> &&
639  !std::is_const_v<std::remove_reference_t<T>>;
640  template <typename T>
642  : std::bool_constant<is_nonconst_lvalue_reference_to_output_terminal_tuple_v<T>> {};
643  } // namespace meta
644 
645 } // namespace ttg
646 
647 #endif // TTG_TERMINALS_H
Edge is used to connect In and Out terminals.
Definition: edge.h:25
typename base_type::finalize_callback_type finalize_callback_type
Definition: terminal.h:157
typename base_type::setsize_callback_type setsize_callback_type
Definition: terminal.h:156
void set_callback(const send_callback_type &send_callback, const move_callback_type &move_callback, const broadcast_callback_type &bcast_callback=broadcast_callback_type{}, const setsize_callback_type &setsize_callback=setsize_callback_type{}, const finalize_callback_type &finalize_callback=finalize_callback_type{}, const prepare_send_callback_type &prepare_send_callback=prepare_send_callback_type{})
Definition: terminal.h:192
In()
Default constructor of an Input Terminal.
Definition: terminal.h:180
static constexpr bool is_an_input_terminal
Definition: terminal.h:159
void prepare_send(const rangeT &keylist, Value &&value)
Definition: terminal.h:319
ttg::detail::ContainerWrapper< keyT, valueT > container
Definition: terminal.h:160
valueT value_type
Definition: terminal.h:146
std::enable_if_t< meta::is_none_void_v< Key, Value >, void > send(const Key &key, Value &&value)
Definition: terminal.h:206
void send()
Definition: terminal.h:246
keyT key_type
Definition: terminal.h:147
meta::detail::send_callback_t< keyT, std::decay_t< valueT > > send_callback_type
Definition: terminal.h:153
meta::detail::broadcast_callback_t< keyT, std::decay_t< valueT > > broadcast_callback_type
Definition: terminal.h:155
meta::detail::prepare_send_callback_t< keyT, std::decay_t< valueT > > prepare_send_callback_type
Definition: terminal.h:158
std::enable_if_t<!meta::is_void_v< Key >, void > sendk(const Key &key)
Definition: terminal.h:221
std::enable_if_t<!meta::is_void_v< Value >, void > sendv(Value &&value)
Definition: terminal.h:230
std::enable_if_t< meta::is_void_v< Value >, void > broadcast(const rangeT &keylist)
Definition: terminal.h:298
std::enable_if_t<!meta::is_void_v< Value >, void > broadcast(const rangeT &keylist, const Value &value)
Definition: terminal.h:257
meta::detail::move_callback_t< keyT, std::decay_t< valueT > > move_callback_type
Definition: terminal.h:154
std::enable_if_t<!meta::is_void_v< Value >, void > broadcast(const rangeT &keylist, Value &&value)
Definition: terminal.h:277
void prepare_send(Value &&value)
Definition: terminal.h:334
Base type for input terminals receiving messages annotated by task IDs of type keyT
Definition: terminal.h:82
std::enable_if_t<!meta::is_void_v< Key >, void > finalize(const Key &key)
Definition: terminal.h:124
std::enable_if_t< meta::is_void_v< Key >, void > set_size(std::size_t size)
Definition: terminal.h:118
InTerminalBase(TerminalBase::Type t)
Definition: terminal.h:92
finalize_callback_type finalize_callback
Definition: terminal.h:95
setsize_callback_type setsize_callback
Definition: terminal.h:94
void set_callback(const setsize_callback_type &setsize_callback=setsize_callback_type{}, const finalize_callback_type &finalize_callback=finalize_callback_type{})
Definition: terminal.h:97
meta::detail::setsize_callback_t< keyT > setsize_callback_type
Definition: terminal.h:87
static constexpr bool is_an_input_terminal
Definition: terminal.h:89
meta::detail::finalize_callback_t< keyT > finalize_callback_type
Definition: terminal.h:88
std::enable_if_t<!meta::is_void_v< Key >, void > set_size(const Key &key, std::size_t size)
Definition: terminal.h:112
std::enable_if_t< meta::is_void_v< Key >, void > finalize()
Definition: terminal.h:131
static constexpr bool is_an_output_terminal
Definition: terminal.h:436
std::enable_if_t< meta::is_void_v< Key > &&!meta::is_void_v< valueT >, void > prepare_send(const Value &value)
Definition: terminal.h:600
void connect(TerminalBase *in) override
Definition: terminal.h:449
std::enable_if_t< meta::is_none_void_v< Key > &&!meta::is_void_v< valueT >, void > prepare_send(const rangeT &keylist, const Value &value)
Definition: terminal.h:587
std::enable_if_t< meta::is_none_void_v< Key, Value >, void > send(const Key &key, Value &&value)
Definition: terminal.h:532
std::enable_if_t< meta::is_void_v< Key > &&!meta::is_void_v< Value >, void > sendv(Value &&value)
Definition: terminal.h:487
std::enable_if_t< meta::is_all_void_v< Key, Value >, void > send()
Definition: terminal.h:514
std::enable_if_t< meta::is_none_void_v< Key > &&meta::is_void_v< valueT >, void > broadcast(const rangeT &keylist)
Definition: terminal.h:574
valueT value_type
Definition: terminal.h:431
typename OutTerminalBase< keyT >::key_type key_type
Definition: terminal.h:432
std::enable_if_t< meta::is_none_void_v< Key, Value >, void > broadcast(const rangeT &keylist, const Value &value)
Definition: terminal.h:561
Out()=default
std::enable_if_t<!meta::is_void_v< Key > &&meta::is_void_v< Value >, void > sendk(const Key &key)
Definition: terminal.h:475
static constexpr bool is_an_output_terminal
Definition: terminal.h:377
auto nsuccessors() const
Definition: terminal.h:389
std::enable_if_t<!meta::is_void_v< Key >, void > finalize(const Key &key)
Definition: terminal.h:409
std::enable_if_t< meta::is_void_v< Key >, void > set_size(std::size_t size)
Definition: terminal.h:401
std::enable_if_t<!meta::is_void_v< Key >, void > set_size(const Key &key, std::size_t size)
Definition: terminal.h:393
std::enable_if_t< meta::is_void_v< Key >, void > finalize()
Definition: terminal.h:417
const auto & successors() const
Definition: terminal.h:390
bool is_pull_terminal
Definition: terminal.h:15
void connect_base(TerminalBase *successor)
Definition: terminal.h:60
Type get_type() const
Returns the terminal type.
Definition: terminal.h:104
const std::string & get_name() const
Returns name of terminal.
Definition: terminal.h:86
const std::vector< TerminalBase * > & get_connections() const
Get connections to successors.
Definition: terminal.h:107
void connect_pull(TerminalBase *predecessor)
Definition: terminal.h:66
Type
describes the terminal type
Definition: terminal.h:18
@ Write
can only be written to
@ Read
can only be used to read immutable data
@ Consume
can only be used to read consumable data
A complete version of void.
Definition: void.h:11
typename input_terminals_tuple< keyT, valuesT... >::type input_terminals_tuple_t
Definition: terminal.h:354
constexpr bool is_output_terminal_v
detects whether a given type is an output terminal type
Definition: terminal.h:615
constexpr bool decays_to_output_terminal_tuple_v
Definition: terminal.h:632
constexpr bool is_input_terminal_v
detects whether a given type is an input terminal type
Definition: terminal.h:360
constexpr bool is_nonconst_lvalue_reference_to_output_terminal_tuple_v
Definition: terminal.h:637
constexpr bool is_output_terminal_tuple_v
Definition: terminal.h:629
top-level TTG namespace contains runtime-neutral functionality
Definition: keymap.h:8
int size(World world=default_execution_context())
Definition: run.h:89
int rank(World world=default_execution_context())
Definition: run.h:85
void trace(const T &t, const Ts &... ts)
Definition: trace.h:43
std::function< size_t(keyT const &key)> owner
Definition: terminal.h:27
ContainerWrapper(T &t, mapperT &&mapper, keymapT &&keymap)
Definition: terminal.h:37
ContainerWrapper & operator=(const ContainerWrapper &)=default
ContainerWrapper(const ContainerWrapper &)=default
ContainerWrapper(ContainerWrapper &&)=default
std::function< valueT(keyT const &key)> get
Definition: terminal.h:26
std::tuple< ttg::In< keyT, valuesT >... > type
Definition: terminal.h:345