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