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