Cpp-Taskflow  2.4-master-branch
task.hpp
1 #pragma once
2 
3 #include "graph.hpp"
4 
5 namespace tf {
6 
7 // ----------------------------------------------------------------------------
8 // Task Traits
9 // ----------------------------------------------------------------------------
10 
18 template <typename C>
19 constexpr bool is_static_task_v = is_invocable_r_v<void, C> &&
20  !is_invocable_r_v<int, C>;
21 
29 template <typename C>
30 constexpr bool is_dynamic_task_v = is_invocable_r_v<void, C, Subflow&>;
31 
39 template <typename C>
40 constexpr bool is_condition_task_v = is_invocable_r_v<int, C>;
41 
42 #ifdef TF_ENABLE_CUDA
43 
50 template <typename C>
51 constexpr bool is_cudaflow_task_v = is_invocable_r_v<void, C, cudaFlow&>;
52 #endif
53 
54 // ----------------------------------------------------------------------------
55 // Task
56 // ----------------------------------------------------------------------------
57 
68 class Task {
69 
70  friend class FlowBuilder;
71  friend class Taskflow;
72  friend class TaskView;
73 
74  public:
75 
79  Task() = default;
80 
84  Task(const Task& other);
85 
89  Task& operator = (const Task&);
90 
95 
99  bool operator == (const Task& rhs) const;
100 
104  bool operator != (const Task& rhs) const;
105 
109  const std::string& name() const;
110 
114  size_t num_successors() const;
115 
119  size_t num_dependents() const;
120 
124  size_t num_strong_dependents() const;
125 
129  size_t num_weak_dependents() const;
130 
138  Task& name(const std::string& name);
139 
149  template <typename C>
150  std::enable_if_t<is_static_task_v<C>, Task>& work(C&& callable);
151 
161  template <typename C>
162  std::enable_if_t<is_dynamic_task_v<C>, Task>& work(C&& callable);
163 
173  template <typename C>
174  std::enable_if_t<is_condition_task_v<C>, Task>& work(C&& callable);
175 
176 #ifdef TF_ENABLE_CUDA
177 
186  template <typename C>
187  std::enable_if_t<is_cudaflow_task_v<C>, Task>& work(C&& callable);
188 #endif
189 
197  Task& composed_of(Taskflow& taskflow);
198 
208  template <typename... Ts>
209  Task& precede(Ts&&... tasks);
210 
220  template <typename... Ts>
221  Task& succeed(Ts&&... tasks);
222 
226  void reset();
227 
231  void reset_work();
232 
236  bool empty() const;
237 
241  bool has_work() const;
242 
246  template <typename V>
247  void for_each_successor(V&& visitor) const;
248 
252  template <typename V>
253  void for_each_dependent(V&& visitor) const;
254 
258  size_t hash_value() const;
259 
260 
261  private:
262 
263  Task(Node*);
264 
265  Node* _node {nullptr};
266 
267  template <typename T>
268  void _precede(T&&);
269 
270  template <typename T, typename... Rest>
271  void _precede(T&&, Rest&&...);
272 
273  template <typename T>
274  void _succeed(T&&);
275 
276  template <typename T, typename... Rest>
277  void _succeed(T&&, Rest&&...);
278 };
279 
280 // Constructor
281 inline Task::Task(Node* node) : _node {node} {
282 }
283 
284 // Constructor
285 inline Task::Task(const Task& rhs) : _node {rhs._node} {
286 }
287 
288 // Function: precede
289 template <typename... Ts>
290 Task& Task::precede(Ts&&... tasks) {
291  //(_node->_precede(tgts._node), ...);
292  _precede(std::forward<Ts>(tasks)...);
293  return *this;
294 }
295 
297 // Procedure: _precede
298 template <typename T>
299 void Task::_precede(T&& other) {
300  _node->_precede(other._node);
301 }
302 
304 // Procedure: _precede
305 template <typename T, typename... Ts>
306 void Task::_precede(T&& task, Ts&&... others) {
307  _precede(std::forward<T>(task));
308  _precede(std::forward<Ts>(others)...);
309 }
310 
311 // Function: succeed
312 template <typename... Ts>
313 Task& Task::succeed(Ts&&... tasks) {
314  //(tasks._node->_precede(_node), ...);
315  _succeed(std::forward<Ts>(tasks)...);
316  return *this;
317 }
318 
320 // Procedure: succeed
321 template <typename T>
322 void Task::_succeed(T&& other) {
323  other._node->_precede(_node);
324 }
325 
327 // Procedure: _succeed
328 template <typename T, typename... Ts>
329 void Task::_succeed(T&& task, Ts&&... others) {
330  _succeed(std::forward<T>(task));
331  _succeed(std::forward<Ts>(others)...);
332 }
333 
334 // Function: composed_of
336  _node->_handle.emplace<Node::ModuleWork>(&tf);
337  return *this;
338 }
339 
340 // Operator =
341 inline Task& Task::operator = (const Task& rhs) {
342  _node = rhs._node;
343  return *this;
344 }
345 
346 // Operator =
348  _node = ptr;
349  return *this;
350 }
351 
352 // Operator ==
353 inline bool Task::operator == (const Task& rhs) const {
354  return _node == rhs._node;
355 }
356 
357 // Operator !=
358 inline bool Task::operator != (const Task& rhs) const {
359  return _node != rhs._node;
360 }
361 
362 // Function: name
363 inline Task& Task::name(const std::string& name) {
364  _node->_name = name;
365  return *this;
366 }
367 
368 // Procedure: reset
369 inline void Task::reset() {
370  _node = nullptr;
371 }
372 
373 // Procedure: reset_work
374 inline void Task::reset_work() {
375  _node->_handle = nstd::monostate{};
376 }
377 
378 // Function: name
379 inline const std::string& Task::name() const {
380  return _node->_name;
381 }
382 
383 // Function: num_dependents
384 inline size_t Task::num_dependents() const {
385  return _node->num_dependents();
386 }
387 
388 // Function: num_strong_dependents
389 inline size_t Task::num_strong_dependents() const {
390  return _node->num_strong_dependents();
391 }
392 
393 // Function: num_weak_dependents
394 inline size_t Task::num_weak_dependents() const {
395  return _node->num_weak_dependents();
396 }
397 
398 // Function: num_successors
399 inline size_t Task::num_successors() const {
400  return _node->num_successors();
401 }
402 
403 // Function: empty
404 inline bool Task::empty() const {
405  return _node == nullptr;
406 }
407 
408 // Function: has_work
409 inline bool Task::has_work() const {
410  return _node ? _node->_handle.index() != 0 : false;
411 }
412 
413 // Function: for_each_successor
414 template <typename V>
415 void Task::for_each_successor(V&& visitor) const {
416  for(size_t i=0; i<_node->_successors.size(); ++i) {
417  visitor(Task(_node->_successors[i]));
418  }
419 }
420 
421 // Function: for_each_dependent
422 template <typename V>
423 void Task::for_each_dependent(V&& visitor) const {
424  for(size_t i=0; i<_node->_dependents.size(); ++i) {
425  visitor(Task(_node->_dependents[i]));
426  }
427 }
428 
429 // Function: hash_value
430 inline size_t Task::hash_value() const {
431  return std::hash<Node*>{}(_node);
432 }
433 
434 // Function: work
435 // assign a static work
436 template <typename C>
437 std::enable_if_t<is_static_task_v<C>, Task>& Task::work(C&& c) {
438  _node->_handle.emplace<Node::StaticWork>(std::forward<C>(c));
439  return *this;
440 }
441 
442 // Function: work
443 // assigns a dynamic work
444 template <typename C>
445 std::enable_if_t<is_dynamic_task_v<C>, Task>& Task::work(C&& c) {
446  _node->_handle.emplace<Node::DynamicWork>(std::forward<C>(c));
447  return *this;
448 }
449 
450 // Function: work
451 // assigns a condition work
452 template <typename C>
453 std::enable_if_t<is_condition_task_v<C>, Task>& Task::work(C&& c) {
454  _node->_handle.emplace<Node::ConditionWork>(std::forward<C>(c));
455  return *this;
456 }
457 
458 #ifdef TF_ENABLE_CUDA
459 // Function: work
460 // assigns a cudaFlow work
461 template <typename C>
462 std::enable_if_t<is_cudaflow_task_v<C>, Task>& Task::work(C&& c) {
463  _node->_handle.emplace<Node::cudaFlowWork>(std::forward<C>(c));
464  return *this;
465 }
466 #endif
467 
468 // ----------------------------------------------------------------------------
469 
475 class TaskView {
476 
477  friend class Executor;
478 
479  public:
480 
484  TaskView() = default;
485 
489  TaskView(const Task& task);
490 
494  TaskView(const TaskView& other);
495 
499  TaskView& operator = (const TaskView& other);
500 
504  TaskView& operator = (const Task& other);
505 
510 
514  bool operator == (const TaskView&) const;
515 
519  bool operator != (const TaskView&) const;
520 
524  const std::string& name() const;
525 
529  size_t num_successors() const;
530 
534  size_t num_dependents() const;
535 
539  size_t num_strong_dependents() const;
540 
544  size_t num_weak_dependents() const;
545 
549  void reset();
550 
554  bool empty() const;
555 
559  template <typename V>
560  void for_each_successor(V&& visitor) const;
561 
565  template <typename V>
566  void for_each_dependent(V&& visitor) const;
567 
568  private:
569 
570  TaskView(Node*);
571 
572  Node* _node {nullptr};
573 };
574 
575 // Constructor
576 inline TaskView::TaskView(Node* node) : _node {node} {
577 }
578 
579 // Constructor
580 inline TaskView::TaskView(const TaskView& rhs) : _node {rhs._node} {
581 }
582 
583 // Constructor
584 inline TaskView::TaskView(const Task& task) : _node {task._node} {
585 }
586 
587 // Operator =
589  _node = rhs._node;
590  return *this;
591 }
592 
593 // Operator =
594 inline TaskView& TaskView::operator = (const Task& rhs) {
595  _node = rhs._node;
596  return *this;
597 }
598 
599 // Operator =
601  _node = ptr;
602  return *this;
603 }
604 
605 // Function: name
606 inline const std::string& TaskView::name() const {
607  return _node->_name;
608 }
609 
610 // Function: num_dependents
611 inline size_t TaskView::num_dependents() const {
612  return _node->num_dependents();
613 }
614 
615 // Function: num_strong_dependents
616 inline size_t TaskView::num_strong_dependents() const {
617  return _node->num_strong_dependents();
618 }
619 
620 // Function: num_weak_dependents
621 inline size_t TaskView::num_weak_dependents() const {
622  return _node->num_weak_dependents();
623 }
624 
625 // Function: num_successors
626 inline size_t TaskView::num_successors() const {
627  return _node->num_successors();
628 }
629 
630 // Function: reset
631 inline void TaskView::reset() {
632  _node = nullptr;
633 }
634 
635 // Function: empty
636 inline bool TaskView::empty() const {
637  return _node == nullptr;
638 }
639 
640 // Operator ==
641 inline bool TaskView::operator == (const TaskView& rhs) const {
642  return _node == rhs._node;
643 }
644 
645 // Operator !=
646 inline bool TaskView::operator != (const TaskView& rhs) const {
647  return _node != rhs._node;
648 }
649 
650 // Function: for_each_successor
651 template <typename V>
652 void TaskView::for_each_successor(V&& visitor) const {
653  for(size_t i=0; i<_node->_successors.size(); ++i) {
654  visitor(TaskView(_node->_successors[i]));
655  }
656 }
657 
658 // Function: for_each_dependent
659 template <typename V>
660 void TaskView::for_each_dependent(V&& visitor) const {
661  for(size_t i=0; i<_node->_dependents.size(); ++i) {
662  visitor(TaskView(_node->_dependents[i]));
663  }
664 }
665 
666 } // end of namespace tf. ---------------------------------------------------
667 
668 namespace std {
669 
676 template <>
677 struct hash<tf::Task> {
678  auto operator() (const tf::Task& task) const noexcept {
679  return task.hash_value();
680  }
681 };
682 
683 } // end of namespace std ----------------------------------------------------
684 
685 
686 
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:384
void reset_work()
resets the associated work to a placeholder
Definition: task.hpp:374
void reset()
resets the task handle to null
Definition: task.hpp:369
TaskView()=default
constructs an empty task view
bool operator!=(const TaskView &) const
compares if two taskviews are associated with different tasks
Definition: task.hpp:646
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:660
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:621
Task & composed_of(Taskflow &taskflow)
creates a module task from a taskflow
Definition: task.hpp:335
size_t num_successors() const
queries the number of successors of the task
Definition: task.hpp:626
Definition: error.hpp:9
bool operator==(const Task &rhs) const
compares if two tasks are associated with the same graph node
Definition: task.hpp:353
std::enable_if_t< is_static_task_v< C >, Task > & work(C &&callable)
assigns a static task
Definition: task.hpp:437
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition: task.hpp:313
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:652
bool operator!=(const Task &rhs) const
compares if two tasks are not associated with the same graph node
Definition: task.hpp:358
bool empty() const
queries if the task view is empty
Definition: task.hpp:636
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:616
Task & operator=(const Task &)
replaces the contents with a copy of the other task
Definition: task.hpp:341
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition: task.hpp:423
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:379
immutable accessor class to a task node used by tf::ExecutorObserver
Definition: task.hpp:475
T operator()(T... args)
bool empty() const
queries if the task handle points to a task node
Definition: task.hpp:404
void reset()
resets to an empty view
Definition: task.hpp:631
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition: task.hpp:389
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:399
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition: task.hpp:394
handle to a node in a task dependency graph
Definition: task.hpp:68
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition: task.hpp:290
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition: task.hpp:415
Task()=default
constructs an empty task
execution interface for running a taskflow graph
Definition: executor.hpp:32
TaskView & operator=(const TaskView &other)
replaces the contents with a copy of the other task
Definition: task.hpp:588
size_t hash_value() const
obtains a hash value of the underlying node
Definition: task.hpp:430
bool operator==(const TaskView &) const
compares if two taskviews are associated with the same task
Definition: task.hpp:641
size_t num_dependents() const
queries the number of predecessors of the task
Definition: task.hpp:611
bool has_work() const
queries if the task has a work assigned
Definition: task.hpp:409
const std::string & name() const
queries the name of the task
Definition: task.hpp:606