Taskflow  2.4-master-branch
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  NUM_TASK_TYPES
26 };
27 
31 inline const char* task_type_to_string(TaskType type) {
32 
33  const char* val;
34 
35  switch(type) {
36  case PLACEHOLDER_TASK: val = "placeholder"; break;
37 #ifdef TF_ENABLE_CUDA
38  case CUDAFLOW_TASK: val = "cudaflow"; break;
39 #endif
40  case STATIC_TASK: val = "static"; break;
41  case DYNAMIC_TASK: val = "subflow"; break;
42  case CONDITION_TASK: val = "condition"; break;
43  case MODULE_TASK: val = "module"; break;
44  default: val = "undefined"; break;
45  }
46 
47  return val;
48 }
49 
50 // ----------------------------------------------------------------------------
51 // Task Traits
52 // ----------------------------------------------------------------------------
53 
61 template <typename C>
62 constexpr bool is_static_task_v = is_invocable_r_v<void, C> &&
63  !is_invocable_r_v<int, C>;
64 
72 template <typename C>
73 constexpr bool is_dynamic_task_v = is_invocable_r_v<void, C, Subflow&>;
74 
82 template <typename C>
83 constexpr bool is_condition_task_v = is_invocable_r_v<int, C>;
84 
85 #ifdef TF_ENABLE_CUDA
86 
93 template <typename C>
94 constexpr bool is_cudaflow_task_v = is_invocable_r_v<void, C, cudaFlow&>;
95 #endif
96 
97 
98 
99 // ----------------------------------------------------------------------------
100 // Task
101 // ----------------------------------------------------------------------------
102 
113 class Task {
114 
115  friend class FlowBuilder;
116  friend class Taskflow;
117  friend class TaskView;
118 
119  public:
120 
124  Task() = default;
125 
129  Task(const Task& other);
130 
134  Task& operator = (const Task&);
135 
140 
144  bool operator == (const Task& rhs) const;
145 
149  bool operator != (const Task& rhs) const;
150 
154  const std::string& name() const;
155 
159  size_t num_successors() const;
160 
164  size_t num_dependents() const;
165 
169  size_t num_strong_dependents() const;
170 
174  size_t num_weak_dependents() const;
175 
183  Task& name(const std::string& name);
184 
194  template <typename C>
195  std::enable_if_t<is_static_task_v<C>, Task>& work(C&& callable);
196 
206  template <typename C>
207  std::enable_if_t<is_dynamic_task_v<C>, Task>& work(C&& callable);
208 
218  template <typename C>
219  std::enable_if_t<is_condition_task_v<C>, Task>& work(C&& callable);
220 
221 #ifdef TF_ENABLE_CUDA
222 
231  template <typename C>
232  std::enable_if_t<is_cudaflow_task_v<C>, Task>& work(C&& callable);
233 #endif
234 
242  Task& composed_of(Taskflow& taskflow);
243 
253  template <typename... Ts>
254  Task& precede(Ts&&... tasks);
255 
265  template <typename... Ts>
266  Task& succeed(Ts&&... tasks);
267 
271  void reset();
272 
276  void reset_work();
277 
281  bool empty() const;
282 
286  bool has_work() const;
287 
291  template <typename V>
292  void for_each_successor(V&& visitor) const;
293 
297  template <typename V>
298  void for_each_dependent(V&& visitor) const;
299 
303  size_t hash_value() const;
304 
308  TaskType type() const;
309 
310  private:
311 
312  Task(Node*);
313 
314  Node* _node {nullptr};
315 
316  template <typename T>
317  void _precede(T&&);
318 
319  template <typename T, typename... Rest>
320  void _precede(T&&, Rest&&...);
321 
322  template <typename T>
323  void _succeed(T&&);
324 
325  template <typename T, typename... Rest>
326  void _succeed(T&&, Rest&&...);
327 };
328 
329 // Constructor
330 inline Task::Task(Node* node) : _node {node} {
331 }
332 
333 // Constructor
334 inline Task::Task(const Task& rhs) : _node {rhs._node} {
335 }
336 
337 // Function: precede
338 template <typename... Ts>
339 Task& Task::precede(Ts&&... tasks) {
340  //(_node->_precede(tgts._node), ...);
341  _precede(std::forward<Ts>(tasks)...);
342  return *this;
343 }
344 
346 // Procedure: _precede
347 template <typename T>
348 void Task::_precede(T&& other) {
349  _node->_precede(other._node);
350 }
351 
353 // Procedure: _precede
354 template <typename T, typename... Ts>
355 void Task::_precede(T&& task, Ts&&... others) {
356  _precede(std::forward<T>(task));
357  _precede(std::forward<Ts>(others)...);
358 }
359 
360 // Function: succeed
361 template <typename... Ts>
362 Task& Task::succeed(Ts&&... tasks) {
363  //(tasks._node->_precede(_node), ...);
364  _succeed(std::forward<Ts>(tasks)...);
365  return *this;
366 }
367 
369 // Procedure: succeed
370 template <typename T>
371 void Task::_succeed(T&& other) {
372  other._node->_precede(_node);
373 }
374 
376 // Procedure: _succeed
377 template <typename T, typename... Ts>
378 void Task::_succeed(T&& task, Ts&&... others) {
379  _succeed(std::forward<T>(task));
380  _succeed(std::forward<Ts>(others)...);
381 }
382 
383 // Function: composed_of
385  _node->_handle.emplace<Node::ModuleWork>(&tf);
386  return *this;
387 }
388 
389 // Operator =
390 inline Task& Task::operator = (const Task& rhs) {
391  _node = rhs._node;
392  return *this;
393 }
394 
395 // Operator =
397  _node = ptr;
398  return *this;
399 }
400 
401 // Operator ==
402 inline bool Task::operator == (const Task& rhs) const {
403  return _node == rhs._node;
404 }
405 
406 // Operator !=
407 inline bool Task::operator != (const Task& rhs) const {
408  return _node != rhs._node;
409 }
410 
411 // Function: name
412 inline Task& Task::name(const std::string& name) {
413  _node->_name = name;
414  return *this;
415 }
416 
417 // Procedure: reset
418 inline void Task::reset() {
419  _node = nullptr;
420 }
421 
422 // Procedure: reset_work
423 inline void Task::reset_work() {
424  _node->_handle = nstd::monostate{};
425 }
426 
427 // Function: name
428 inline const std::string& Task::name() const {
429  return _node->_name;
430 }
431 
432 // Function: num_dependents
433 inline size_t Task::num_dependents() const {
434  return _node->num_dependents();
435 }
436 
437 // Function: num_strong_dependents
438 inline size_t Task::num_strong_dependents() const {
439  return _node->num_strong_dependents();
440 }
441 
442 // Function: num_weak_dependents
443 inline size_t Task::num_weak_dependents() const {
444  return _node->num_weak_dependents();
445 }
446 
447 // Function: num_successors
448 inline size_t Task::num_successors() const {
449  return _node->num_successors();
450 }
451 
452 // Function: empty
453 inline bool Task::empty() const {
454  return _node == nullptr;
455 }
456 
457 // Function: has_work
458 inline bool Task::has_work() const {
459  return _node ? _node->_handle.index() != 0 : false;
460 }
461 
462 // Function: task_type
463 inline TaskType Task::type() const {
464  return static_cast<TaskType>(_node->_handle.index());
465 }
466 
467 // Function: for_each_successor
468 template <typename V>
469 void Task::for_each_successor(V&& visitor) const {
470  for(size_t i=0; i<_node->_successors.size(); ++i) {
471  visitor(Task(_node->_successors[i]));
472  }
473 }
474 
475 // Function: for_each_dependent
476 template <typename V>
477 void Task::for_each_dependent(V&& visitor) const {
478  for(size_t i=0; i<_node->_dependents.size(); ++i) {
479  visitor(Task(_node->_dependents[i]));
480  }
481 }
482 
483 // Function: hash_value
484 inline size_t Task::hash_value() const {
485  return std::hash<Node*>{}(_node);
486 }
487 
488 // Function: work
489 // assign a static work
490 template <typename C>
491 std::enable_if_t<is_static_task_v<C>, Task>& Task::work(C&& c) {
492  _node->_handle.emplace<Node::StaticWork>(std::forward<C>(c));
493  return *this;
494 }
495 
496 // Function: work
497 // assigns a dynamic work
498 template <typename C>
499 std::enable_if_t<is_dynamic_task_v<C>, Task>& Task::work(C&& c) {
500  _node->_handle.emplace<Node::DynamicWork>(std::forward<C>(c));
501  return *this;
502 }
503 
504 // Function: work
505 // assigns a condition work
506 template <typename C>
507 std::enable_if_t<is_condition_task_v<C>, Task>& Task::work(C&& c) {
508  _node->_handle.emplace<Node::ConditionWork>(std::forward<C>(c));
509  return *this;
510 }
511 
512 #ifdef TF_ENABLE_CUDA
513 // Function: work
514 // assigns a cudaFlow work
515 template <typename C>
516 std::enable_if_t<is_cudaflow_task_v<C>, Task>& Task::work(C&& c) {
517  _node->_handle.emplace<Node::cudaFlowWork>(std::forward<C>(c));
518  return *this;
519 }
520 #endif
521 
522 // ----------------------------------------------------------------------------
523 
529 class TaskView {
530 
531  friend class Executor;
532 
533  public:
534 
538  TaskView() = default;
539 
543  TaskView(const Task& task);
544 
548  TaskView(const TaskView& other);
549 
553  TaskView& operator = (const TaskView& other);
554 
558  TaskView& operator = (const Task& other);
559 
564 
568  bool operator == (const TaskView&) const;
569 
573  bool operator != (const TaskView&) const;
574 
578  const std::string& name() const;
579 
583  size_t num_successors() const;
584 
588  size_t num_dependents() const;
589 
593  size_t num_strong_dependents() const;
594 
598  size_t num_weak_dependents() const;
599 
603  void reset();
604 
608  bool empty() const;
609 
613  template <typename V>
614  void for_each_successor(V&& visitor) const;
615 
619  template <typename V>
620  void for_each_dependent(V&& visitor) const;
621 
625  TaskType type() const;
626 
627  private:
628 
629  TaskView(Node*);
630 
631  Node* _node {nullptr};
632 };
633 
634 // Constructor
635 inline TaskView::TaskView(Node* node) : _node {node} {
636 }
637 
638 // Constructor
639 inline TaskView::TaskView(const TaskView& rhs) : _node {rhs._node} {
640 }
641 
642 // Constructor
643 inline TaskView::TaskView(const Task& task) : _node {task._node} {
644 }
645 
646 // Operator =
648  _node = rhs._node;
649  return *this;
650 }
651 
652 // Operator =
653 inline TaskView& TaskView::operator = (const Task& rhs) {
654  _node = rhs._node;
655  return *this;
656 }
657 
658 // Operator =
660  _node = ptr;
661  return *this;
662 }
663 
664 // Function: name
665 inline const std::string& TaskView::name() const {
666  return _node->_name;
667 }
668 
669 // Function: num_dependents
670 inline size_t TaskView::num_dependents() const {
671  return _node->num_dependents();
672 }
673 
674 // Function: num_strong_dependents
675 inline size_t TaskView::num_strong_dependents() const {
676  return _node->num_strong_dependents();
677 }
678 
679 // Function: num_weak_dependents
680 inline size_t TaskView::num_weak_dependents() const {
681  return _node->num_weak_dependents();
682 }
683 
684 // Function: num_successors
685 inline size_t TaskView::num_successors() const {
686  return _node->num_successors();
687 }
688 
689 // Function: reset
690 inline void TaskView::reset() {
691  _node = nullptr;
692 }
693 
694 // Function: empty
695 inline bool TaskView::empty() const {
696  return _node == nullptr;
697 }
698 
699 // Function: type
700 inline TaskType TaskView::type() const {
701  return static_cast<TaskType>(_node->_handle.index());
702 }
703 
704 // Operator ==
705 inline bool TaskView::operator == (const TaskView& rhs) const {
706  return _node == rhs._node;
707 }
708 
709 // Operator !=
710 inline bool TaskView::operator != (const TaskView& rhs) const {
711  return _node != rhs._node;
712 }
713 
714 // Function: for_each_successor
715 template <typename V>
716 void TaskView::for_each_successor(V&& visitor) const {
717  for(size_t i=0; i<_node->_successors.size(); ++i) {
718  visitor(TaskView(_node->_successors[i]));
719  }
720 }
721 
722 // Function: for_each_dependent
723 template <typename V>
724 void TaskView::for_each_dependent(V&& visitor) const {
725  for(size_t i=0; i<_node->_dependents.size(); ++i) {
726  visitor(TaskView(_node->_dependents[i]));
727  }
728 }
729 
730 } // end of namespace tf. ---------------------------------------------------
731 
732 namespace std {
733 
740 template <>
741 struct hash<tf::Task> {
742  auto operator() (const tf::Task& task) const noexcept {
743  return task.hash_value();
744  }
745 };
746 
747 } // end of namespace std ----------------------------------------------------
748 
749 
750 
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:433
void reset_work()
resets the associated work to a placeholder
Definition: task.hpp:423
void reset()
resets the task handle to null
Definition: task.hpp:418
TaskView()=default
constructs an empty task view
bool operator!=(const TaskView &) const
compares if two taskviews are associated with different tasks
Definition: task.hpp:710
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:724
TaskType type() const
queries the task type
Definition: task.hpp:700
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:680
Task & composed_of(Taskflow &taskflow)
creates a module task from a taskflow
Definition: task.hpp:384
size_t num_successors() const
queries the number of successors of the task
Definition: task.hpp:685
Definition: error.hpp:9
bool operator==(const Task &rhs) const
compares if two tasks are associated with the same graph node
Definition: task.hpp:402
std::enable_if_t< is_static_task_v< C >, Task > & work(C &&callable)
assigns a static task
Definition: task.hpp:491
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition: task.hpp:362
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:716
bool operator!=(const Task &rhs) const
compares if two tasks are not associated with the same graph node
Definition: task.hpp:407
bool empty() const
queries if the task view is empty
Definition: task.hpp:695
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:675
Task & operator=(const Task &)
replaces the contents with a copy of the other task
Definition: task.hpp:390
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:477
main entry to create a task dependency graph
Definition: taskflow.hpp:18
const std::string & name() const
queries the name of the task
Definition: task.hpp:428
class to access task information from the observer interface
Definition: task.hpp:529
T operator()(T... args)
bool empty() const
queries if the task handle points to a task node
Definition: task.hpp:453
void reset()
resets to an empty view
Definition: task.hpp:690
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:438
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:448
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:443
handle to a node in a task dependency graph
Definition: task.hpp:113
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition: task.hpp:339
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:469
Task()=default
constructs an empty task
execution interface for running a taskflow graph
Definition: executor.hpp:43
TaskView & operator=(const TaskView &other)
replaces the contents with a copy of the other task
Definition: task.hpp:647
size_t hash_value() const
obtains a hash value of the underlying node
Definition: task.hpp:484
TaskType type() const
returns the task type
Definition: task.hpp:463
bool operator==(const TaskView &) const
compares if two taskviews are associated with the same task
Definition: task.hpp:705
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:670
bool has_work() const
queries if the task has a work assigned
Definition: task.hpp:458
const std::string & name() const
queries the name of the task
Definition: task.hpp:665