Taskflow  2.7.0
task.hpp
1 #pragma once
2 
3 #include "graph.hpp"
4 
5 namespace tf {
6 
7 // ----------------------------------------------------------------------------
8 // Task Types
9 // ----------------------------------------------------------------------------
10 
16 enum TaskType {
17  PLACEHOLDER_TASK = Node::PLACEHOLDER_WORK,
18 #ifdef TF_ENABLE_CUDA
19  CUDAFLOW_TASK = Node::CUDAFLOW_WORK,
20 #endif
21  STATIC_TASK = Node::STATIC_WORK,
22  DYNAMIC_TASK = Node::DYNAMIC_WORK,
23  CONDITION_TASK = Node::CONDITION_WORK,
24  MODULE_TASK = Node::MODULE_WORK,
25  ASYNC_TASK = Node::ASYNC_WORK,
26  NUM_TASK_TYPES
27 };
28 
32 inline const char* task_type_to_string(TaskType type) {
33 
34  const char* val;
35 
36  switch(type) {
37  case PLACEHOLDER_TASK: val = "placeholder"; break;
38 #ifdef TF_ENABLE_CUDA
39  case CUDAFLOW_TASK: val = "cudaflow"; break;
40 #endif
41  case STATIC_TASK: val = "static"; break;
42  case DYNAMIC_TASK: val = "subflow"; break;
43  case CONDITION_TASK: val = "condition"; break;
44  case MODULE_TASK: val = "module"; break;
45  case ASYNC_TASK: val = "async"; break;
46  default: val = "undefined"; break;
47  }
48 
49  return val;
50 }
51 
52 // ----------------------------------------------------------------------------
53 // Task Traits
54 // ----------------------------------------------------------------------------
55 
63 template <typename C>
64 constexpr bool is_static_task_v = is_invocable_r_v<void, C> &&
65  !is_invocable_r_v<int, C>;
66 
74 template <typename C>
75 constexpr bool is_dynamic_task_v = is_invocable_r_v<void, C, Subflow&>;
76 
84 template <typename C>
85 constexpr bool is_condition_task_v = is_invocable_r_v<int, C>;
86 
87 #ifdef TF_ENABLE_CUDA
88 
95 template <typename C>
96 constexpr bool is_cudaflow_task_v = is_invocable_r_v<void, C, cudaFlow&>;
97 #endif
98 
99 
100 
101 // ----------------------------------------------------------------------------
102 // Task
103 // ----------------------------------------------------------------------------
104 
115 class Task {
116 
117  friend class FlowBuilder;
118  friend class Taskflow;
119  friend class TaskView;
120 
121  public:
122 
126  Task() = default;
127 
131  Task(const Task& other);
132 
136  Task& operator = (const Task&);
137 
142 
146  bool operator == (const Task& rhs) const;
147 
151  bool operator != (const Task& rhs) const;
152 
156  const std::string& name() const;
157 
161  size_t num_successors() const;
162 
166  size_t num_dependents() const;
167 
171  size_t num_strong_dependents() const;
172 
176  size_t num_weak_dependents() const;
177 
185  Task& name(const std::string& name);
186 
196  template <typename C>
197  std::enable_if_t<is_static_task_v<C>, Task>& work(C&& callable);
198 
208  template <typename C>
209  std::enable_if_t<is_dynamic_task_v<C>, Task>& work(C&& callable);
210 
220  template <typename C>
221  std::enable_if_t<is_condition_task_v<C>, Task>& work(C&& callable);
222 
223 #ifdef TF_ENABLE_CUDA
224 
233  template <typename C>
234  std::enable_if_t<is_cudaflow_task_v<C>, Task>& work(C&& callable);
235 #endif
236 
244  Task& composed_of(Taskflow& taskflow);
245 
255  template <typename... Ts>
256  Task& precede(Ts&&... tasks);
257 
267  template <typename... Ts>
268  Task& succeed(Ts&&... tasks);
269 
273  void reset();
274 
278  void reset_work();
279 
283  bool empty() const;
284 
288  bool has_work() const;
289 
293  template <typename V>
294  void for_each_successor(V&& visitor) const;
295 
299  template <typename V>
300  void for_each_dependent(V&& visitor) const;
301 
305  size_t hash_value() const;
306 
310  TaskType type() const;
311 
312  private:
313 
314  Task(Node*);
315 
316  Node* _node {nullptr};
317 
318  template <typename T>
319  void _precede(T&&);
320 
321  template <typename T, typename... Rest>
322  void _precede(T&&, Rest&&...);
323 
324  template <typename T>
325  void _succeed(T&&);
326 
327  template <typename T, typename... Rest>
328  void _succeed(T&&, Rest&&...);
329 };
330 
331 // Constructor
332 inline Task::Task(Node* node) : _node {node} {
333 }
334 
335 // Constructor
336 inline Task::Task(const Task& rhs) : _node {rhs._node} {
337 }
338 
339 // Function: precede
340 template <typename... Ts>
341 Task& Task::precede(Ts&&... tasks) {
342  //(_node->_precede(tgts._node), ...);
343  _precede(std::forward<Ts>(tasks)...);
344  return *this;
345 }
346 
348 // Procedure: _precede
349 template <typename T>
350 void Task::_precede(T&& other) {
351  _node->_precede(other._node);
352 }
353 
355 // Procedure: _precede
356 template <typename T, typename... Ts>
357 void Task::_precede(T&& task, Ts&&... others) {
358  _precede(std::forward<T>(task));
359  _precede(std::forward<Ts>(others)...);
360 }
361 
362 // Function: succeed
363 template <typename... Ts>
364 Task& Task::succeed(Ts&&... tasks) {
365  //(tasks._node->_precede(_node), ...);
366  _succeed(std::forward<Ts>(tasks)...);
367  return *this;
368 }
369 
371 // Procedure: succeed
372 template <typename T>
373 void Task::_succeed(T&& other) {
374  other._node->_precede(_node);
375 }
376 
378 // Procedure: _succeed
379 template <typename T, typename... Ts>
380 void Task::_succeed(T&& task, Ts&&... others) {
381  _succeed(std::forward<T>(task));
382  _succeed(std::forward<Ts>(others)...);
383 }
384 
385 // Function: composed_of
387  _node->_handle.emplace<Node::ModuleWork>(&tf);
388  return *this;
389 }
390 
391 // Operator =
392 inline Task& Task::operator = (const Task& rhs) {
393  _node = rhs._node;
394  return *this;
395 }
396 
397 // Operator =
399  _node = ptr;
400  return *this;
401 }
402 
403 // Operator ==
404 inline bool Task::operator == (const Task& rhs) const {
405  return _node == rhs._node;
406 }
407 
408 // Operator !=
409 inline bool Task::operator != (const Task& rhs) const {
410  return _node != rhs._node;
411 }
412 
413 // Function: name
414 inline Task& Task::name(const std::string& name) {
415  _node->_name = name;
416  return *this;
417 }
418 
419 // Procedure: reset
420 inline void Task::reset() {
421  _node = nullptr;
422 }
423 
424 // Procedure: reset_work
425 inline void Task::reset_work() {
426  _node->_handle = nstd::monostate{};
427 }
428 
429 // Function: name
430 inline const std::string& Task::name() const {
431  return _node->_name;
432 }
433 
434 // Function: num_dependents
435 inline size_t Task::num_dependents() const {
436  return _node->num_dependents();
437 }
438 
439 // Function: num_strong_dependents
440 inline size_t Task::num_strong_dependents() const {
441  return _node->num_strong_dependents();
442 }
443 
444 // Function: num_weak_dependents
445 inline size_t Task::num_weak_dependents() const {
446  return _node->num_weak_dependents();
447 }
448 
449 // Function: num_successors
450 inline size_t Task::num_successors() const {
451  return _node->num_successors();
452 }
453 
454 // Function: empty
455 inline bool Task::empty() const {
456  return _node == nullptr;
457 }
458 
459 // Function: has_work
460 inline bool Task::has_work() const {
461  return _node ? _node->_handle.index() != 0 : false;
462 }
463 
464 // Function: task_type
465 inline TaskType Task::type() const {
466  return static_cast<TaskType>(_node->_handle.index());
467 }
468 
469 // Function: for_each_successor
470 template <typename V>
471 void Task::for_each_successor(V&& visitor) const {
472  for(size_t i=0; i<_node->_successors.size(); ++i) {
473  visitor(Task(_node->_successors[i]));
474  }
475 }
476 
477 // Function: for_each_dependent
478 template <typename V>
479 void Task::for_each_dependent(V&& visitor) const {
480  for(size_t i=0; i<_node->_dependents.size(); ++i) {
481  visitor(Task(_node->_dependents[i]));
482  }
483 }
484 
485 // Function: hash_value
486 inline size_t Task::hash_value() const {
487  return std::hash<Node*>{}(_node);
488 }
489 
490 // Function: work
491 // assign a static work
492 template <typename C>
493 std::enable_if_t<is_static_task_v<C>, Task>& Task::work(C&& c) {
494  _node->_handle.emplace<Node::StaticWork>(std::forward<C>(c));
495  return *this;
496 }
497 
498 // Function: work
499 // assigns a dynamic work
500 template <typename C>
501 std::enable_if_t<is_dynamic_task_v<C>, Task>& Task::work(C&& c) {
502  _node->_handle.emplace<Node::DynamicWork>(std::forward<C>(c));
503  return *this;
504 }
505 
506 // Function: work
507 // assigns a condition work
508 template <typename C>
509 std::enable_if_t<is_condition_task_v<C>, Task>& Task::work(C&& c) {
510  _node->_handle.emplace<Node::ConditionWork>(std::forward<C>(c));
511  return *this;
512 }
513 
514 #ifdef TF_ENABLE_CUDA
515 // Function: work
516 // assigns a cudaFlow work
517 template <typename C>
518 std::enable_if_t<is_cudaflow_task_v<C>, Task>& Task::work(C&& c) {
519  _node->_handle.emplace<Node::cudaFlowWork>(std::forward<C>(c));
520  return *this;
521 }
522 #endif
523 
524 // ----------------------------------------------------------------------------
525 
531 class TaskView {
532 
533  friend class Executor;
534 
535  public:
536 
540  TaskView() = default;
541 
545  TaskView(const Task& task);
546 
550  TaskView(const TaskView& other);
551 
555  TaskView& operator = (const TaskView& other);
556 
560  TaskView& operator = (const Task& other);
561 
566 
570  bool operator == (const TaskView&) const;
571 
575  bool operator != (const TaskView&) const;
576 
580  const std::string& name() const;
581 
585  size_t num_successors() const;
586 
590  size_t num_dependents() const;
591 
595  size_t num_strong_dependents() const;
596 
600  size_t num_weak_dependents() const;
601 
605  void reset();
606 
610  bool empty() const;
611 
615  template <typename V>
616  void for_each_successor(V&& visitor) const;
617 
621  template <typename V>
622  void for_each_dependent(V&& visitor) const;
623 
627  TaskType type() const;
628 
629  private:
630 
631  TaskView(Node*);
632 
633  Node* _node {nullptr};
634 };
635 
636 // Constructor
637 inline TaskView::TaskView(Node* node) : _node {node} {
638 }
639 
640 // Constructor
641 inline TaskView::TaskView(const TaskView& rhs) : _node {rhs._node} {
642 }
643 
644 // Constructor
645 inline TaskView::TaskView(const Task& task) : _node {task._node} {
646 }
647 
648 // Operator =
650  _node = rhs._node;
651  return *this;
652 }
653 
654 // Operator =
655 inline TaskView& TaskView::operator = (const Task& rhs) {
656  _node = rhs._node;
657  return *this;
658 }
659 
660 // Operator =
662  _node = ptr;
663  return *this;
664 }
665 
666 // Function: name
667 inline const std::string& TaskView::name() const {
668  return _node->_name;
669 }
670 
671 // Function: num_dependents
672 inline size_t TaskView::num_dependents() const {
673  return _node->num_dependents();
674 }
675 
676 // Function: num_strong_dependents
677 inline size_t TaskView::num_strong_dependents() const {
678  return _node->num_strong_dependents();
679 }
680 
681 // Function: num_weak_dependents
682 inline size_t TaskView::num_weak_dependents() const {
683  return _node->num_weak_dependents();
684 }
685 
686 // Function: num_successors
687 inline size_t TaskView::num_successors() const {
688  return _node->num_successors();
689 }
690 
691 // Function: reset
692 inline void TaskView::reset() {
693  _node = nullptr;
694 }
695 
696 // Function: empty
697 inline bool TaskView::empty() const {
698  return _node == nullptr;
699 }
700 
701 // Function: type
702 inline TaskType TaskView::type() const {
703  return static_cast<TaskType>(_node->_handle.index());
704 }
705 
706 // Operator ==
707 inline bool TaskView::operator == (const TaskView& rhs) const {
708  return _node == rhs._node;
709 }
710 
711 // Operator !=
712 inline bool TaskView::operator != (const TaskView& rhs) const {
713  return _node != rhs._node;
714 }
715 
716 // Function: for_each_successor
717 template <typename V>
718 void TaskView::for_each_successor(V&& visitor) const {
719  for(size_t i=0; i<_node->_successors.size(); ++i) {
720  visitor(TaskView(_node->_successors[i]));
721  }
722 }
723 
724 // Function: for_each_dependent
725 template <typename V>
726 void TaskView::for_each_dependent(V&& visitor) const {
727  for(size_t i=0; i<_node->_dependents.size(); ++i) {
728  visitor(TaskView(_node->_dependents[i]));
729  }
730 }
731 
732 } // end of namespace tf. ---------------------------------------------------
733 
734 namespace std {
735 
742 template <>
743 struct hash<tf::Task> {
744  auto operator() (const tf::Task& task) const noexcept {
745  return task.hash_value();
746  }
747 };
748 
749 } // end of namespace std ----------------------------------------------------
750 
751 
752 
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:435
void reset_work()
resets the associated work to a placeholder
Definition: task.hpp:425
void reset()
resets the task handle to null
Definition: task.hpp:420
TaskView()=default
constructs an empty task view
bool operator!=(const TaskView &) const
compares if two taskviews are associated with different tasks
Definition: task.hpp:712
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:726
TaskType type() const
queries the task type
Definition: task.hpp:702
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:682
Task & composed_of(Taskflow &taskflow)
creates a module task from a taskflow
Definition: task.hpp:386
size_t num_successors() const
queries the number of successors of the task
Definition: task.hpp:687
Definition: error.hpp:9
bool operator==(const Task &rhs) const
compares if two tasks are associated with the same graph node
Definition: task.hpp:404
std::enable_if_t< is_static_task_v< C >, Task > & work(C &&callable)
assigns a static task
Definition: task.hpp:493
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition: task.hpp:364
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:718
bool operator!=(const Task &rhs) const
compares if two tasks are not associated with the same graph node
Definition: task.hpp:409
bool empty() const
queries if the task view is empty
Definition: task.hpp:697
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:677
Task & operator=(const Task &)
replaces the contents with a copy of the other task
Definition: task.hpp:392
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:479
main entry to create a task dependency graph
Definition: core/taskflow.hpp:18
const std::string & name() const
queries the name of the task
Definition: task.hpp:430
class to access task information from the observer interface
Definition: task.hpp:531
T operator()(T... args)
bool empty() const
queries if the task handle points to a task node
Definition: task.hpp:455
void reset()
resets to an empty view
Definition: task.hpp:692
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:440
building methods of a task dependency graph
Definition: flow_builder.hpp:13
size_t num_successors() const
queries the number of successors of the task
Definition: task.hpp:450
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:445
handle to a node in a task dependency graph
Definition: task.hpp:115
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition: task.hpp:341
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:471
Task()=default
constructs an empty task
execution interface for running a taskflow graph
Definition: executor.hpp:24
TaskView & operator=(const TaskView &other)
replaces the contents with a copy of the other task
Definition: task.hpp:649
size_t hash_value() const
obtains a hash value of the underlying node
Definition: task.hpp:486
TaskType type() const
returns the task type
Definition: task.hpp:465
bool operator==(const TaskView &) const
compares if two taskviews are associated with the same task
Definition: task.hpp:707
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:672
bool has_work() const
queries if the task has a work assigned
Definition: task.hpp:460
const std::string & name() const
queries the name of the task
Definition: task.hpp:667