transwarp
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
transwarp.h
1 /// @mainpage transwarp is a header-only C++ library for task concurrency
2 /// @details https://github.com/bloomen/transwarp
3 /// @version 1.6.0
4 /// @author Christian Blume
5 /// @date 2018
6 /// @copyright MIT http://www.opensource.org/licenses/mit-license.php
7 #pragma once
8 #include <algorithm>
9 #include <atomic>
10 #include <chrono>
11 #include <cstddef>
12 #include <functional>
13 #include <future>
14 #include <memory>
15 #include <mutex>
16 #include <queue>
17 #include <stdexcept>
18 #include <string>
19 #include <thread>
20 #include <tuple>
21 #include <type_traits>
22 #include <vector>
23 
24 
25 /// The transwarp namespace
26 namespace transwarp {
27 
28 
29 /// The possible task types
30 enum class task_type {
31  root, ///< The task has no parents
32  accept, ///< The task's functor accepts all parent futures
33  accept_any, ///< The task's functor accepts the first parent future that becomes ready
34  consume, ///< The task's functor consumes all parent results
35  consume_any, ///< The task's functor consumes the first parent result that becomes ready
36  wait, ///< The task's functor takes no arguments but waits for all parents to finish
37  wait_any, ///< The task's functor takes no arguments but waits for the first parent to finish
38 };
39 
40 
41 /// Base class for exceptions
42 class transwarp_error : public std::runtime_error {
43 public:
44  explicit transwarp_error(const std::string& message)
45  : std::runtime_error(message)
46  {}
47 };
48 
49 
50 /// Exception thrown when a task is canceled
52 public:
53  explicit task_canceled(const std::string& node_repr)
54  : transwarp::transwarp_error("Task canceled: " + node_repr)
55  {}
56 };
57 
58 
59 /// Exception thrown when a task was destroyed prematurely
61 public:
62  explicit task_destroyed(const std::string& node_repr)
63  : transwarp::transwarp_error("Task destroyed: " + node_repr)
64  {}
65 };
66 
67 
68 /// Exception thrown when an invalid parameter was passed to a function
70 public:
71  explicit invalid_parameter(const std::string& parameter)
72  : transwarp::transwarp_error("Invalid parameter: " + parameter)
73  {}
74 };
75 
76 
77 /// Exception thrown when a task is used in unintended ways
79 public:
80  explicit control_error(const std::string& message)
81  : transwarp::transwarp_error("Control error: " + message)
82  {}
83 };
84 
85 
86 /// String conversion for the task_type enumeration
87 inline std::string to_string(const transwarp::task_type& type) {
88  switch (type) {
89  case transwarp::task_type::root: return "root";
90  case transwarp::task_type::accept: return "accept";
91  case transwarp::task_type::accept_any: return "accept_any";
92  case transwarp::task_type::consume: return "consume";
93  case transwarp::task_type::consume_any: return "consume_any";
94  case transwarp::task_type::wait: return "wait";
95  case transwarp::task_type::wait_any: return "wait_any";
96  default: throw transwarp::invalid_parameter("task type");
97  }
98 }
99 
100 
101 /// The root type. Used for tag dispatch
102 struct root_type : std::integral_constant<transwarp::task_type, transwarp::task_type::root> {};
103 constexpr transwarp::root_type root{}; ///< The root task tag
104 
105 /// The accept type. Used for tag dispatch
106 struct accept_type : std::integral_constant<transwarp::task_type, transwarp::task_type::accept> {};
107 constexpr transwarp::accept_type accept{}; ///< The accept task tag
108 
109 /// The accept_any type. Used for tag dispatch
110 struct accept_any_type : std::integral_constant<transwarp::task_type, transwarp::task_type::accept_any> {};
111 constexpr transwarp::accept_any_type accept_any{}; ///< The accept_any task tag
112 
113 /// The consume type. Used for tag dispatch
114 struct consume_type : std::integral_constant<transwarp::task_type, transwarp::task_type::consume> {};
115 constexpr transwarp::consume_type consume{}; ///< The consume task tag
116 
117 /// The consume_any type. Used for tag dispatch
118 struct consume_any_type : std::integral_constant<transwarp::task_type, transwarp::task_type::consume_any> {};
119 constexpr transwarp::consume_any_type consume_any{}; ///< The consume_any task tag
120 
121 /// The wait type. Used for tag dispatch
122 struct wait_type : std::integral_constant<transwarp::task_type, transwarp::task_type::wait> {};
123 constexpr transwarp::wait_type wait{}; ///< The wait task tag
124 
125 /// The wait_any type. Used for tag dispatch
126 struct wait_any_type : std::integral_constant<transwarp::task_type, transwarp::task_type::wait_any> {};
127 constexpr transwarp::wait_any_type wait_any{}; ///< The wait_any task tag
128 
129 
130 /// Detail namespace for internal functionality only
131 namespace detail {
132 
133 struct visit_depth;
134 struct unvisit;
135 struct final_visitor;
136 struct schedule_visitor;
137 struct node_manip;
138 template<bool>
140 
141 } // detail
142 
143 
144 /// A node carrying meta-data of a task
145 class node {
146 public:
147 
148  node() = default;
149 
150  // delete copy/move semantics
151  node(const node&) = delete;
152  node& operator=(const node&) = delete;
153  node(node&&) = delete;
154  node& operator=(node&&) = delete;
155 
156  /// The task ID
157  std::size_t get_id() const noexcept {
158  return id_;
159  }
160 
161  /// The task level
162  std::size_t get_level() const noexcept {
163  return level_;
164  }
165 
166  /// The task type
167  transwarp::task_type get_type() const noexcept {
168  return type_;
169  }
170 
171  /// The optional task name (may be null)
172  const std::shared_ptr<std::string>& get_name() const noexcept {
173  return name_;
174  }
175 
176  /// The optional, task-specific executor (may be null)
177  const std::shared_ptr<std::string>& get_executor() const noexcept {
178  return executor_;
179  }
180 
181  /// The task's parents (may be empty)
182  const std::vector<std::shared_ptr<node>>& get_parents() const noexcept {
183  return parents_;
184  }
185 
186  /// The task priority (defaults to 0)
187  std::size_t get_priority() const noexcept {
188  return priority_;
189  }
190 
191  /// The custom task data (may be null)
192  const std::shared_ptr<void>& get_custom_data() const noexcept {
193  return custom_data_;
194  }
195 
196  /// Returns whether the associated task is canceled
197  bool is_canceled() const noexcept {
198  return canceled_.load();
199  }
200 
201 private:
202  friend struct transwarp::detail::node_manip;
203 
204  std::size_t id_ = 0;
205  std::size_t level_ = 0;
207  std::shared_ptr<std::string> name_;
208  std::shared_ptr<std::string> executor_;
209  std::vector<std::shared_ptr<node>> parents_;
210  std::size_t priority_ = 0;
211  std::shared_ptr<void> custom_data_;
212  std::atomic_bool canceled_{false};
213 };
214 
215 /// String conversion for the node class
216 inline std::string to_string(const transwarp::node& node, const std::string& seperator="\n") {
217  std::string s;
218  s += '"';
219  const auto& name = node.get_name();
220  if (name) {
221  s += "<" + *name + ">" + seperator;
222  }
223  s += transwarp::to_string(node.get_type());
224  s += " id=" + std::to_string(node.get_id());
225  s += " lev=" + std::to_string(node.get_level());
226  const auto& exec = node.get_executor();
227  if (exec) {
228  s += seperator + "<" + *exec + ">";
229  }
230  s += '"';
231  return s;
232 }
233 
234 
235 /// An edge between two nodes
236 class edge {
237 public:
238  // cppcheck-suppress passedByValue
239  edge(std::shared_ptr<transwarp::node> parent, std::shared_ptr<transwarp::node> child) noexcept
240  : parent_(std::move(parent)), child_(std::move(child))
241  {}
242 
243  // default copy/move semantics
244  edge(const edge&) = default;
245  edge& operator=(const edge&) = default;
246  edge(edge&&) = default;
247  edge& operator=(edge&&) = default;
248 
249  /// Returns the parent node
250  const std::shared_ptr<transwarp::node>& get_parent() const noexcept {
251  return parent_;
252  }
253 
254  /// Returns the child node
255  const std::shared_ptr<transwarp::node>& get_child() const noexcept {
256  return child_;
257  }
258 
259 private:
260  std::shared_ptr<transwarp::node> parent_;
261  std::shared_ptr<transwarp::node> child_;
262 };
263 
264 /// String conversion for the edge class
265 inline std::string to_string(const transwarp::edge& edge, const std::string& separator="\n") {
266  return transwarp::to_string(*edge.get_parent(), separator) + " -> " + transwarp::to_string(*edge.get_child(), separator);
267 }
268 
269 
270 /// Creates a dot-style string from the given graph
271 inline std::string to_string(const std::vector<transwarp::edge>& graph, const std::string& separator="\n") {
272  std::string dot = "digraph {" + separator;
273  for (const auto& edge : graph) {
274  dot += transwarp::to_string(edge, separator) + separator;
275  }
276  dot += "}";
277  return dot;
278 }
279 
280 
281 /// The executor interface used to perform custom task execution
282 class executor {
283 public:
284  virtual ~executor() = default;
285 
286  /// Is supposed to return the name of the executor
287  virtual std::string get_name() const = 0;
288 
289  /// Is supposed to run a task which is wrapped by the functor. The functor only
290  /// captures two smart pointers and can hence be copied at low cost. node represents
291  /// the task that the functor belongs to.
292  /// This function is only ever called on the thread of the caller to schedule()
293  virtual void execute(const std::function<void()>& functor, const std::shared_ptr<transwarp::node>& node) = 0;
294 };
295 
296 
297 /// The task events that can be subscribed to using the below listener interface
298 enum class event_type {
299  before_scheduled, ///< just before a task is scheduled (handle_event called on thread of caller to schedule())
300  before_started, ///< just before a task starts running (handle_event called on thread that task is run on)
301  before_invoked, ///< just before a task's functor is invoked (handle_event called on thread that task is run on)
302  after_finished, ///< just after a task has finished running (handle_event called on thread that task is run on)
303  after_canceled, ///< just after a task was canceled (handle_event called on thread that task is run on)
304  count,
305 };
306 
307 
308 /// The listener interface to listen to events raised by tasks
309 class listener {
310 public:
311  virtual ~listener() = default;
312 
313  /// This may be called from arbitrary threads depending on the event type (see transwarp::event_type)
314  virtual void handle_event(transwarp::event_type event, const std::shared_ptr<transwarp::node>& node) = 0;
315 };
316 
317 
318 /// Determines in which order tasks are scheduled in the graph
319 enum class schedule_type {
320  breadth, ///< Scheduling according to a breadth-first search (default)
321  depth, ///< Scheduling according to a depth-first search
322 };
323 
324 
325 /// An interface for the task class
326 class itask {
327 public:
328  virtual ~itask() = default;
329 
330  virtual void set_executor(std::shared_ptr<transwarp::executor> executor) = 0;
331  virtual void set_executor_all(std::shared_ptr<transwarp::executor> executor) = 0;
332  virtual void remove_executor() = 0;
333  virtual void remove_executor_all() = 0;
334  virtual void set_priority(std::size_t priority) = 0;
335  virtual void set_priority_all(std::size_t priority) = 0;
336  virtual void reset_priority() = 0;
337  virtual void reset_priority_all() = 0;
338  virtual void set_custom_data(std::shared_ptr<void> custom_data) = 0;
339  virtual void set_custom_data_all(std::shared_ptr<void> custom_data) = 0;
340  virtual void remove_custom_data() = 0;
341  virtual void remove_custom_data_all() = 0;
342  virtual const std::shared_ptr<transwarp::node>& get_node() const noexcept = 0;
343  virtual void add_listener(std::shared_ptr<transwarp::listener> listener) = 0;
344  virtual void add_listener(transwarp::event_type event, std::shared_ptr<transwarp::listener> listener) = 0;
345  virtual void remove_listener(const std::shared_ptr<transwarp::listener>& listener) = 0;
346  virtual void remove_listener(transwarp::event_type event, const std::shared_ptr<transwarp::listener>& listener) = 0;
347  virtual void remove_listeners(transwarp::event_type event) = 0;
348  virtual void remove_listeners() = 0;
349  virtual void schedule() = 0;
350  virtual void schedule(transwarp::executor& executor) = 0;
351  virtual void schedule(bool reset) = 0;
352  virtual void schedule(transwarp::executor& executor, bool reset) = 0;
353  virtual void schedule_all() = 0;
354  virtual void schedule_all(transwarp::executor& executor) = 0;
355  virtual void schedule_all(bool reset_all) = 0;
356  virtual void schedule_all(transwarp::executor& executor, bool reset_all) = 0;
357  virtual void schedule_all(transwarp::schedule_type type) = 0;
358  virtual void schedule_all(transwarp::executor& executor, transwarp::schedule_type type) = 0;
359  virtual void schedule_all(transwarp::schedule_type type, bool reset_all) = 0;
360  virtual void schedule_all(transwarp::executor& executor, transwarp::schedule_type type, bool reset_all) = 0;
361  virtual void set_exception(std::exception_ptr exception) = 0;
362  virtual bool was_scheduled() const noexcept = 0;
363  virtual void wait() const = 0;
364  virtual bool is_ready() const = 0;
365  virtual bool has_result() const = 0;
366  virtual void reset() = 0;
367  virtual void reset_all() = 0;
368  virtual void cancel(bool enabled) noexcept = 0;
369  virtual void cancel_all(bool enabled) noexcept = 0;
370  virtual std::vector<transwarp::edge> get_graph() const = 0;
371 
372 protected:
373  virtual void schedule_impl(bool reset, transwarp::executor* executor=nullptr) = 0;
374 
375 private:
376  friend struct transwarp::detail::visit_depth;
377  friend struct transwarp::detail::unvisit;
378  friend struct transwarp::detail::final_visitor;
380 
381  virtual void visit_depth(const std::function<void(itask&)>& visitor) = 0;
382  virtual void unvisit() noexcept = 0;
383  virtual void set_node_id(std::size_t id) noexcept = 0;
384 };
385 
386 
387 /// Removes reference and const from a type
388 template<typename T>
389 struct decay {
390  using type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
391 };
392 
393 
394 /// Returns the result type of a std::shared_future<T>
395 template<typename T>
396 struct result_info {
397  using type = typename std::result_of<decltype(&std::shared_future<T>::get)(std::shared_future<T>)>::type;
398 };
399 
400 
401 /// The task class (non-void result type)
402 template<typename ResultType>
403 class task : public transwarp::itask {
404 public:
405  using result_type = ResultType;
406 
407  virtual ~task() = default;
408 
409  virtual void set_value(const typename transwarp::decay<result_type>::type& value) = 0;
410  virtual void set_value(typename transwarp::decay<result_type>::type&& value) = 0;
411  virtual const std::shared_future<result_type>& get_future() const noexcept = 0;
412  virtual typename transwarp::result_info<result_type>::type get() const = 0;
413 };
414 
415 /// The task class (non-void, non-const reference result type)
416 template<typename ResultType>
417 class task<ResultType&> : public transwarp::itask {
418 public:
419  using result_type = ResultType&;
420 
421  virtual ~task() = default;
422 
423  virtual void set_value(typename transwarp::decay<result_type>::type& value) = 0;
424  virtual const std::shared_future<result_type>& get_future() const noexcept = 0;
425  virtual typename transwarp::result_info<result_type>::type get() const = 0;
426 };
427 
428 /// The task class (void result type)
429 template<>
430 class task<void> : public transwarp::itask {
431 public:
432  using result_type = void;
433 
434  virtual ~task() = default;
435 
436  virtual void set_value() = 0;
437  virtual const std::shared_future<result_type>& get_future() const noexcept = 0;
438  virtual result_type get() const = 0;
439 };
440 
441 
442 /// A base class for a user-defined functor that needs access to the node associated
443 /// to the task or a cancel point to stop a task while it's running
444 class functor {
445 public:
446 
447  virtual ~functor() = default;
448 
449 protected:
450 
451  /// The node associated to the task
452  const std::shared_ptr<transwarp::node>& transwarp_node() const noexcept {
453  return transwarp_node_;
454  }
455 
456  /// If the associated task is canceled then this will throw transwarp::task_canceled
457  /// which will stop the task while it's running
458  void transwarp_cancel_point() const {
459  if (transwarp_node_->is_canceled()) {
460  throw transwarp::task_canceled(std::to_string(transwarp_node_->get_id()));
461  }
462  }
463 
464 private:
465  template<bool>
467 
468  std::shared_ptr<transwarp::node> transwarp_node_;
469 };
470 
471 
472 /// Detail namespace for internal functionality only
473 namespace detail {
474 
475 
476 /// Node manipulation
477 struct node_manip {
478 
479  static void set_id(transwarp::node& node, std::size_t id) noexcept {
480  node.id_ = id;
481  }
482 
483  static void set_level(transwarp::node& node, std::size_t level) noexcept {
484  node.level_ = level;
485  }
486 
487  static void set_type(transwarp::node& node, transwarp::task_type type) noexcept {
488  node.type_ = type;
489  }
490 
491  static void set_name(transwarp::node& node, std::shared_ptr<std::string> name) noexcept {
492  node.name_ = name;
493  }
494 
495  static void set_executor(transwarp::node& node, std::shared_ptr<std::string> executor) noexcept {
496  if (executor) {
497  node.executor_ = std::move(executor);
498  } else {
499  node.executor_.reset();
500  }
501  }
502 
503  static void add_parent(transwarp::node& node, std::shared_ptr<transwarp::node> parent) {
504  node.parents_.push_back(std::move(parent));
505  }
506 
507  static void set_priority(transwarp::node& node, std::size_t priority) noexcept {
508  node.priority_ = priority;
509  }
510 
511  static void set_custom_data(transwarp::node& node, std::shared_ptr<void> custom_data) {
512  if (custom_data) {
513  node.custom_data_ = std::move(custom_data);
514  } else {
515  node.custom_data_.reset();
516  }
517  }
518 
519  static void set_canceled(transwarp::node& node, bool enabled) noexcept {
520  node.canceled_ = enabled;
521  }
522 
523 };
524 
525 
526 /// A simple thread pool used to execute tasks in parallel
527 class thread_pool {
528 public:
529 
530  explicit thread_pool(std::size_t n_threads)
531  : done_(false)
532  {
533  if (n_threads == 0) {
534  throw transwarp::invalid_parameter("number of threads");
535  }
536  const auto n_target = threads_.size() + n_threads;
537  while (threads_.size() < n_target) {
538  std::thread thread;
539  try {
540  thread = std::thread(&thread_pool::worker, this);
541  } catch (...) {
542  shutdown();
543  throw;
544  }
545  try {
546  threads_.push_back(std::move(thread));
547  } catch (...) {
548  shutdown();
549  thread.join();
550  throw;
551  }
552  }
553  }
554 
555  // delete copy/move semantics
556  thread_pool(const thread_pool&) = delete;
557  thread_pool& operator=(const thread_pool&) = delete;
558  thread_pool(thread_pool&&) = delete;
559  thread_pool& operator=(thread_pool&&) = delete;
560 
561  ~thread_pool() {
562  shutdown();
563  }
564 
565  void push(const std::function<void()>& functor) {
566  {
567  std::lock_guard<std::mutex> lock(mutex_);
568  functors_.push(functor);
569  }
570  cond_var_.notify_one();
571  }
572 
573 private:
574 
575  void worker() {
576  for (;;) {
577  std::function<void()> functor;
578  {
579  std::unique_lock<std::mutex> lock(mutex_);
580  cond_var_.wait(lock, [this]{
581  return done_ || !functors_.empty();
582  });
583  if (done_ && functors_.empty()) {
584  break;
585  }
586  functor = functors_.front();
587  functors_.pop();
588  }
589  functor();
590  }
591  }
592 
593  void shutdown() {
594  {
595  std::lock_guard<std::mutex> lock(mutex_);
596  done_ = true;
597  }
598  cond_var_.notify_all();
599  for (auto& thread : threads_) {
600  thread.join();
601  }
602  threads_.clear();
603  }
604 
605  bool done_;
606  std::vector<std::thread> threads_;
607  std::queue<std::function<void()>> functors_;
608  std::condition_variable cond_var_;
609  std::mutex mutex_;
610 };
611 
612 
613 template<int offset, typename... ParentResults>
615  static void work(const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& source, std::tuple<std::shared_future<ParentResults>...>& target) {
616  std::get<offset>(target) = std::get<offset>(source)->get_future();
618  }
619 };
620 
621 template<typename... ParentResults>
622 struct assign_futures_impl<-1, ParentResults...> {
623  static void work(const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>&, std::tuple<std::shared_future<ParentResults>...>&) {}
624 };
625 
626 /// Returns the futures from the given tuple of tasks
627 template<typename... ParentResults>
628 std::tuple<std::shared_future<ParentResults>...> get_futures(const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& input) {
629  std::tuple<std::shared_future<ParentResults>...> result;
630  assign_futures_impl<static_cast<int>(sizeof...(ParentResults)) - 1, ParentResults...>::work(input, result);
631  return result;
632 }
633 
634 /// Returns the futures from the given vector of tasks
635 template<typename ParentResultType>
636 std::vector<std::shared_future<ParentResultType>> get_futures(const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& input) {
637  std::vector<std::shared_future<ParentResultType>> result;
638  result.reserve(input.size());
639  for (const auto& task : input) {
640  result.emplace_back(task->get_future());
641  }
642  return result;
643 }
644 
645 
646 /// Runs the task with the given arguments, hence, invoking the task's functor
647 template<typename Result, typename Task, typename... Args>
648 Result run_task(std::size_t node_id, const Task& task, Args&&... args) {
649  auto t = task.lock();
650  if (!t) {
651  throw transwarp::task_destroyed(std::to_string(node_id));
652  }
653  if (t->node_->is_canceled()) {
654  throw transwarp::task_canceled(std::to_string(node_id));
655  }
657  return t->functor_(std::forward<Args>(args)...);
658 }
659 
660 
661 inline void wait_for_all() {}
662 
663 /// Waits for all parents to finish
664 template<typename ParentResult, typename... ParentResults>
665 void wait_for_all(const std::shared_ptr<transwarp::task<ParentResult>>& parent, const std::shared_ptr<transwarp::task<ParentResults>>& ...parents) {
666  parent->get_future().wait();
668 }
669 
670 
671 /// Waits for all parents to finish
672 template<typename ParentResultType>
673 void wait_for_all(const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
674  for (const auto& parent : parents) {
675  parent->get_future().wait();
676  }
677 }
678 
679 
680 template<typename Parent>
681 Parent wait_for_any_impl() {
682  return {};
683 }
684 
685 template<typename Parent, typename ParentResult, typename... ParentResults>
686 Parent wait_for_any_impl(const std::shared_ptr<transwarp::task<ParentResult>>& parent, const std::shared_ptr<transwarp::task<ParentResults>>& ...parents) {
687  const auto status = parent->get_future().wait_for(std::chrono::microseconds(1));
688  if (status == std::future_status::ready) {
689  return parent;
690  }
691  return transwarp::detail::wait_for_any_impl<Parent>(parents...);
692 }
693 
694 /// Waits for the first parent to finish
695 template<typename Parent, typename... ParentResults>
696 Parent wait_for_any(const std::shared_ptr<transwarp::task<ParentResults>>& ...parents) {
697  for (;;) {
698  auto parent = transwarp::detail::wait_for_any_impl<Parent>(parents...);
699  if (parent) {
700  return parent;
701  }
702  }
703 }
704 
705 
706 /// Waits for the first parent to finish
707 template<typename ParentResultType>
708 std::shared_ptr<transwarp::task<ParentResultType>> wait_for_any(const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
709  for (;;) {
710  for (const auto& parent : parents) {
711  const auto status = parent->get_future().wait_for(std::chrono::microseconds(1));
712  if (status == std::future_status::ready) {
713  return parent;
714  }
715  }
716  }
717 }
718 
719 
720 template<typename OneResult>
721 void cancel_all_but_one(const std::shared_ptr<transwarp::task<OneResult>>&) {}
722 
723 /// Cancels all tasks but one
724 template<typename OneResult, typename ParentResult, typename... ParentResults>
725 void cancel_all_but_one(const std::shared_ptr<transwarp::task<OneResult>>& one, const std::shared_ptr<transwarp::task<ParentResult>>& parent, const std::shared_ptr<transwarp::task<ParentResults>>& ...parents) {
726  if (one != parent) {
727  parent->cancel(true);
728  }
730 }
731 
732 
733 /// Cancels all tasks but one
734 template<typename OneResult, typename ParentResultType>
735 void cancel_all_but_one(const std::shared_ptr<transwarp::task<OneResult>>& one, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
736  for (const auto& parent : parents) {
737  if (one != parent) {
738  parent->cancel(true);
739  }
740  }
741 }
742 
743 
744 template<typename TaskType, bool done, int total, int... n>
745 struct call_impl {
746  template<typename Result, typename Task, typename... ParentResults>
747  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
748  return call_impl<TaskType, total == 1 + static_cast<int>(sizeof...(n)), total, n..., static_cast<int>(sizeof...(n))>::template
749  work<Result>(node_id, task, parents);
750  }
751 };
752 
753 template<typename TaskType>
755 
756 template<int total, int... n>
757 struct call_impl<transwarp::root_type, true, total, n...> {
758  template<typename Result, typename Task, typename... ParentResults>
759  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>&) {
760  return transwarp::detail::run_task<Result>(node_id, task);
761  }
762 };
763 
764 template<>
765 struct call_impl_vector<transwarp::root_type> {
766  template<typename Result, typename Task, typename ParentResultType>
767  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>&) {
768  return transwarp::detail::run_task<Result>(node_id, task);
769  }
770 };
771 
772 template<int total, int... n>
773 struct call_impl<transwarp::accept_type, true, total, n...> {
774  template<typename Result, typename Task, typename... ParentResults>
775  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
776  transwarp::detail::wait_for_all(std::get<n>(parents)...);
777  const auto futures = transwarp::detail::get_futures(parents);
778  return transwarp::detail::run_task<Result>(node_id, task, std::get<n>(futures)...);
779  }
780 };
781 
782 template<>
783 struct call_impl_vector<transwarp::accept_type> {
784  template<typename Result, typename Task, typename ParentResultType>
785  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
787  return transwarp::detail::run_task<Result>(node_id, task, transwarp::detail::get_futures(parents));
788  }
789 };
790 
791 template<int total, int... n>
792 struct call_impl<transwarp::accept_any_type, true, total, n...> {
793  template<typename Result, typename Task, typename... ParentResults>
794  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
795  using parent_t = typename std::remove_reference<decltype(std::get<0>(parents))>::type; // use first type as reference
796  auto parent = transwarp::detail::wait_for_any<parent_t>(std::get<n>(parents)...);
797  transwarp::detail::cancel_all_but_one(parent, std::get<n>(parents)...);
798  return transwarp::detail::run_task<Result>(node_id, task, parent->get_future());
799  }
800 };
801 
802 template<>
803 struct call_impl_vector<transwarp::accept_any_type> {
804  template<typename Result, typename Task, typename ParentResultType>
805  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
808  return transwarp::detail::run_task<Result>(node_id, task, parent->get_future());
809  }
810 };
811 
812 template<int total, int... n>
813 struct call_impl<transwarp::consume_type, true, total, n...> {
814  template<typename Result, typename Task, typename... ParentResults>
815  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
816  transwarp::detail::wait_for_all(std::get<n>(parents)...);
817  return transwarp::detail::run_task<Result>(node_id, task, std::get<n>(parents)->get_future().get()...);
818  }
819 };
820 
821 template<>
822 struct call_impl_vector<transwarp::consume_type> {
823  template<typename Result, typename Task, typename ParentResultType>
824  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
826  std::vector<ParentResultType> results;
827  results.reserve(parents.size());
828  for (const auto& parent : parents) {
829  results.emplace_back(parent->get_future().get());
830  }
831  return transwarp::detail::run_task<Result>(node_id, task, std::move(results));
832  }
833 };
834 
835 template<int total, int... n>
836 struct call_impl<transwarp::consume_any_type, true, total, n...> {
837  template<typename Result, typename Task, typename... ParentResults>
838  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
839  using parent_t = typename std::remove_reference<decltype(std::get<0>(parents))>::type; /// use first type as reference
840  auto parent = transwarp::detail::wait_for_any<parent_t>(std::get<n>(parents)...);
841  transwarp::detail::cancel_all_but_one(parent, std::get<n>(parents)...);
842  return transwarp::detail::run_task<Result>(node_id, task, parent->get_future().get());
843  }
844 };
845 
846 template<>
847 struct call_impl_vector<transwarp::consume_any_type> {
848  template<typename Result, typename Task, typename ParentResultType>
849  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
852  return transwarp::detail::run_task<Result>(node_id, task, parent->get_future().get());
853  }
854 };
855 
856 template<int total, int... n>
857 struct call_impl<transwarp::wait_type, true, total, n...> {
858  template<typename Result, typename Task, typename... ParentResults>
859  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
860  transwarp::detail::wait_for_all(std::get<n>(parents)...);
861  get_all(std::get<n>(parents)...); // ensures that exceptions are propagated
862  return transwarp::detail::run_task<Result>(node_id, task);
863  }
864  template<typename T, typename... Args>
865  static void get_all(const T& arg, const Args& ...args) {
866  arg->get_future().get();
867  get_all(args...);
868  }
869  static void get_all() {}
870 };
871 
872 template<>
873 struct call_impl_vector<transwarp::wait_type> {
874  template<typename Result, typename Task, typename ParentResultType>
875  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
877  for (const auto& parent : parents) {
878  parent->get_future().get(); // ensures that exceptions are propagated
879  }
880  return transwarp::detail::run_task<Result>(node_id, task);
881  }
882 };
883 
884 template<int total, int... n>
885 struct call_impl<transwarp::wait_any_type, true, total, n...> {
886  template<typename Result, typename Task, typename... ParentResults>
887  static Result work(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
888  using parent_t = typename std::remove_reference<decltype(std::get<0>(parents))>::type; // use first type as reference
889  auto parent = transwarp::detail::wait_for_any<parent_t>(std::get<n>(parents)...);
890  transwarp::detail::cancel_all_but_one(parent, std::get<n>(parents)...);
891  parent->get_future().get(); // ensures that exceptions are propagated
892  return transwarp::detail::run_task<Result>(node_id, task);
893  }
894 };
895 
896 template<>
897 struct call_impl_vector<transwarp::wait_any_type> {
898  template<typename Result, typename Task, typename ParentResultType>
899  static Result work(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
902  parent->get_future().get(); // ensures that exceptions are propagated
903  return transwarp::detail::run_task<Result>(node_id, task);
904  }
905 };
906 
907 /// Calls the functor of the given task with the results from the tuple of parents.
908 /// Throws transwarp::task_canceled if the task is canceled.
909 /// Throws transwarp::task_destroyed in case the task was destroyed prematurely.
910 template<typename TaskType, typename Result, typename Task, typename... ParentResults>
911 Result call(std::size_t node_id, const Task& task, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& parents) {
912  constexpr std::size_t n = std::tuple_size<std::tuple<std::shared_future<ParentResults>...>>::value;
914  work<Result>(node_id, task, parents);
915 }
916 
917 /// Calls the functor of the given task with the results from the vector of parents.
918 /// Throws transwarp::task_canceled if the task is canceled.
919 /// Throws transwarp::task_destroyed in case the task was destroyed prematurely.
920 template<typename TaskType, typename Result, typename Task, typename ParentResultType>
921 Result call(std::size_t node_id, const Task& task, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& parents) {
923  work<Result>(node_id, task, parents);
924 }
925 
926 template<std::size_t...> struct indices {};
927 
928 template<std::size_t...> struct construct_range;
929 
930 template<std::size_t end, std::size_t idx, std::size_t... i>
931 struct construct_range<end, idx, i...> : construct_range<end, idx + 1, i..., idx> {};
932 
933 template<std::size_t end, std::size_t... i>
934 struct construct_range<end, end, i...> {
935  using type = transwarp::detail::indices<i...>;
936 };
937 
938 template<std::size_t b, std::size_t e>
939 struct index_range {
941 };
942 
943 template<typename Functor, typename... ParentResults>
944 void call_with_each_index(transwarp::detail::indices<>, const Functor&, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>&) {}
945 
946 template<std::size_t i, std::size_t... j, typename Functor, typename... ParentResults>
947 void call_with_each_index(transwarp::detail::indices<i, j...>, const Functor& f, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& t) {
948  auto ptr = std::get<i>(t);
949  if (!ptr) {
950  throw transwarp::invalid_parameter("task pointer");
951  }
952  f(*ptr);
953  transwarp::detail::call_with_each_index(transwarp::detail::indices<j...>(), f, t);
954 }
955 
956 /// Calls the functor with every element in the tuple
957 template<typename Functor, typename... ParentResults>
958 void call_with_each(const Functor& f, const std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>& t) {
959  constexpr std::size_t n = std::tuple_size<std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>>::value;
960  using index_t = typename transwarp::detail::index_range<0, n>::type;
961  transwarp::detail::call_with_each_index(index_t(), f, t);
962 }
963 
964 /// Calls the functor with every element in the vector
965 template<typename Functor, typename ParentResultType>
966 void call_with_each(const Functor& f, const std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>& v) {
967  for (const auto& ptr : v) {
968  if (!ptr) {
969  throw transwarp::invalid_parameter("task pointer");
970  }
971  f(*ptr);
972  }
973 }
974 
975 
976 /// Sets parents and level of the node
978  explicit parent_visitor(std::shared_ptr<transwarp::node>& node) noexcept
979  : node_(node) {}
980 
981  void operator()(const transwarp::itask& task) const {
982  transwarp::detail::node_manip::add_parent(*node_, task.get_node());
983  if (node_->get_level() <= task.get_node()->get_level()) {
984  /// A child's level is always larger than any of its parents' levels
985  transwarp::detail::node_manip::set_level(*node_, task.get_node()->get_level() + 1);
986  }
987  }
988 
989  std::shared_ptr<transwarp::node>& node_;
990 };
991 
992 /// Applies final bookkeeping to the task
994  final_visitor() noexcept
995  : id_(0) {}
996 
997  void operator()(transwarp::itask& task) noexcept {
998  task.set_node_id(id_++);
999  }
1000 
1001  std::size_t id_;
1002 };
1003 
1004 /// Generates a graph
1006  explicit graph_visitor(std::vector<transwarp::edge>& graph) noexcept
1007  : graph_(graph) {}
1008 
1009  void operator()(const transwarp::itask& task) {
1010  const auto& node = task.get_node();
1011  for (const auto& parent : node->get_parents()) {
1012  graph_.emplace_back(parent, node);
1013  }
1014  }
1015 
1016  std::vector<transwarp::edge>& graph_;
1017 };
1018 
1019 /// Schedules using the given executor
1021  schedule_visitor(bool reset, transwarp::executor* executor) noexcept
1022  : reset_(reset), executor_(executor) {}
1023 
1024  void operator()(transwarp::itask& task) {
1025  task.schedule_impl(reset_, executor_);
1026  }
1027 
1028  bool reset_;
1029  transwarp::executor* executor_;
1030 };
1031 
1032 /// Resets the given task
1034 
1035  template<typename Task>
1036  void operator()(Task& task) const {
1037  task.reset();
1038  }
1039 };
1040 
1041 /// Cancels or resumes the given task
1043  explicit cancel_visitor(bool enabled) noexcept
1044  : enabled_(enabled) {}
1045 
1046  void operator()(transwarp::itask& task) const noexcept {
1047  task.cancel(enabled_);
1048  }
1049 
1050  bool enabled_;
1051 };
1052 
1053 /// Assigns an executor to the given task
1055  explicit set_executor_visitor(std::shared_ptr<transwarp::executor> executor) noexcept
1056  : executor_(std::move(executor)) {}
1057 
1058  void operator()(transwarp::itask& task) const noexcept {
1059  task.set_executor(executor_);
1060  }
1061 
1062  std::shared_ptr<transwarp::executor> executor_;
1063 };
1064 
1065 /// Removes the executor from the given task
1067 
1068  void operator()(transwarp::itask& task) const noexcept {
1069  task.remove_executor();
1070  }
1071 };
1072 
1073 /// Assigns a priority to the given task
1075  explicit set_priority_visitor(std::size_t priority) noexcept
1076  : priority_(priority) {}
1077 
1078  void operator()(transwarp::itask& task) const noexcept {
1079  task.set_priority(priority_);
1080  }
1081 
1082  std::size_t priority_;
1083 };
1084 
1085 /// Resets the priority of the given task
1087 
1088  void operator()(transwarp::itask& task) const noexcept {
1089  task.reset_priority();
1090  }
1091 };
1092 
1093 /// Assigns custom data to the given task
1095  explicit set_custom_data_visitor(std::shared_ptr<void> custom_data) noexcept
1096  : custom_data_(std::move(custom_data)) {}
1097 
1098  void operator()(transwarp::itask& task) const noexcept {
1099  task.set_custom_data(custom_data_);
1100  }
1101 
1102  std::shared_ptr<void> custom_data_;
1103 };
1104 
1105 /// Removes custom data from the given task
1107 
1108  void operator()(transwarp::itask& task) const noexcept {
1109  task.remove_custom_data();
1110  }
1111 };
1112 
1113 /// Pushes the given task into the vector of tasks
1115  explicit push_task_visitor(std::vector<transwarp::itask*>& tasks)
1116  : tasks_(tasks) {}
1117 
1118  void operator()(transwarp::itask& task) {
1119  tasks_.push_back(&task);
1120  }
1121 
1122  std::vector<transwarp::itask*>& tasks_;
1123 };
1124 
1125 /// Visits the given task using the visitor given in the constructor
1126 struct visit_depth {
1127  explicit visit_depth(const std::function<void(transwarp::itask&)>& visitor) noexcept
1128  : visitor_(visitor) {}
1129 
1130  void operator()(transwarp::itask& task) const {
1131  task.visit_depth(visitor_);
1132  }
1133 
1134  const std::function<void(transwarp::itask&)>& visitor_;
1135 };
1136 
1137 /// Unvisits the given task
1138 struct unvisit {
1139 
1140  void operator()(transwarp::itask& task) const noexcept {
1141  task.unvisit();
1142  }
1143 };
1144 
1145 /// Determines the result type of the Functor dispatching on the task type
1146 template<typename TaskType, typename Functor, typename... ParentResults>
1147 struct result {
1148  static_assert(std::is_same<TaskType, transwarp::root_type>::value ||
1149  std::is_same<TaskType, transwarp::accept_type>::value ||
1150  std::is_same<TaskType, transwarp::accept_any_type>::value ||
1151  std::is_same<TaskType, transwarp::consume_type>::value ||
1152  std::is_same<TaskType, transwarp::consume_any_type>::value ||
1153  std::is_same<TaskType, transwarp::wait_type>::value ||
1154  std::is_same<TaskType, transwarp::wait_any_type>::value,
1155  "Invalid task type, must be one of: root, accept, accept_any, consume, consume_any, wait, wait_any");
1156 };
1157 
1158 template<typename Functor, typename... ParentResults>
1159 struct result<transwarp::root_type, Functor, ParentResults...> {
1160  static_assert(sizeof...(ParentResults) == 0, "A root task cannot have parent tasks");
1161  using type = decltype(std::declval<Functor>()());
1162 };
1163 
1164 template<typename Functor, typename... ParentResults>
1165 struct result<transwarp::accept_type, Functor, ParentResults...> {
1166  static_assert(sizeof...(ParentResults) > 0, "An accept task must have at least one parent");
1167  using type = decltype(std::declval<Functor>()(std::declval<std::shared_future<ParentResults>>()...));
1168 };
1169 
1170 template<typename Functor, typename ParentResultType>
1171 struct result<transwarp::accept_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1172  using type = decltype(std::declval<Functor>()(std::declval<std::vector<std::shared_future<ParentResultType>>>()));
1173 };
1174 
1175 template<typename Functor, typename... ParentResults>
1176 struct result<transwarp::accept_any_type, Functor, ParentResults...> {
1177  static_assert(sizeof...(ParentResults) > 0, "An accept_any task must have at least one parent");
1178  using arg_t = typename std::tuple_element<0, std::tuple<ParentResults...>>::type; /// using first type as reference
1179  using type = decltype(std::declval<Functor>()(std::declval<std::shared_future<arg_t>>()));
1180 };
1181 
1182 template<typename Functor, typename ParentResultType>
1183 struct result<transwarp::accept_any_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1184  using type = decltype(std::declval<Functor>()(std::declval<std::shared_future<ParentResultType>>()));
1185 };
1186 
1187 template<typename Functor, typename... ParentResults>
1188 struct result<transwarp::consume_type, Functor, ParentResults...> {
1189  static_assert(sizeof...(ParentResults) > 0, "A consume task must have at least one parent");
1190  using type = decltype(std::declval<Functor>()(std::declval<ParentResults>()...));
1191 };
1192 
1193 template<typename Functor, typename ParentResultType>
1194 struct result<transwarp::consume_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1195  using type = decltype(std::declval<Functor>()(std::declval<std::vector<ParentResultType>>()));
1196 };
1197 
1198 template<typename Functor, typename... ParentResults>
1199 struct result<transwarp::consume_any_type, Functor, ParentResults...> {
1200  static_assert(sizeof...(ParentResults) > 0, "A consume_any task must have at least one parent");
1201  using arg_t = typename std::tuple_element<0, std::tuple<ParentResults...>>::type; /// using first type as reference
1202  using type = decltype(std::declval<Functor>()(std::declval<arg_t>()));
1203 };
1204 
1205 template<typename Functor, typename ParentResultType>
1206 struct result<transwarp::consume_any_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1207  using type = decltype(std::declval<Functor>()(std::declval<ParentResultType>()));
1208 };
1209 
1210 template<typename Functor, typename... ParentResults>
1211 struct result<transwarp::wait_type, Functor, ParentResults...> {
1212  static_assert(sizeof...(ParentResults) > 0, "A wait task must have at least one parent");
1213  using type = decltype(std::declval<Functor>()());
1214 };
1215 
1216 template<typename Functor, typename ParentResultType>
1217 struct result<transwarp::wait_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1218  using type = decltype(std::declval<Functor>()());
1219 };
1220 
1221 template<typename Functor, typename... ParentResults>
1222 struct result<transwarp::wait_any_type, Functor, ParentResults...> {
1223  static_assert(sizeof...(ParentResults) > 0, "A wait_any task must have at least one parent");
1224  using type = decltype(std::declval<Functor>()());
1225 };
1226 
1227 template<typename Functor, typename ParentResultType>
1228 struct result<transwarp::wait_any_type, Functor, std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1229  using type = decltype(std::declval<Functor>()());
1230 };
1231 
1232 template<bool is_transwarp_functor>
1233 struct assign_node_if_impl;
1234 
1235 template<>
1236 struct assign_node_if_impl<true> {
1237  template<typename Functor>
1238  void operator()(Functor& functor, std::shared_ptr<transwarp::node> node) const noexcept {
1239  functor.transwarp_node_ = std::move(node);
1240  }
1241 };
1242 
1243 template<>
1244 struct assign_node_if_impl<false> {
1245  template<typename Functor>
1246  void operator()(Functor&, std::shared_ptr<transwarp::node>) const noexcept {}
1247 };
1248 
1249 /// Assigns the node to the given functor if the functor is a subclass of transwarp::functor
1250 template<typename Functor>
1251 void assign_node_if(Functor& functor, std::shared_ptr<transwarp::node> node) noexcept {
1253 }
1254 
1255 /// Returns a ready future with the given value as its state
1256 template<typename ResultType, typename Value>
1257 std::shared_future<ResultType> make_future_with_value(Value&& value) {
1258  std::promise<ResultType> promise;
1259  promise.set_value(std::forward<Value>(value));
1260  return promise.get_future();
1261 }
1262 
1263 /// Returns a ready future
1264 inline std::shared_future<void> make_ready_future() {
1265  std::promise<void> promise;
1266  promise.set_value();
1267  return promise.get_future();
1268 }
1269 
1270 /// Returns a ready future with the given exception as its state
1271 template<typename ResultType>
1272 std::shared_future<ResultType> make_future_with_exception(std::exception_ptr exception) {
1273  if (!exception) {
1274  throw transwarp::invalid_parameter("exception pointer");
1275  }
1276  std::promise<ResultType> promise;
1277  promise.set_exception(exception);
1278  return promise.get_future();
1279 }
1280 
1281 
1282 /// Determines the type of the parents
1283 template<typename... ParentResults>
1284 struct parents {
1285  using type = std::tuple<std::shared_ptr<transwarp::task<ParentResults>>...>;
1286 };
1287 
1288 /// Determines the type of the parents. Specialization for vector parents
1289 template<typename ParentResultType>
1290 struct parents<std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>> {
1291  using type = std::vector<std::shared_ptr<transwarp::task<ParentResultType>>>;
1292 };
1293 
1294 
1295 /// A callable to run a task given its parents
1296 template<typename TaskType, typename ResultType, typename Task, typename Parents>
1297 struct runner {
1298 
1299  const std::size_t node_id;
1300  const typename transwarp::decay<Task>::type task;
1301  const typename transwarp::decay<Parents>::type parents;
1302 
1303  ResultType operator()() {
1304  try {
1305  return transwarp::detail::call<TaskType, ResultType>(node_id, task, parents);
1306  } catch (const transwarp::task_canceled&) {
1307  if (const auto t = task.lock()) {
1308  t->raise_event(transwarp::event_type::after_canceled);
1309  }
1310  throw;
1311  }
1312  }
1313 };
1314 
1315 
1316 } // detail
1317 
1318 
1319 /// Executor for sequential execution. Runs functors sequentially on the same thread
1321 public:
1322 
1323  sequential() = default;
1324 
1325  // delete copy/move semantics
1326  sequential(const sequential&) = delete;
1327  sequential& operator=(const sequential&) = delete;
1328  sequential(sequential&&) = delete;
1329  sequential& operator=(sequential&&) = delete;
1330 
1331  /// Returns the name of the executor
1332  std::string get_name() const override {
1333  return "transwarp::sequential";
1334  }
1335 
1336  /// Runs the functor on the current thread
1337  void execute(const std::function<void()>& functor, const std::shared_ptr<transwarp::node>&) override {
1338  functor();
1339  }
1340 };
1341 
1342 
1343 /// Executor for parallel execution. Uses a simple thread pool
1345 public:
1346 
1347  explicit parallel(std::size_t n_threads)
1348  : pool_(n_threads)
1349  {}
1350 
1351  // delete copy/move semantics
1352  parallel(const parallel&) = delete;
1353  parallel& operator=(const parallel&) = delete;
1354  parallel(parallel&&) = delete;
1355  parallel& operator=(parallel&&) = delete;
1356 
1357  /// Returns the name of the executor
1358  std::string get_name() const override {
1359  return "transwarp::parallel";
1360  }
1361 
1362  /// Pushes the functor into the thread pool for asynchronous execution
1363  void execute(const std::function<void()>& functor, const std::shared_ptr<transwarp::node>&) override {
1364  pool_.push(functor);
1365  }
1366 
1367 private:
1369 };
1370 
1371 
1372 /// Detail namespace for internal functionality only
1373 namespace detail {
1374 
1375 /// The base task class that contains the functionality that can be used
1376 /// with all result types (void and non-void).
1377 template<typename ResultType, typename TaskType, typename Functor, typename... ParentResults>
1378 class task_impl_base : public transwarp::task<ResultType>,
1379  public std::enable_shared_from_this<task_impl_base<ResultType, TaskType, Functor, ParentResults...>> {
1380 public:
1381  /// The task type
1382  using task_type = TaskType;
1383 
1384  /// The result type of this task
1385  using result_type = ResultType;
1386 
1387  /// Assigns an executor to this task which takes precedence over
1388  /// the executor provided in schedule() or schedule_all()
1389  void set_executor(std::shared_ptr<transwarp::executor> executor) override {
1391  if (!executor) {
1392  throw transwarp::invalid_parameter("executor pointer");
1393  }
1394  executor_ = std::move(executor);
1395  transwarp::detail::node_manip::set_executor(*node_, std::make_shared<std::string>(executor_->get_name()));
1396  }
1397 
1398  /// Assigns an executor to all tasks which takes precedence over
1399  /// the executor provided in schedule() or schedule_all()
1400  void set_executor_all(std::shared_ptr<transwarp::executor> executor) override {
1402  transwarp::detail::set_executor_visitor visitor(std::move(executor));
1403  visit_depth_all(visitor);
1404  }
1405 
1406  /// Removes the executor from this task
1407  void remove_executor() override {
1409  executor_.reset();
1410  transwarp::detail::node_manip::set_executor(*node_, nullptr);
1411  }
1412 
1413  /// Removes the executor from all tasks
1414  void remove_executor_all() override {
1417  visit_depth_all(visitor);
1418  }
1419 
1420  /// Sets a task priority (defaults to 0). transwarp will not directly use this.
1421  /// This is only useful if something else is using the priority (e.g. a custom executor)
1422  void set_priority(std::size_t priority) override {
1424  transwarp::detail::node_manip::set_priority(*node_, priority);
1425  }
1426 
1427  /// Sets a priority to all tasks (defaults to 0). transwarp will not directly use this.
1428  /// This is only useful if something else is using the priority (e.g. a custom executor)
1429  void set_priority_all(std::size_t priority) override {
1431  transwarp::detail::set_priority_visitor visitor(priority);
1432  visit_depth_all(visitor);
1433  }
1434 
1435  /// Resets the task priority to 0
1436  void reset_priority() override {
1438  transwarp::detail::node_manip::set_priority(*node_, 0);
1439  }
1440 
1441  /// Resets the priority of all tasks to 0
1442  void reset_priority_all() override {
1445  visit_depth_all(visitor);
1446  }
1447 
1448  /// Assigns custom data to this task. transwarp will not directly use this.
1449  /// This is only useful if something else is using this custom data (e.g. a custom executor)
1450  void set_custom_data(std::shared_ptr<void> custom_data) override {
1452  if (!custom_data) {
1453  throw transwarp::invalid_parameter("custom data pointer");
1454  }
1455  transwarp::detail::node_manip::set_custom_data(*node_, std::move(custom_data));
1456  }
1457 
1458  /// Assigns custom data to all tasks. transwarp will not directly use this.
1459  /// This is only useful if something else is using this custom data (e.g. a custom executor)
1460  void set_custom_data_all(std::shared_ptr<void> custom_data) override {
1462  transwarp::detail::set_custom_data_visitor visitor(std::move(custom_data));
1463  visit_depth_all(visitor);
1464  }
1465 
1466  /// Removes custom data from this task
1467  void remove_custom_data() override {
1469  transwarp::detail::node_manip::set_custom_data(*node_, nullptr);
1470  }
1471 
1472  /// Removes custom data from all tasks
1473  void remove_custom_data_all() override {
1476  visit_depth_all(visitor);
1477  }
1478 
1479  /// Returns the future associated to the underlying execution
1480  const std::shared_future<result_type>& get_future() const noexcept override {
1481  return future_;
1482  }
1483 
1484  /// Returns the associated node
1485  const std::shared_ptr<transwarp::node>& get_node() const noexcept override {
1486  return node_;
1487  }
1488 
1489  /// Adds a new listener for all event types
1490  void add_listener(std::shared_ptr<transwarp::listener> listener) override {
1492  check_listener(listener);
1493  for (auto& l : listeners_) {
1494  l.push_back(listener);
1495  }
1496  }
1497 
1498  /// Adds a new listener for the given event type only
1499  void add_listener(transwarp::event_type event, std::shared_ptr<transwarp::listener> listener) override {
1501  check_listener(listener);
1502  listeners_[get_event_index(event)].push_back(std::move(listener));
1503  }
1504 
1505  /// Removes the listener for all event types
1506  void remove_listener(const std::shared_ptr<transwarp::listener>& listener) override {
1508  check_listener(listener);
1509  for (auto& l : listeners_) {
1510  l.erase(std::remove(l.begin(), l.end(), listener), l.end());
1511  }
1512  }
1513 
1514  /// Removes the listener for the given event type only
1515  void remove_listener(transwarp::event_type event, const std::shared_ptr<transwarp::listener>& listener) override {
1517  check_listener(listener);
1518  auto& l = listeners_[get_event_index(event)];
1519  l.erase(std::remove(l.begin(), l.end(), listener), l.end());
1520  }
1521 
1522  /// Removes all listeners for the given event type
1525  listeners_[get_event_index(event)].clear();
1526  }
1527 
1528  /// Removes all listeners
1529  void remove_listeners() override {
1531  for (auto& l : listeners_) {
1532  l.clear();
1533  }
1534  }
1535 
1536  /// Schedules this task for execution on the caller thread.
1537  /// The task-specific executor gets precedence if it exists.
1538  /// This overload will reset the underlying future.
1539  void schedule() override {
1541  this->schedule_impl(true);
1542  }
1543 
1544  /// Schedules this task for execution on the caller thread.
1545  /// The task-specific executor gets precedence if it exists.
1546  /// reset denotes whether schedule should reset the underlying
1547  /// future and schedule even if the future is already valid.
1548  void schedule(bool reset) override {
1550  this->schedule_impl(reset);
1551  }
1552 
1553  /// Schedules this task for execution using the provided executor.
1554  /// The task-specific executor gets precedence if it exists.
1555  /// This overload will reset the underlying future.
1558  this->schedule_impl(true, &executor);
1559  }
1560 
1561  /// Schedules this task for execution using the provided executor.
1562  /// The task-specific executor gets precedence if it exists.
1563  /// reset denotes whether schedule should reset the underlying
1564  /// future and schedule even if the future is already valid.
1565  void schedule(transwarp::executor& executor, bool reset) override {
1567  this->schedule_impl(reset, &executor);
1568  }
1569 
1570  /// Schedules all tasks in the graph for execution on the caller thread.
1571  /// The task-specific executors get precedence if they exist.
1572  /// This overload will reset the underlying futures.
1573  void schedule_all() override {
1575  schedule_all_impl(true, transwarp::schedule_type::breadth);
1576  }
1577 
1578  /// Schedules all tasks in the graph for execution using the provided executor.
1579  /// The task-specific executors get precedence if they exist.
1580  /// This overload will reset the underlying futures.
1583  schedule_all_impl(true, transwarp::schedule_type::breadth, &executor);
1584  }
1585 
1586  /// Schedules all tasks in the graph for execution on the caller thread.
1587  /// The task-specific executors get precedence if they exist.
1588  /// reset_all denotes whether schedule_all should reset the underlying
1589  /// futures and schedule even if the futures are already present.
1590  void schedule_all(bool reset_all) override {
1592  schedule_all_impl(reset_all, transwarp::schedule_type::breadth);
1593  }
1594 
1595  /// Schedules all tasks in the graph for execution using the provided executor.
1596  /// The task-specific executors get precedence if they exist.
1597  /// reset_all denotes whether schedule_all should reset the underlying
1598  /// futures and schedule even if the futures are already present.
1601  schedule_all_impl(reset_all, transwarp::schedule_type::breadth, &executor);
1602  }
1603 
1604  /// Schedules all tasks in the graph for execution on the caller thread.
1605  /// The task-specific executors get precedence if they exist.
1606  /// This overload will reset the underlying futures.
1609  schedule_all_impl(true, type);
1610  }
1611 
1612  /// Schedules all tasks in the graph for execution using the provided executor.
1613  /// The task-specific executors get precedence if they exist.
1614  /// This overload will reset the underlying futures.
1617  schedule_all_impl(true, type, &executor);
1618  }
1619 
1620  /// Schedules all tasks in the graph for execution on the caller thread.
1621  /// The task-specific executors get precedence if they exist.
1622  /// reset_all denotes whether schedule_all should reset the underlying
1623  /// futures and schedule even if the futures are already present.
1626  schedule_all_impl(reset_all, type);
1627  }
1628 
1629  /// Schedules all tasks in the graph for execution using the provided executor.
1630  /// The task-specific executors get precedence if they exist.
1631  /// reset_all denotes whether schedule_all should reset the underlying
1632  /// futures and schedule even if the futures are already present.
1635  schedule_all_impl(reset_all, type, &executor);
1636  }
1637 
1638  /// Assigns an exception to this task. Scheduling will have no effect after an exception
1639  /// has been set. Calling reset() will remove the exception and re-enable scheduling.
1640  void set_exception(std::exception_ptr exception) override {
1642  future_ = transwarp::detail::make_future_with_exception<result_type>(exception);
1643  schedule_mode_ = false;
1644  }
1645 
1646  /// Returns whether the task was scheduled and not reset afterwards.
1647  /// This means that the underlying future is valid
1648  bool was_scheduled() const noexcept override {
1649  return future_.valid();
1650  }
1651 
1652  /// Waits for the task to complete. Should only be called if was_scheduled()
1653  /// is true, throws transwarp::control_error otherwise
1654  void wait() const override {
1656  future_.wait();
1657  }
1658 
1659  /// Returns whether the task has finished processing. Should only be called
1660  /// if was_scheduled() is true, throws transwarp::control_error otherwise
1661  bool is_ready() const override {
1663  return future_.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
1664  }
1665 
1666  /// Returns whether this task contains a result
1667  bool has_result() const noexcept override {
1668  return was_scheduled() && is_ready();
1669  }
1670 
1671  /// Resets this task
1672  void reset() override {
1674  future_ = std::shared_future<result_type>();
1675  transwarp::detail::node_manip::set_canceled(*node_, false);
1676  schedule_mode_ = true;
1677  }
1678 
1679  /// Resets all tasks in the graph
1680  void reset_all() override {
1683  visit_depth_all(visitor);
1684  }
1685 
1686  /// If enabled then this task is canceled which will
1687  /// throw transwarp::task_canceled when retrieving the task result.
1688  /// Passing false is equivalent to resume.
1689  void cancel(bool enabled) noexcept override {
1690  transwarp::detail::node_manip::set_canceled(*node_, enabled);
1691  }
1692 
1693  /// If enabled then all pending tasks in the graph are canceled which will
1694  /// throw transwarp::task_canceled when retrieving the task result.
1695  /// Passing false is equivalent to resume.
1696  void cancel_all(bool enabled) noexcept override {
1697  transwarp::detail::cancel_visitor visitor(enabled);
1698  visit_depth_all(visitor);
1699  }
1700 
1701  /// Returns the graph of the task structure. This is mainly for visualizing
1702  /// the tasks and their interdependencies. Pass the result into transwarp::to_string
1703  /// to retrieve a dot-style graph representation for easy viewing.
1704  std::vector<transwarp::edge> get_graph() const override {
1705  std::vector<transwarp::edge> graph;
1706  transwarp::detail::graph_visitor visitor(graph);
1707  const_cast<task_impl_base*>(this)->visit_depth_all(visitor);
1708  return graph;
1709  }
1710 
1711 protected:
1712 
1713  template<typename F>
1714  // cppcheck-suppress passedByValue
1715  task_impl_base(bool has_name, std::string name, F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
1716  : node_(std::make_shared<transwarp::node>()),
1717  functor_(std::forward<F>(functor)),
1718  parents_(std::make_tuple(std::move(parents)...)),
1719  listeners_(static_cast<std::size_t>(transwarp::event_type::count))
1720  {
1721  init(has_name, std::move(name));
1722  }
1723 
1724  template<typename F, typename P>
1725  // cppcheck-suppress passedByValue
1726  task_impl_base(bool has_name, std::string name, F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
1727  : node_(std::make_shared<transwarp::node>()),
1728  functor_(std::forward<F>(functor)),
1729  parents_(std::move(parents)),
1730  listeners_(static_cast<std::size_t>(transwarp::event_type::count))
1731  {
1732  if (parents_.empty()) {
1733  throw transwarp::invalid_parameter("parents are empty");
1734  }
1735  init(has_name, std::move(name));
1736  }
1737 
1738  void init(bool has_name, std::string name) {
1739  transwarp::detail::node_manip::set_type(*node_, task_type::value);
1740  transwarp::detail::node_manip::set_name(*node_, (has_name ? std::make_shared<std::string>(std::move(name)) : nullptr));
1741  transwarp::detail::assign_node_if(functor_, node_);
1744  visit_depth(visitor);
1745  unvisit();
1746  }
1747 
1748  /// Checks if the task is currently running and throws transwarp::control_error if it is
1750  if (future_.valid() && future_.wait_for(std::chrono::seconds(0)) != std::future_status::ready) {
1751  throw transwarp::control_error("task currently running: " + transwarp::to_string(*node_, " "));
1752  }
1753  }
1754 
1755  /// Checks if the task was scheduled and throws transwarp::control_error if it's not
1757  if (!future_.valid()) {
1758  throw transwarp::control_error("task was not scheduled: " + transwarp::to_string(*node_, " "));
1759  }
1760  }
1761 
1762  bool schedule_mode_ = true;
1763  std::shared_future<result_type> future_;
1764 
1765 private:
1766 
1767  template<typename Y, typename R, typename T, typename P>
1768  friend struct transwarp::detail::runner;
1769 
1770  template<typename R, typename T, typename... A>
1771  friend R transwarp::detail::run_task(std::size_t, const T&, A&&...);
1772 
1773  /// Assigns the given id to the node
1774  void set_node_id(std::size_t id) noexcept override {
1775  transwarp::detail::node_manip::set_id(*node_, id);
1776  }
1777 
1778  /// Schedules this task for execution using the provided executor.
1779  /// The task-specific executor gets precedence if it exists.
1780  /// Runs the task on the same thread as the caller if neither the global
1781  /// nor the task-specific executor is found.
1782  void schedule_impl(bool reset, transwarp::executor* executor=nullptr) override {
1783  if (schedule_mode_ && (reset || !future_.valid())) {
1784  if (reset) {
1785  transwarp::detail::node_manip::set_canceled(*node_, false);
1786  }
1787  std::weak_ptr<task_impl_base> self = this->shared_from_this();
1788  auto pack_task = std::make_shared<std::packaged_task<result_type()>>(
1791  future_ = pack_task->get_future();
1792  auto callable = [pack_task,self] {
1793  if (const auto t = self.lock()) {
1794  t->raise_event(transwarp::event_type::before_started);
1795  }
1796  (*pack_task)();
1797  if (const auto t = self.lock()) {
1798  t->raise_event(transwarp::event_type::after_finished);
1799  }
1800  };
1801  if (executor_) {
1802  executor_->execute(callable, node_);
1803  } else if (executor) {
1804  executor->execute(callable, node_);
1805  } else {
1806  callable();
1807  }
1808  }
1809  }
1810 
1811  /// Schedules all tasks in the graph for execution using the provided executor.
1812  /// The task-specific executors get precedence if they exist.
1813  /// Runs tasks on the same thread as the caller if neither the global
1814  /// nor a task-specific executor is found.
1815  void schedule_all_impl(bool reset_all, transwarp::schedule_type type, transwarp::executor* executor=nullptr) {
1816  transwarp::detail::schedule_visitor visitor(reset_all, executor);
1817  switch (type) {
1819  visit_breadth_all(visitor);
1820  break;
1822  visit_depth_all(visitor);
1823  break;
1824  default:
1825  throw transwarp::invalid_parameter("schedule type");
1826  }
1827  }
1828 
1829  /// Visits all tasks in a breadth-first traversal.
1830  template<typename Visitor>
1831  void visit_breadth_all(Visitor& visitor) {
1832  if (breadth_tasks_.empty()) {
1833  breadth_tasks_.reserve(node_->get_id() + 1);
1834  visit_depth(transwarp::detail::push_task_visitor(breadth_tasks_));
1835  unvisit();
1836  auto compare = [](const transwarp::itask* const l, const transwarp::itask* const r) {
1837  const auto l_level = l->get_node()->get_level();
1838  const auto l_id = l->get_node()->get_id();
1839  const auto r_level = r->get_node()->get_level();
1840  const auto r_id = r->get_node()->get_id();
1841  return std::tie(l_level, l_id) < std::tie(r_level, r_id);
1842  };
1843  std::sort(breadth_tasks_.begin(), breadth_tasks_.end(), compare);
1844  }
1845  for (auto task : breadth_tasks_) {
1846  visitor(*task);
1847  }
1848  }
1849 
1850  /// Visits all tasks in a depth-first traversal.
1851  template<typename Visitor>
1852  void visit_depth_all(Visitor& visitor) {
1853  if (depth_tasks_.empty()) {
1854  depth_tasks_.reserve(node_->get_id() + 1);
1855  visit_depth(transwarp::detail::push_task_visitor(depth_tasks_));
1856  unvisit();
1857  }
1858  for (auto task : depth_tasks_) {
1859  visitor(*task);
1860  }
1861  }
1862 
1863  /// Visits each task in a depth-first traversal.
1864  void visit_depth(const std::function<void(transwarp::itask&)>& visitor) override {
1865  if (!visited_) {
1867  visitor(*this);
1868  visited_ = true;
1869  }
1870  }
1871 
1872  /// Traverses through each task and marks them as not visited.
1873  void unvisit() noexcept override {
1874  if (visited_) {
1875  visited_ = false;
1877  }
1878  }
1879 
1880  /// Returns the index for a given event type
1881  std::size_t get_event_index(transwarp::event_type event) const {
1882  const auto index = static_cast<std::size_t>(event);
1883  if (index >= static_cast<std::size_t>(transwarp::event_type::count)) {
1884  throw transwarp::invalid_parameter("event type");
1885  }
1886  return index;
1887  }
1888 
1889  /// Raises the given event to all listeners
1890  void raise_event(transwarp::event_type event) const {
1891  for (const auto& listener : listeners_[static_cast<std::size_t>(event)]) {
1892  listener->handle_event(event, get_node());
1893  }
1894  }
1895 
1896  /// Check for non-null listener pointer
1897  void check_listener(const std::shared_ptr<transwarp::listener>& listener) const {
1898  if (!listener) {
1899  throw transwarp::invalid_parameter("listener pointer");
1900  }
1901  }
1902 
1903  std::shared_ptr<transwarp::node> node_;
1904  Functor functor_;
1905  typename transwarp::detail::parents<ParentResults...>::type parents_;
1906  bool visited_ = false;
1907  std::shared_ptr<transwarp::executor> executor_;
1908  std::vector<std::vector<std::shared_ptr<transwarp::listener>>> listeners_;
1909  std::vector<transwarp::itask*> depth_tasks_;
1910  std::vector<transwarp::itask*> breadth_tasks_;
1911 };
1912 
1913 
1914 /// A task proxy for non-void result type.
1915 template<typename ResultType, typename TaskType, typename Functor, typename... ParentResults>
1916 class task_impl_proxy : public transwarp::detail::task_impl_base<ResultType, TaskType, Functor, ParentResults...> {
1917 public:
1918  /// The task type
1919  using task_type = TaskType;
1920 
1921  /// The result type of this task
1922  using result_type = ResultType;
1923 
1924  /// Assigns a value to this task. Scheduling will have no effect after a value
1925  /// has been set. Calling reset() will remove the value and re-enable scheduling.
1926  void set_value(const typename transwarp::decay<result_type>::type& value) override {
1927  set_value_impl(value);
1928  }
1929 
1930  /// Assigns a value to this task. Scheduling will have no effect after a value
1931  /// has been set. Calling reset() will remove the value and re-enable scheduling.
1932  void set_value(typename transwarp::decay<result_type>::type&& value) override {
1933  set_value_impl(value);
1934  }
1935 
1936  /// Returns the result of this task. Throws any exceptions that the underlying
1937  /// functor throws. Should only be called if was_scheduled() is true,
1938  /// throws transwarp::control_error otherwise
1939  typename transwarp::result_info<result_type>::type get() const override {
1940  this->ensure_task_was_scheduled();
1941  return this->future_.get();
1942  }
1943 
1944 protected:
1945 
1946  template<typename F>
1947  // cppcheck-suppress passedByValue
1948  // cppcheck-suppress uninitMemberVar
1949  task_impl_proxy(std::string name, F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
1950  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents)...)
1951  {}
1952 
1953  template<typename F>
1954  // cppcheck-suppress uninitMemberVar
1955  explicit task_impl_proxy(F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
1956  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents)...)
1957  {}
1958 
1959  template<typename F, typename P>
1960  // cppcheck-suppress passedByValue
1961  // cppcheck-suppress uninitMemberVar
1962  task_impl_proxy(std::string name, F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
1963  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents))
1964  {}
1965 
1966  template<typename F, typename P>
1967  // cppcheck-suppress uninitMemberVar
1968  task_impl_proxy(F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
1969  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents))
1970  {}
1971 
1972 private:
1973 
1974  template<typename T>
1975  void set_value_impl(T&& value) {
1976  this->ensure_task_not_running();
1977  this->future_ = transwarp::detail::make_future_with_value<result_type>(std::forward<T>(value));
1978  this->schedule_mode_ = false;
1979  }
1980 
1981 };
1982 
1983 /// A task for non-void, non-const reference result type.
1984 template<typename ResultType, typename TaskType, typename Functor, typename... ParentResults>
1985 class task_impl_proxy<ResultType&, TaskType, Functor, ParentResults...> : public transwarp::detail::task_impl_base<ResultType&, TaskType, Functor, ParentResults...> {
1986 public:
1987  /// The task type
1988  using task_type = TaskType;
1989 
1990  /// The result type of this task
1991  using result_type = ResultType&;
1992 
1993  /// Assigns a value to this task. Scheduling will have no effect after a value
1994  /// has been set. Calling reset() will remove the value and re-enable scheduling.
1995  void set_value(typename transwarp::decay<result_type>::type& value) override {
1996  set_value_impl(value);
1997  }
1998 
1999  /// Returns the result of this task. Throws any exceptions that the underlying
2000  /// functor throws. Should only be called if was_scheduled() is true,
2001  /// throws transwarp::control_error otherwise
2002  typename transwarp::result_info<result_type>::type get() const override {
2003  this->ensure_task_was_scheduled();
2004  return this->future_.get();
2005  }
2006 
2007 protected:
2008 
2009  template<typename F>
2010  // cppcheck-suppress passedByValue
2011  // cppcheck-suppress uninitMemberVar
2012  task_impl_proxy(std::string name, F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2013  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents)...)
2014  {}
2015 
2016  template<typename F>
2017  // cppcheck-suppress uninitMemberVar
2018  explicit task_impl_proxy(F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2019  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents)...)
2020  {}
2021 
2022  template<typename F, typename P>
2023  // cppcheck-suppress passedByValue
2024  // cppcheck-suppress uninitMemberVar
2025  task_impl_proxy(std::string name, F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2026  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents))
2027  {}
2028 
2029  template<typename F, typename P>
2030  // cppcheck-suppress uninitMemberVar
2031  task_impl_proxy(F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2032  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents))
2033  {}
2034 
2035 private:
2036 
2037  template<typename T>
2038  void set_value_impl(T&& value) {
2039  this->ensure_task_not_running();
2040  this->future_ = transwarp::detail::make_future_with_value<result_type>(std::forward<T>(value));
2041  this->schedule_mode_ = false;
2042  }
2043 
2044 };
2045 
2046 /// A task for void result type.
2047 template<typename TaskType, typename Functor, typename... ParentResults>
2048 class task_impl_proxy<void, TaskType, Functor, ParentResults...> : public transwarp::detail::task_impl_base<void, TaskType, Functor, ParentResults...> {
2049 public:
2050  /// The task type
2051  using task_type = TaskType;
2052 
2053  /// The result type of this task
2054  using result_type = void;
2055 
2056  /// Assigns a value to this task. Scheduling will have no effect after a call
2057  /// to this. Calling reset() will reset this and re-enable scheduling.
2058  void set_value() override {
2059  this->ensure_task_not_running();
2060  this->future_ = transwarp::detail::make_ready_future();
2061  this->schedule_mode_ = false;
2062  }
2063 
2064  /// Blocks until the task finishes. Throws any exceptions that the underlying
2065  /// functor throws. Should only be called if was_scheduled() is true,
2066  /// throws transwarp::control_error otherwise
2067  void get() const override {
2068  this->ensure_task_was_scheduled();
2069  this->future_.get();
2070  }
2071 
2072 protected:
2073 
2074  template<typename F>
2075  // cppcheck-suppress passedByValue
2076  // cppcheck-suppress uninitMemberVar
2077  task_impl_proxy(std::string name, F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2078  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents)...)
2079  {}
2080 
2081  template<typename F>
2082  // cppcheck-suppress uninitMemberVar
2083  explicit task_impl_proxy(F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2084  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents)...)
2085  {}
2086 
2087  template<typename F, typename P>
2088  // cppcheck-suppress passedByValue
2089  // cppcheck-suppress uninitMemberVar
2090  task_impl_proxy(std::string name, F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2091  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(true, std::move(name), std::forward<F>(functor), std::move(parents))
2092  {}
2093 
2094  template<typename F, typename P>
2095  // cppcheck-suppress uninitMemberVar
2096  task_impl_proxy(F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2097  : transwarp::detail::task_impl_base<result_type, task_type, Functor, ParentResults...>(false, "", std::forward<F>(functor), std::move(parents))
2098  {}
2099 
2100 };
2101 
2102 } // detail
2103 
2104 
2105 /// A task representing a piece of work given by functor and parent tasks.
2106 /// By connecting tasks a directed acyclic graph is built.
2107 /// Tasks should be created using the make_task factory functions.
2108 template<typename TaskType, typename Functor, typename... ParentResults>
2109 class task_impl : public transwarp::detail::task_impl_proxy<typename transwarp::detail::result<TaskType, Functor, ParentResults...>::type, TaskType, Functor, ParentResults...> {
2110 public:
2111  /// The task type
2112  using task_type = TaskType;
2113 
2114  /// The result type of this task
2115  using result_type = typename transwarp::detail::result<TaskType, Functor, ParentResults...>::type;
2116 
2117  /// A task is defined by name, functor, and parent tasks. name is optional, see overload
2118  /// Note: A task must be created using shared_ptr (because of shared_from_this)
2119  template<typename F, typename = typename std::enable_if<std::is_same<Functor, typename std::decay<F>::type>::value>::type>
2120  // cppcheck-suppress passedByValue
2121  // cppcheck-suppress uninitMemberVar
2122  task_impl(std::string name, F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2123  : transwarp::detail::task_impl_proxy<result_type, task_type, Functor, ParentResults...>(std::move(name), std::forward<F>(functor), std::move(parents)...)
2124  {}
2125 
2126  /// This overload is for omitting the task name
2127  /// Note: A task must be created using shared_ptr (because of shared_from_this)
2128  template<typename F, typename = typename std::enable_if<std::is_same<Functor, typename std::decay<F>::type>::value>::type>
2129  // cppcheck-suppress uninitMemberVar
2130  explicit task_impl(F&& functor, std::shared_ptr<transwarp::task<ParentResults>>... parents)
2131  : transwarp::detail::task_impl_proxy<result_type, task_type, Functor, ParentResults...>(std::forward<F>(functor), std::move(parents)...)
2132  {}
2133 
2134  /// A task is defined by name, functor, and parent tasks. name is optional, see overload
2135  /// Note: A task must be created using shared_ptr (because of shared_from_this)
2136  template<typename F, typename P, typename = typename std::enable_if<std::is_same<Functor, typename std::decay<F>::type>::value>::type>
2137  // cppcheck-suppress uninitMemberVar
2138  task_impl(std::string name, F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2139  : transwarp::detail::task_impl_proxy<result_type, task_type, Functor, ParentResults...>(std::move(name), std::forward<F>(functor), std::move(parents))
2140  {}
2141 
2142  /// This overload is for omitting the task name
2143  /// Note: A task must be created using shared_ptr (because of shared_from_this)
2144  template<typename F, typename P, typename = typename std::enable_if<std::is_same<Functor, typename std::decay<F>::type>::value>::type>
2145  // cppcheck-suppress uninitMemberVar
2146  task_impl(F&& functor, std::vector<std::shared_ptr<transwarp::task<P>>> parents)
2147  : transwarp::detail::task_impl_proxy<result_type, task_type, Functor, ParentResults...>(std::forward<F>(functor), std::move(parents))
2148  {}
2149 
2150  /// Creates a continuation to this task
2151  template<typename TaskType_, typename Functor_>
2152  auto then(TaskType_, std::string name, Functor_&& functor) const
2153  -> decltype(std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::move(name), std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<task_impl*>(this)->shared_from_this()))) {
2154  return std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::move(name), std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<task_impl*>(this)->shared_from_this()));
2155  }
2156 
2157  /// Creates a continuation to this task. Overload for omitting for task name
2158  template<typename TaskType_, typename Functor_>
2159  auto then(TaskType_, Functor_&& functor) const
2160  -> decltype(std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<task_impl*>(this)->shared_from_this()))) {
2161  return std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<task_impl*>(this)->shared_from_this()));
2162  }
2163 
2164  // delete copy/move semantics
2165  task_impl(const task_impl&) = delete;
2166  task_impl& operator=(const task_impl&) = delete;
2167  task_impl(task_impl&&) = delete;
2168  task_impl& operator=(task_impl&&) = delete;
2169 };
2170 
2171 
2172 /// A value task that stores a single value and doesn't require scheduling.
2173 /// Value tasks should be created using the make_value_task factory functions.
2174 template<typename ResultType>
2175 class value_task : public transwarp::task<ResultType>,
2176  public std::enable_shared_from_this<value_task<ResultType>> {
2177 public:
2178  /// The task type
2180 
2181  /// The result type of this task
2182  using result_type = ResultType;
2183 
2184  /// A value task is defined by name and value. name is optional, see overload
2185  /// Note: A value task must be created using shared_ptr (because of shared_from_this)
2186  template<typename T, typename = typename std::enable_if<std::is_same<result_type, typename transwarp::decay<T>::type>::value>::type>
2187  // cppcheck-suppress passedByValue
2188  // cppcheck-suppress uninitMemberVar
2189  value_task(std::string name, T&& value)
2190  : value_task(true, std::move(name), std::forward<T>(value))
2191  {}
2192 
2193  /// This overload is for omitting the task name
2194  /// Note: A value task must be created using shared_ptr (because of shared_from_this)
2195  template<typename T, typename = typename std::enable_if<std::is_same<result_type, typename transwarp::decay<T>::type>::value>::type>
2196  // cppcheck-suppress uninitMemberVar
2197  explicit value_task(T&& value)
2198  : value_task(false, "", std::forward<T>(value))
2199  {}
2200 
2201  virtual ~value_task() = default;
2202 
2203  // delete copy/move semantics
2204  value_task(const value_task&) = delete;
2205  value_task& operator=(const value_task&) = delete;
2206  value_task(value_task&&) = delete;
2207  value_task& operator=(value_task&&) = delete;
2208 
2209  /// Creates a continuation to this task
2210  template<typename TaskType_, typename Functor_>
2211  auto then(TaskType_, std::string name, Functor_&& functor) const
2212  -> decltype(std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::move(name), std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<value_task*>(this)->shared_from_this()))) {
2213  return std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::move(name), std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<value_task*>(this)->shared_from_this()));
2214  }
2215 
2216  /// Creates a continuation to this task. Overload for omitting for task name
2217  template<typename TaskType_, typename Functor_>
2218  auto then(TaskType_, Functor_&& functor) const
2219  -> decltype(std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<value_task*>(this)->shared_from_this()))) {
2220  return std::make_shared<transwarp::task_impl<TaskType_, typename std::decay<Functor_>::type, result_type>>(std::forward<Functor_>(functor), std::dynamic_pointer_cast<transwarp::task<result_type>>(const_cast<value_task*>(this)->shared_from_this()));
2221  }
2222 
2223  /// No-op because a value task never runs
2224  void set_executor(std::shared_ptr<transwarp::executor>) override {}
2225 
2226  /// No-op because a value task never runs and doesn't have parents
2227  void set_executor_all(std::shared_ptr<transwarp::executor>) override {}
2228 
2229  /// No-op because a value task never runs
2230  void remove_executor() override {}
2231 
2232  /// No-op because a value task never runs and doesn't have parents
2233  void remove_executor_all() override {}
2234 
2235  /// Sets a task priority (defaults to 0). transwarp will not directly use this.
2236  /// This is only useful if something else is using the priority
2237  void set_priority(std::size_t priority) override {
2238  transwarp::detail::node_manip::set_priority(*node_, priority);
2239  }
2240 
2241  /// Sets a priority to all tasks (defaults to 0). transwarp will not directly use this.
2242  /// This is only useful if something else is using the priority
2243  void set_priority_all(std::size_t priority) override {
2244  set_priority(priority);
2245  }
2246 
2247  /// Resets the task priority to 0
2248  void reset_priority() override {
2249  transwarp::detail::node_manip::set_priority(*node_, 0);
2250  }
2251 
2252  /// Resets the priority of all tasks to 0
2253  void reset_priority_all() override {
2254  reset_priority();
2255  }
2256 
2257  /// Assigns custom data to this task. transwarp will not directly use this.
2258  /// This is only useful if something else is using this custom data
2259  void set_custom_data(std::shared_ptr<void> custom_data) override {
2260  if (!custom_data) {
2261  throw transwarp::invalid_parameter("custom data pointer");
2262  }
2263  transwarp::detail::node_manip::set_custom_data(*node_, std::move(custom_data));
2264  }
2265 
2266  /// Assigns custom data to all tasks. transwarp will not directly use this.
2267  /// This is only useful if something else is using this custom data
2268  void set_custom_data_all(std::shared_ptr<void> custom_data) override {
2269  set_custom_data(std::move(custom_data));
2270  }
2271 
2272  /// Removes custom data from this task
2273  void remove_custom_data() override {
2274  transwarp::detail::node_manip::set_custom_data(*node_, nullptr);
2275  }
2276 
2277  /// Removes custom data from all tasks
2278  void remove_custom_data_all() override {
2280  }
2281 
2282  /// Returns the future associated to the underlying execution
2283  const std::shared_future<result_type>& get_future() const noexcept override {
2284  return future_;
2285  }
2286 
2287  /// Returns the associated node
2288  const std::shared_ptr<transwarp::node>& get_node() const noexcept override {
2289  return node_;
2290  }
2291 
2292  /// No-op because a value task doesn't raise events
2293  void add_listener(std::shared_ptr<transwarp::listener>) override {}
2294 
2295  /// No-op because a value task doesn't raise events
2296  void add_listener(transwarp::event_type, std::shared_ptr<transwarp::listener>) override {}
2297 
2298  /// No-op because a value task doesn't raise events
2299  void remove_listener(const std::shared_ptr<transwarp::listener>&) override {}
2300 
2301  /// No-op because a value task doesn't raise events
2302  void remove_listener(transwarp::event_type, const std::shared_ptr<transwarp::listener>&) override {}
2303 
2304  /// No-op because a value task doesn't raise events
2306 
2307  /// No-op because a value task doesn't raise events
2308  void remove_listeners() override {}
2309 
2310  /// No-op because a value task never runs
2311  void schedule() override {}
2312 
2313  /// No-op because a value task never runs
2314  void schedule(transwarp::executor&) override {}
2315 
2316  /// No-op because a value task never runs
2317  void schedule(bool) override {}
2318 
2319  /// No-op because a value task never runs
2320  void schedule(transwarp::executor&, bool) override {}
2321 
2322  /// No-op because a value task never runs and doesn't have parents
2323  void schedule_all() override {}
2324 
2325  /// No-op because a value task never runs and doesn't have parents
2327 
2328  /// No-op because a value task never runs and doesn't have parents
2329  void schedule_all(bool) override {}
2330 
2331  /// No-op because a value task never runs and doesn't have parents
2332  void schedule_all(transwarp::executor&, bool) override {}
2333 
2334  /// No-op because a value task never runs and doesn't have parents
2336 
2337  /// No-op because a value task never runs and doesn't have parents
2339 
2340  /// No-op because a value task never runs and doesn't have parents
2341  void schedule_all(transwarp::schedule_type, bool) override {}
2342 
2343  /// No-op because a value task never runs and doesn't have parents
2345 
2346  /// Assigns a value to this task
2347  void set_value(const typename transwarp::decay<result_type>::type& value) override {
2348  future_ = transwarp::detail::make_future_with_value<result_type>(value);
2349  }
2350 
2351  /// Assigns a value to this task
2352  void set_value(typename transwarp::decay<result_type>::type&& value) override {
2353  future_ = transwarp::detail::make_future_with_value<result_type>(value);
2354  };
2355 
2356  /// Assigns an exception to this task
2357  void set_exception(std::exception_ptr exception) override {
2358  future_ = transwarp::detail::make_future_with_exception<result_type>(exception);
2359  }
2360 
2361  /// Returns true because a value task is scheduled once on construction
2362  bool was_scheduled() const noexcept override {
2363  return true;
2364  }
2365 
2366  /// No-op because a value task never runs
2367  void wait() const override {}
2368 
2369  /// Returns true because a value task is always ready
2370  bool is_ready() const override {
2371  return true;
2372  }
2373 
2374  /// Returns true because a value task always contains a result
2375  bool has_result() const noexcept override {
2376  return true;
2377  }
2378 
2379  /// Returns the result of this task
2380  typename transwarp::result_info<result_type>::type get() const override {
2381  return future_.get();
2382  }
2383 
2384  /// No-op because a value task never runs
2385  void reset() override {}
2386 
2387  /// No-op because a value task never runs and doesn't have parents
2388  void reset_all() override {}
2389 
2390  /// No-op because a value task never runs
2391  void cancel(bool) noexcept override {}
2392 
2393  /// No-op because a value task never runs and doesn't have parents
2394  void cancel_all(bool) noexcept override {}
2395 
2396  /// Returns an empty graph because a value task doesn't have parents
2397  std::vector<transwarp::edge> get_graph() const override {
2398  return {};
2399  }
2400 
2401 private:
2402 
2403  template<typename T>
2404  // cppcheck-suppress passedByValue
2405  value_task(bool has_name, std::string name, T&& value)
2406  : node_(std::make_shared<transwarp::node>()),
2407  future_(transwarp::detail::make_future_with_value<result_type>(std::forward<T>(value)))
2408  {
2409  transwarp::detail::node_manip::set_type(*node_, task_type::value);
2410  transwarp::detail::node_manip::set_name(*node_, (has_name ? std::make_shared<std::string>(std::move(name)) : nullptr));
2411  }
2412 
2413  /// Assigns the given id to the node
2414  void set_node_id(std::size_t id) noexcept override {
2415  transwarp::detail::node_manip::set_id(*node_, id);
2416  }
2417 
2418  /// No-op because a value task never runs
2419  void schedule_impl(bool, transwarp::executor*) override {}
2420 
2421  /// Visits this task
2422  void visit_depth(const std::function<void(transwarp::itask&)>& visitor) override {
2423  if (!visited_) {
2424  visitor(*this);
2425  visited_ = true;
2426  }
2427  }
2428 
2429  /// Marks this task as not visited
2430  void unvisit() noexcept override {
2431  visited_ = false;
2432  }
2433 
2434  std::shared_ptr<transwarp::node> node_;
2435  std::shared_future<result_type> future_;
2436  bool visited_ = false;
2437 };
2438 
2439 
2440 /// A factory function to create a new task
2441 template<typename TaskType, typename Functor, typename... Parents>
2442 auto make_task(TaskType, std::string name, Functor&& functor, std::shared_ptr<Parents>... parents)
2443  -> decltype(std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, typename Parents::result_type...>>(std::move(name), std::forward<Functor>(functor), std::move(parents)...)) {
2444  return std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, typename Parents::result_type...>>(std::move(name), std::forward<Functor>(functor), std::move(parents)...);
2445 }
2446 
2447 /// A factory function to create a new task. Overload for omitting the task name
2448 template<typename TaskType, typename Functor, typename... Parents>
2449 auto make_task(TaskType, Functor&& functor, std::shared_ptr<Parents>... parents)
2450  -> decltype(std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, typename Parents::result_type...>>(std::forward<Functor>(functor), std::move(parents)...)) {
2451  return std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, typename Parents::result_type...>>(std::forward<Functor>(functor), std::move(parents)...);
2452 }
2453 
2454 
2455 /// A factory function to create a new task with vector parents
2456 template<typename TaskType, typename Functor, typename ParentType>
2457 auto make_task(TaskType, std::string name, Functor&& functor, std::vector<ParentType> parents)
2458  -> decltype(std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, decltype(parents)>>(std::move(name), std::forward<Functor>(functor), std::move(parents))) {
2459  return std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, decltype(parents)>>(std::move(name), std::forward<Functor>(functor), std::move(parents));
2460 }
2461 
2462 /// A factory function to create a new task with vector parents. Overload for omitting the task name
2463 template<typename TaskType, typename Functor, typename ParentType>
2464 auto make_task(TaskType, Functor&& functor, std::vector<ParentType> parents)
2465  -> decltype(std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, decltype(parents)>>(std::forward<Functor>(functor), std::move(parents))) {
2466  return std::make_shared<transwarp::task_impl<TaskType, typename std::decay<Functor>::type, decltype(parents)>>(std::forward<Functor>(functor), std::move(parents));
2467 }
2468 
2469 
2470 /// A factory function to create a new value task
2471 template<typename Value>
2472 auto make_value_task(std::string name, Value&& value)
2473  -> decltype(std::make_shared<transwarp::value_task<typename transwarp::decay<Value>::type>>(std::move(name), std::forward<Value>(value))) {
2474  return std::make_shared<transwarp::value_task<typename transwarp::decay<Value>::type>>(std::move(name), std::forward<Value>(value));
2475 }
2476 
2477 /// A factory function to create a new value task. Overload for omitting the task name
2478 template<typename Value>
2479 auto make_value_task(Value&& value)
2480  -> decltype(std::make_shared<transwarp::value_task<typename transwarp::decay<Value>::type>>(std::forward<Value>(value))) {
2481  return std::make_shared<transwarp::value_task<typename transwarp::decay<Value>::type>>(std::forward<Value>(value));
2482 }
2483 
2484 
2485 } // transwarp
void set_custom_data_all(std::shared_ptr< void > custom_data) override
Assigns custom data to all tasks. transwarp will not directly use this. This is only useful if someth...
Definition: transwarp.h:1460
constexpr transwarp::wait_any_type wait_any
The wait_any task tag.
Definition: transwarp.h:127
void remove_custom_data_all() override
Removes custom data from all tasks.
Definition: transwarp.h:2278
The executor interface used to perform custom task execution.
Definition: transwarp.h:282
Exception thrown when a task was destroyed prematurely.
Definition: transwarp.h:60
A simple thread pool used to execute tasks in parallel.
Definition: transwarp.h:527
void cancel_all(bool) noexceptoverride
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2394
void operator()(const transwarp::itask &task) const
Definition: transwarp.h:981
Node manipulation.
Definition: transwarp.h:477
void remove_listeners(transwarp::event_type) override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2305
Generates a graph.
Definition: transwarp.h:1005
The consume type. Used for tag dispatch.
Definition: transwarp.h:114
void schedule_all(transwarp::executor &) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2326
Removes the executor from the given task.
Definition: transwarp.h:1066
Definition: transwarp.h:928
void reset_priority_all() override
Resets the priority of all tasks to 0.
Definition: transwarp.h:1442
Definition: transwarp.h:139
The task has no parents.
just after a task was canceled (handle_event called on thread that task is run on) ...
TaskType task_type
The task type.
Definition: transwarp.h:2051
void set_exception(std::exception_ptr exception) override
Assigns an exception to this task.
Definition: transwarp.h:2357
void schedule_all(bool reset_all) override
Schedules all tasks in the graph for execution on the caller thread. The task-specific executors get ...
Definition: transwarp.h:1590
void ensure_task_was_scheduled() const
Checks if the task was scheduled and throws transwarp::control_error if it&#39;s not. ...
Definition: transwarp.h:1756
Sets parents and level of the node.
Definition: transwarp.h:977
value_task(std::string name, T &&value)
A value task is defined by name and value. name is optional, see overload Note: A value task must be ...
Definition: transwarp.h:2189
void set_executor(std::shared_ptr< transwarp::executor >) override
No-op because a value task never runs.
Definition: transwarp.h:2224
void set_executor_all(std::shared_ptr< transwarp::executor > executor) override
Assigns an executor to all tasks which takes precedence over the executor provided in schedule() or s...
Definition: transwarp.h:1400
bool was_scheduled() const noexceptoverride
Returns whether the task was scheduled and not reset afterwards. This means that the underlying futur...
Definition: transwarp.h:1648
void cancel(bool) noexceptoverride
No-op because a value task never runs.
Definition: transwarp.h:2391
just before a task is scheduled (handle_event called on thread of caller to schedule()) ...
void schedule_all() override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2323
void schedule_all(transwarp::executor &executor, bool reset_all) override
Schedules all tasks in the graph for execution using the provided executor. The task-specific executo...
Definition: transwarp.h:1599
std::string get_name() const override
Returns the name of the executor.
Definition: transwarp.h:1358
Assigns a priority to the given task.
Definition: transwarp.h:1074
void set_value(const typename transwarp::decay< result_type >::type &value) override
Assigns a value to this task.
Definition: transwarp.h:2347
void schedule(transwarp::executor &executor) override
Schedules this task for execution using the provided executor. The task-specific executor gets preced...
Definition: transwarp.h:1556
Assigns an executor to the given task.
Definition: transwarp.h:1054
Unvisits the given task.
Definition: transwarp.h:1138
void set_priority(std::size_t priority) override
Sets a task priority (defaults to 0). transwarp will not directly use this. This is only useful if so...
Definition: transwarp.h:2237
void cancel_all(bool enabled) noexceptoverride
If enabled then all pending tasks in the graph are canceled which will throw transwarp::task_canceled...
Definition: transwarp.h:1696
void remove_custom_data() override
Removes custom data from this task.
Definition: transwarp.h:1467
void set_custom_data_all(std::shared_ptr< void > custom_data) override
Assigns custom data to all tasks. transwarp will not directly use this. This is only useful if someth...
Definition: transwarp.h:2268
std::tuple< std::shared_future< ParentResults >...> get_futures(const std::tuple< std::shared_ptr< transwarp::task< ParentResults >>...> &input)
Returns the futures from the given tuple of tasks.
Definition: transwarp.h:628
void set_value(typename transwarp::decay< result_type >::type &&value) override
Assigns a value to this task.
Definition: transwarp.h:2352
void schedule_all(transwarp::schedule_type type, bool reset_all) override
Schedules all tasks in the graph for execution on the caller thread. The task-specific executors get ...
Definition: transwarp.h:1624
Scheduling according to a breadth-first search (default)
void schedule_all() override
Schedules all tasks in the graph for execution on the caller thread. The task-specific executors get ...
Definition: transwarp.h:1573
void set_executor(std::shared_ptr< transwarp::executor > executor) override
Assigns an executor to this task which takes precedence over the executor provided in schedule() or s...
Definition: transwarp.h:1389
void set_custom_data(std::shared_ptr< void > custom_data) override
Assigns custom data to this task. transwarp will not directly use this. This is only useful if someth...
Definition: transwarp.h:2259
The task class (non-void result type)
Definition: transwarp.h:403
value_task(T &&value)
This overload is for omitting the task name Note: A value task must be created using shared_ptr (beca...
Definition: transwarp.h:2197
Definition: transwarp.h:939
void schedule_all(transwarp::executor &executor, transwarp::schedule_type type, bool reset_all) override
Schedules all tasks in the graph for execution using the provided executor. The task-specific executo...
Definition: transwarp.h:1633
decltype(std::declval< Functor >()(std::declval< std::shared_future< arg_t >>())) type
using first type as reference
Definition: transwarp.h:1179
void reset_priority_all() override
Resets the priority of all tasks to 0.
Definition: transwarp.h:2253
void set_value(const typename transwarp::decay< result_type >::type &value) override
Assigns a value to this task. Scheduling will have no effect after a value has been set...
Definition: transwarp.h:1926
void set_priority(std::size_t priority) override
Sets a task priority (defaults to 0). transwarp will not directly use this. This is only useful if so...
Definition: transwarp.h:1422
const std::shared_ptr< std::string > & get_executor() const noexcept
The optional, task-specific executor (may be null)
Definition: transwarp.h:177
void assign_node_if(Functor &functor, std::shared_ptr< transwarp::node > node) noexcept
Assigns the node to the given functor if the functor is a subclass of transwarp::functor.
Definition: transwarp.h:1251
void reset() override
Resets this task.
Definition: transwarp.h:1672
const std::vector< std::shared_ptr< node > > & get_parents() const noexcept
The task&#39;s parents (may be empty)
Definition: transwarp.h:182
decltype(std::declval< Functor >()(std::declval< arg_t >())) type
using first type as reference
Definition: transwarp.h:1202
just before a task&#39;s functor is invoked (handle_event called on thread that task is run on) ...
Definition: transwarp.h:926
auto then(TaskType_, Functor_ &&functor) const -> decltype(std::make_shared< transwarp::task_impl< TaskType_, typename std::decay< Functor_ >::type, result_type >>(std::forward< Functor_ >(functor), std::dynamic_pointer_cast< transwarp::task< result_type >>(const_cast< value_task * >(this) ->shared_from_this())))
Creates a continuation to this task. Overload for omitting for task name.
Definition: transwarp.h:2218
The task&#39;s functor accepts the first parent future that becomes ready.
The consume_any type. Used for tag dispatch.
Definition: transwarp.h:118
ResultType result_type
The result type of this task.
Definition: transwarp.h:1922
void set_custom_data(std::shared_ptr< void > custom_data) override
Assigns custom data to this task. transwarp will not directly use this. This is only useful if someth...
Definition: transwarp.h:1450
bool was_scheduled() const noexceptoverride
Returns true because a value task is scheduled once on construction.
Definition: transwarp.h:2362
void execute(const std::function< void()> &functor, const std::shared_ptr< transwarp::node > &) override
Pushes the functor into the thread pool for asynchronous execution.
Definition: transwarp.h:1363
void wait_for_all(const std::vector< std::shared_ptr< transwarp::task< ParentResultType >>> &parents)
Waits for all parents to finish.
Definition: transwarp.h:673
The accept type. Used for tag dispatch.
Definition: transwarp.h:106
const std::shared_future< result_type > & get_future() const noexceptoverride
Returns the future associated to the underlying execution.
Definition: transwarp.h:1480
constexpr transwarp::accept_type accept
The accept task tag.
Definition: transwarp.h:107
Determines the result type of the Functor dispatching on the task type.
Definition: transwarp.h:1147
void schedule_all(transwarp::executor &, transwarp::schedule_type, bool) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2344
void remove_listeners() override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2308
bool has_result() const noexceptoverride
Returns whether this task contains a result.
Definition: transwarp.h:1667
The listener interface to listen to events raised by tasks.
Definition: transwarp.h:309
Exception thrown when a task is canceled.
Definition: transwarp.h:51
TaskType task_type
The task type.
Definition: transwarp.h:2112
void wait() const override
Waits for the task to complete. Should only be called if was_scheduled() is true, throws transwarp::c...
Definition: transwarp.h:1654
Scheduling according to a depth-first search.
void add_listener(transwarp::event_type event, std::shared_ptr< transwarp::listener > listener) override
Adds a new listener for the given event type only.
Definition: transwarp.h:1499
std::size_t get_level() const noexcept
The task level.
Definition: transwarp.h:162
std::shared_future< ResultType > make_future_with_value(Value &&value)
Returns a ready future with the given value as its state.
Definition: transwarp.h:1257
std::string get_name() const override
Returns the name of the executor.
Definition: transwarp.h:1332
void schedule() override
Schedules this task for execution on the caller thread. The task-specific executor gets precedence if...
Definition: transwarp.h:1539
void add_listener(std::shared_ptr< transwarp::listener >) override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2293
void add_listener(std::shared_ptr< transwarp::listener > listener) override
Adds a new listener for all event types.
Definition: transwarp.h:1490
void ensure_task_not_running() const
Checks if the task is currently running and throws transwarp::control_error if it is...
Definition: transwarp.h:1749
just before a task starts running (handle_event called on thread that task is run on) ...
Removes custom data from the given task.
Definition: transwarp.h:1106
void schedule_all(transwarp::executor &, bool) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2332
Resets the given task.
Definition: transwarp.h:1033
const std::shared_ptr< std::string > & get_name() const noexcept
The optional task name (may be null)
Definition: transwarp.h:172
A base class for a user-defined functor that needs access to the node associated to the task or a can...
Definition: transwarp.h:444
constexpr transwarp::consume_any_type consume_any
The consume_any task tag.
Definition: transwarp.h:119
bool is_canceled() const noexcept
Returns whether the associated task is canceled.
Definition: transwarp.h:197
A node carrying meta-data of a task.
Definition: transwarp.h:145
Exception thrown when a task is used in unintended ways.
Definition: transwarp.h:78
Resets the priority of the given task.
Definition: transwarp.h:1086
void schedule() override
No-op because a value task never runs.
Definition: transwarp.h:2311
void add_listener(transwarp::event_type, std::shared_ptr< transwarp::listener >) override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2296
void wait() const override
No-op because a value task never runs.
Definition: transwarp.h:2367
void schedule_all(transwarp::executor &executor, transwarp::schedule_type type) override
Schedules all tasks in the graph for execution using the provided executor. The task-specific executo...
Definition: transwarp.h:1615
std::size_t get_priority() const noexcept
The task priority (defaults to 0)
Definition: transwarp.h:187
const std::shared_ptr< transwarp::node > & get_parent() const noexcept
Returns the parent node.
Definition: transwarp.h:250
A task proxy for non-void result type.
Definition: transwarp.h:1916
void transwarp_cancel_point() const
If the associated task is canceled then this will throw transwarp::task_canceled which will stop the ...
Definition: transwarp.h:458
Returns the result type of a std::shared_future&lt;T&gt;
Definition: transwarp.h:396
The base task class that contains the functionality that can be used with all result types (void and ...
Definition: transwarp.h:1378
Definition: transwarp.h:614
task_impl(F &&functor, std::vector< std::shared_ptr< transwarp::task< P >>> parents)
This overload is for omitting the task name Note: A task must be created using shared_ptr (because of...
Definition: transwarp.h:2146
The task&#39;s functor consumes all parent results.
auto make_value_task(std::string name, Value &&value) -> decltype(std::make_shared< transwarp::value_task< typename transwarp::decay< Value >::type >>(std::move(name), std::forward< Value >(value)))
A factory function to create a new value task.
Definition: transwarp.h:2472
just after a task has finished running (handle_event called on thread that task is run on) ...
void remove_listener(const std::shared_ptr< transwarp::listener > &) override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2299
void set_priority_all(std::size_t priority) override
Sets a priority to all tasks (defaults to 0). transwarp will not directly use this. This is only useful if something else is using the priority.
Definition: transwarp.h:2243
Base class for exceptions.
Definition: transwarp.h:42
void schedule_all(transwarp::schedule_type) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2335
task_impl(std::string name, F &&functor, std::shared_ptr< transwarp::task< ParentResults >>...parents)
A task is defined by name, functor, and parent tasks. name is optional, see overload Note: A task mus...
Definition: transwarp.h:2122
A callable to run a task given its parents.
Definition: transwarp.h:1297
constexpr transwarp::consume_type consume
The consume task tag.
Definition: transwarp.h:115
std::size_t get_id() const noexcept
The task ID.
Definition: transwarp.h:157
void schedule(transwarp::executor &, bool) override
No-op because a value task never runs.
Definition: transwarp.h:2320
A value task that stores a single value and doesn&#39;t require scheduling. Value tasks should be created...
Definition: transwarp.h:2175
void reset_priority() override
Resets the task priority to 0.
Definition: transwarp.h:2248
task_impl(std::string name, F &&functor, std::vector< std::shared_ptr< transwarp::task< P >>> parents)
A task is defined by name, functor, and parent tasks. name is optional, see overload Note: A task mus...
Definition: transwarp.h:2138
Result run_task(std::size_t node_id, const Task &task, Args &&...args)
Runs the task with the given arguments, hence, invoking the task&#39;s functor.
Definition: transwarp.h:648
void remove_listeners(transwarp::event_type event) override
Removes all listeners for the given event type.
Definition: transwarp.h:1523
void remove_listener(const std::shared_ptr< transwarp::listener > &listener) override
Removes the listener for all event types.
Definition: transwarp.h:1506
Determines the type of the parents.
Definition: transwarp.h:1284
const std::shared_ptr< transwarp::node > & transwarp_node() const noexcept
The node associated to the task.
Definition: transwarp.h:452
Parent wait_for_any(const std::shared_ptr< transwarp::task< ParentResults >> &...parents)
Waits for the first parent to finish.
Definition: transwarp.h:696
void reset_all() override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2388
void remove_listener(transwarp::event_type event, const std::shared_ptr< transwarp::listener > &listener) override
Removes the listener for the given event type only.
Definition: transwarp.h:1515
Assigns custom data to the given task.
Definition: transwarp.h:1094
The task&#39;s functor takes no arguments but waits for all parents to finish.
void set_exception(std::exception_ptr exception) override
Assigns an exception to this task. Scheduling will have no effect after an exception has been set...
Definition: transwarp.h:1640
void cancel_all_but_one(const std::shared_ptr< transwarp::task< OneResult >> &one, const std::vector< std::shared_ptr< transwarp::task< ParentResultType >>> &parents)
Cancels all tasks but one.
Definition: transwarp.h:735
Definition: transwarp.h:754
Removes reference and const from a type.
Definition: transwarp.h:389
void remove_listeners() override
Removes all listeners.
Definition: transwarp.h:1529
const std::shared_ptr< void > & get_custom_data() const noexcept
The custom task data (may be null)
Definition: transwarp.h:192
void call_with_each(const Functor &f, const std::tuple< std::shared_ptr< transwarp::task< ParentResults >>...> &t)
Calls the functor with every element in the tuple.
Definition: transwarp.h:958
void reset_priority() override
Resets the task priority to 0.
Definition: transwarp.h:1436
typename transwarp::detail::result< TaskType, Functor, ParentResults...>::type result_type
The result type of this task.
Definition: transwarp.h:2115
void schedule_all(transwarp::executor &, transwarp::schedule_type) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2338
void schedule_all(transwarp::schedule_type, bool) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2341
An edge between two nodes.
Definition: transwarp.h:236
const std::shared_ptr< transwarp::node > & get_child() const noexcept
Returns the child node.
Definition: transwarp.h:255
void schedule_all(transwarp::schedule_type type) override
Schedules all tasks in the graph for execution on the caller thread. The task-specific executors get ...
Definition: transwarp.h:1607
std::vector< transwarp::edge > get_graph() const override
Returns the graph of the task structure. This is mainly for visualizing the tasks and their interdepe...
Definition: transwarp.h:1704
void set_value(typename transwarp::decay< result_type >::type &value) override
Assigns a value to this task. Scheduling will have no effect after a value has been set...
Definition: transwarp.h:1995
void schedule(transwarp::executor &) override
No-op because a value task never runs.
Definition: transwarp.h:2314
void reset_all() override
Resets all tasks in the graph.
Definition: transwarp.h:1680
Definition: transwarp.h:745
ResultType result_type
The result type of this task.
Definition: transwarp.h:2182
Executor for parallel execution. Uses a simple thread pool.
Definition: transwarp.h:1344
The wait_any type. Used for tag dispatch.
Definition: transwarp.h:126
TaskType task_type
The task type.
Definition: transwarp.h:1919
void set_priority_all(std::size_t priority) override
Sets a priority to all tasks (defaults to 0). transwarp will not directly use this. This is only useful if something else is using the priority (e.g. a custom executor)
Definition: transwarp.h:1429
void schedule(bool reset) override
Schedules this task for execution on the caller thread. The task-specific executor gets precedence if...
Definition: transwarp.h:1548
virtual std::string get_name() const =0
Is supposed to return the name of the executor.
auto then(TaskType_, Functor_ &&functor) const -> decltype(std::make_shared< transwarp::task_impl< TaskType_, typename std::decay< Functor_ >::type, result_type >>(std::forward< Functor_ >(functor), std::dynamic_pointer_cast< transwarp::task< result_type >>(const_cast< task_impl * >(this) ->shared_from_this())))
Creates a continuation to this task. Overload for omitting for task name.
Definition: transwarp.h:2159
std::string to_string(const transwarp::task_type &type)
String conversion for the task_type enumeration.
Definition: transwarp.h:87
virtual void execute(const std::function< void()> &functor, const std::shared_ptr< transwarp::node > &node)=0
Is supposed to run a task which is wrapped by the functor. The functor only captures two smart pointe...
void execute(const std::function< void()> &functor, const std::shared_ptr< transwarp::node > &) override
Runs the functor on the current thread.
Definition: transwarp.h:1337
void remove_executor() override
Removes the executor from this task.
Definition: transwarp.h:1407
The accept_any type. Used for tag dispatch.
Definition: transwarp.h:110
transwarp::task_type get_type() const noexcept
The task type.
Definition: transwarp.h:167
virtual void handle_event(transwarp::event_type event, const std::shared_ptr< transwarp::node > &node)=0
This may be called from arbitrary threads depending on the event type (see transwarp::event_type) ...
bool is_ready() const override
Returns true because a value task is always ready.
Definition: transwarp.h:2370
constexpr transwarp::wait_type wait
The wait task tag.
Definition: transwarp.h:123
The root type. Used for tag dispatch.
Definition: transwarp.h:102
The task&#39;s functor consumes the first parent result that becomes ready.
A task representing a piece of work given by functor and parent tasks. By connecting tasks a directed...
Definition: transwarp.h:2109
void remove_listener(transwarp::event_type, const std::shared_ptr< transwarp::listener > &) override
No-op because a value task doesn&#39;t raise events.
Definition: transwarp.h:2302
The wait type. Used for tag dispatch.
Definition: transwarp.h:122
void cancel(bool enabled) noexceptoverride
If enabled then this task is canceled which will throw transwarp::task_canceled when retrieving the t...
Definition: transwarp.h:1689
Schedules using the given executor.
Definition: transwarp.h:1020
Result call(std::size_t node_id, const Task &task, const std::tuple< std::shared_ptr< transwarp::task< ParentResults >>...> &parents)
Calls the functor of the given task with the results from the tuple of parents. Throws transwarp::tas...
Definition: transwarp.h:911
constexpr transwarp::root_type root
The root task tag.
Definition: transwarp.h:103
void remove_custom_data() override
Removes custom data from this task.
Definition: transwarp.h:2273
void set_value(typename transwarp::decay< result_type >::type &&value) override
Assigns a value to this task. Scheduling will have no effect after a value has been set...
Definition: transwarp.h:1932
void schedule_all(transwarp::executor &executor) override
Schedules all tasks in the graph for execution using the provided executor. The task-specific executo...
Definition: transwarp.h:1581
static Result work(std::size_t node_id, const Task &task, const std::tuple< std::shared_ptr< transwarp::task< ParentResults >>...> &parents)
Definition: transwarp.h:838
schedule_type
Determines in which order tasks are scheduled in the graph.
Definition: transwarp.h:319
The task&#39;s functor accepts all parent futures.
Applies final bookkeeping to the task.
Definition: transwarp.h:993
void remove_executor_all() override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2233
void schedule(transwarp::executor &executor, bool reset) override
Schedules this task for execution using the provided executor. The task-specific executor gets preced...
Definition: transwarp.h:1565
std::vector< transwarp::edge > get_graph() const override
Returns an empty graph because a value task doesn&#39;t have parents.
Definition: transwarp.h:2397
const std::shared_ptr< transwarp::node > & get_node() const noexceptoverride
Returns the associated node.
Definition: transwarp.h:1485
task_type
The possible task types.
Definition: transwarp.h:30
void set_value() override
Assigns a value to this task. Scheduling will have no effect after a call to this. Calling reset() will reset this and re-enable scheduling.
Definition: transwarp.h:2058
event_type
The task events that can be subscribed to using the below listener interface.
Definition: transwarp.h:298
The task&#39;s functor takes no arguments but waits for the first parent to finish.
Exception thrown when an invalid parameter was passed to a function.
Definition: transwarp.h:69
void remove_custom_data_all() override
Removes custom data from all tasks.
Definition: transwarp.h:1473
auto make_task(TaskType, std::string name, Functor &&functor, std::shared_ptr< Parents >...parents) -> decltype(std::make_shared< transwarp::task_impl< TaskType, typename std::decay< Functor >::type, typename Parents::result_type...>>(std::move(name), std::forward< Functor >(functor), std::move(parents)...))
A factory function to create a new task.
Definition: transwarp.h:2442
void reset() override
No-op because a value task never runs.
Definition: transwarp.h:2385
std::shared_future< void > make_ready_future()
Returns a ready future.
Definition: transwarp.h:1264
void set_executor_all(std::shared_ptr< transwarp::executor >) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2227
constexpr transwarp::accept_any_type accept_any
The accept_any task tag.
Definition: transwarp.h:111
const std::shared_future< result_type > & get_future() const noexceptoverride
Returns the future associated to the underlying execution.
Definition: transwarp.h:2283
Cancels or resumes the given task.
Definition: transwarp.h:1042
void remove_executor() override
No-op because a value task never runs.
Definition: transwarp.h:2230
void schedule(bool) override
No-op because a value task never runs.
Definition: transwarp.h:2317
void schedule_all(bool) override
No-op because a value task never runs and doesn&#39;t have parents.
Definition: transwarp.h:2329
Visits the given task using the visitor given in the constructor.
Definition: transwarp.h:1126
Pushes the given task into the vector of tasks.
Definition: transwarp.h:1114
Executor for sequential execution. Runs functors sequentially on the same thread. ...
Definition: transwarp.h:1320
auto then(TaskType_, std::string name, Functor_ &&functor) const -> decltype(std::make_shared< transwarp::task_impl< TaskType_, typename std::decay< Functor_ >::type, result_type >>(std::move(name), std::forward< Functor_ >(functor), std::dynamic_pointer_cast< transwarp::task< result_type >>(const_cast< value_task * >(this) ->shared_from_this())))
Creates a continuation to this task.
Definition: transwarp.h:2211
bool has_result() const noexceptoverride
Returns true because a value task always contains a result.
Definition: transwarp.h:2375
std::shared_future< ResultType > make_future_with_exception(std::exception_ptr exception)
Returns a ready future with the given exception as its state.
Definition: transwarp.h:1272
void remove_executor_all() override
Removes the executor from all tasks.
Definition: transwarp.h:1414
const std::shared_ptr< transwarp::node > & get_node() const noexceptoverride
Returns the associated node.
Definition: transwarp.h:2288
bool is_ready() const override
Returns whether the task has finished processing. Should only be called if was_scheduled() is true...
Definition: transwarp.h:1661
task_impl(F &&functor, std::shared_ptr< transwarp::task< ParentResults >>...parents)
This overload is for omitting the task name Note: A task must be created using shared_ptr (because of...
Definition: transwarp.h:2130
auto then(TaskType_, std::string name, Functor_ &&functor) const -> decltype(std::make_shared< transwarp::task_impl< TaskType_, typename std::decay< Functor_ >::type, result_type >>(std::move(name), std::forward< Functor_ >(functor), std::dynamic_pointer_cast< transwarp::task< result_type >>(const_cast< task_impl * >(this) ->shared_from_this())))
Creates a continuation to this task.
Definition: transwarp.h:2152
An interface for the task class.
Definition: transwarp.h:326