| Taskflow: A General-purpose Task-parallel Programming System

Loading...
Searching...
No Matches
task.hpp
1#pragma once
2
3#include "graph.hpp"
4
9
10 namespace tf {
11
12// ----------------------------------------------------------------------------
13// Task Types
14// ----------------------------------------------------------------------------
15
21 enum class TaskType : int {
23 PLACEHOLDER = 0,
25 STATIC,
27 RUNTIME,
29 SUBFLOW,
31 CONDITION,
33 MODULE,
35 ASYNC,
37 UNDEFINED
38};
39
44 inline constexpr std::array<TaskType, 7> TASK_TYPES = {
45 TaskType::PLACEHOLDER,
46 TaskType::STATIC,
47 TaskType::RUNTIME,
48 TaskType::SUBFLOW,
49 TaskType::CONDITION,
50 TaskType::MODULE,
51 TaskType::ASYNC,
52};
53
66 inline const char* to_string(TaskType type) {
67
68 const char* val;
69
70 switch(type) {
71 case TaskType::PLACEHOLDER: val = "placeholder"; break;
72 case TaskType::STATIC: val = "static"; break;
73 case TaskType::RUNTIME: val = "runtime"; break;
74 case TaskType::SUBFLOW: val = "subflow"; break;
75 case TaskType::CONDITION: val = "condition"; break;
76 case TaskType::MODULE: val = "module"; break;
77 case TaskType::ASYNC: val = "async"; break;
78 default: val = "undefined"; break;
79 }
80
81 return val;
82}
83
84// ----------------------------------------------------------------------------
85// Static Task Trait
86// ----------------------------------------------------------------------------
87
93 template <typename C>
94 concept StaticTask = std::invocable<C> &&
95 std::same_as<std::invoke_result_t<C>, void>;
96
104 template <typename C>
105 constexpr bool is_static_task_v = StaticTask<C>;
106
107// ----------------------------------------------------------------------------
108// Subflow Task Trait
109// ----------------------------------------------------------------------------
110
116 template <typename C>
117 concept SubflowTask = std::invocable<C, tf::Subflow&> &&
118 std::same_as<std::invoke_result_t<C, tf::Subflow&>, void>;
119
127 template <typename C>
128 constexpr bool is_subflow_task_v = SubflowTask<C>;
129
130// ----------------------------------------------------------------------------
131// Runtime Task Trait
132// ----------------------------------------------------------------------------
133
140 template <typename C>
141 concept RuntimeTask =
142 (std::invocable<C, tf::Runtime&> &&
143 std::same_as<std::invoke_result_t<C, tf::Runtime&>, void>) ||
144 (std::invocable<C, tf::NonpreemptiveRuntime&> &&
145 std::same_as<std::invoke_result_t<C, tf::NonpreemptiveRuntime&>, void>);
146
154 template <typename C>
155 constexpr bool is_runtime_task_v = RuntimeTask<C>;
156
157
158// ----------------------------------------------------------------------------
159// Condition Task Trait
160// ----------------------------------------------------------------------------
161
167 template <typename C>
168 concept ConditionTask = std::invocable<C> &&
169 std::convertible_to<std::invoke_result_t<C>, int>;
170
178 template <typename C>
179 constexpr bool is_condition_task_v = ConditionTask<C>;
180
187 template <typename C>
188 concept MultiConditionTask = std::invocable<C> &&
189 std::same_as<std::invoke_result_t<C>, SmallVector<int>>;
190
198 template <typename C>
199 constexpr bool is_multi_condition_task_v = MultiConditionTask<C>;
200
201
202// ----------------------------------------------------------------------------
203// Task
204// ----------------------------------------------------------------------------
205
263 class Task {
264
265 friend class FlowBuilder;
266 friend class Runtime;
267 friend class NonpreemptiveRuntime;
268 friend class Taskflow;
269 friend class TaskView;
270 friend class Executor;
271
272 public:
273
279 Task() = default;
280
293 Task(const Task& other);
294
306 Task& operator = (const Task& other);
307
316 Task& operator = (std::nullptr_t);
317
330 bool operator == (const Task& rhs) const;
331
344 bool operator != (const Task& rhs) const;
345
357 const std::string& name() const;
358
371 size_t num_successors() const;
372
385 size_t num_predecessors() const;
386
414 size_t num_strong_dependencies() const;
415
443 size_t num_weak_dependencies() const;
444
457 Task& name(const std::string& name);
458
481 template <typename C>
482 Task& work(C&& callable);
483
501 template <HasGraph T>
502 Task& composed_of(T& object);
503
520 Task& adopt(tf::Graph&& graph);
521
541 template <typename... Ts>
542 Task& precede(Ts&&... tasks);
543
563 template <typename... Ts>
564 Task& succeed(Ts&&... tasks);
565
593 template <typename... Ts>
594 Task& remove_predecessors(Ts&&... tasks);
595
623 template <typename... Ts>
624 Task& remove_successors(Ts&&... tasks);
625
632 Task& release(Semaphore& semaphore);
633
640 template <typename I>
641 Task& release(I first, I last);
642
649 Task& acquire(Semaphore& semaphore);
650
657 template <typename I>
658 Task& acquire(I first, I last);
659
689 Task& data(void* data);
690
703 void reset();
704
708 void reset_work();
709
724 bool empty() const;
725
739 bool has_work() const;
740
763 template <typename V>
764 void for_each_successor(V&& visitor) const;
765
787 template <typename V>
788 void for_each_predecessor(V&& visitor) const;
789
810 template <typename V>
811 void for_each_subflow_task(V&& visitor) const;
812
825 size_t hash_value() const;
826
839 TaskType type() const;
840
850 void dump(std::ostream& ostream) const;
851
879 void* data() const;
880
921 std::exception_ptr exception_ptr() const;
922
928 bool has_exception_ptr() const;
929
930 private:
931
932 Task(Node*);
933
934 Node* _node {nullptr};
935};
936
937// Constructor
938 inline Task::Task(Node* node) : _node {node} {
939}
940
941// Constructor
942 inline Task::Task(const Task& rhs) : _node {rhs._node} {
943}
944
945// Function: precede
946 template <typename... Ts>
947 Task& Task::precede(Ts&&... tasks) {
948 (_node->_precede(tasks._node), ...);
949 //_precede(std::forward<Ts>(tasks)...);
950 return *this;
951}
952
953// Function: succeed
954 template <typename... Ts>
955 Task& Task::succeed(Ts&&... tasks) {
956 (tasks._node->_precede(_node), ...);
957 //_succeed(std::forward<Ts>(tasks)...);
958 return *this;
959}
960
961// Function: remove_predecessors
962 template <typename... Ts>
963 Task& Task::remove_predecessors(Ts&&... tasks) {
964 (tasks._node->_remove_successors(_node), ...);
965 (_node->_remove_predecessors(tasks._node), ...);
966 return *this;
967}
968
969// Function: remove_successors
970 template <typename... Ts>
971 Task& Task::remove_successors(Ts&&... tasks) {
972 (_node->_remove_successors(tasks._node), ...);
973 (tasks._node->_remove_predecessors(_node), ...);
974 return *this;
975}
976
977// Function: composed_of
978 template <HasGraph T>
979 Task& Task::composed_of(T& target) {
980 _node->_handle.emplace<Node::Module>(retrieve_graph(target));
981 return *this;
982}
983
984// Function: adopt
985 inline Task& Task::adopt(Graph&& graph) {
986 _node->_handle.emplace<Node::AdoptedModule>(std::move(graph));
987 return *this;
988}
989
990// Operator =
991 inline Task& Task::operator = (const Task& rhs) {
992 _node = rhs._node;
993 return *this;
994}
995
996// Operator =
997 inline Task& Task::operator = (std::nullptr_t ptr) {
998 _node = ptr;
999 return *this;
1000}
1001
1002// Operator ==
1003 inline bool Task::operator == (const Task& rhs) const {
1004 return _node == rhs._node;
1005}
1006
1007// Operator !=
1008 inline bool Task::operator != (const Task& rhs) const {
1009 return _node != rhs._node;
1010}
1011
1012// Function: name
1013 inline Task& Task::name(const std::string& name) {
1014 _node->_name = name;
1015 return *this;
1016}
1017
1018// Function: acquire
1019 inline Task& Task::acquire(Semaphore& s) {
1020 if(!_node->_semaphores) {
1021 _node->_semaphores = std::make_unique<Node::Semaphores>();
1022 }
1023 _node->_semaphores->to_acquire.push_back(&s);
1024 return *this;
1025}
1026
1027// Function: acquire
1028 template <typename I>
1029 Task& Task::acquire(I first, I last) {
1030 if(!_node->_semaphores) {
1031 _node->_semaphores = std::make_unique<Node::Semaphores>();
1032 }
1033 _node->_semaphores->to_acquire.reserve(
1034 _node->_semaphores->to_acquire.size() + std::distance(first, last)
1035 );
1036 for(auto s = first; s != last; ++s){
1037 _node->_semaphores->to_acquire.push_back(&(*s));
1038 }
1039 return *this;
1040}
1041
1042// Function: release
1043 inline Task& Task::release(Semaphore& s) {
1044 if(!_node->_semaphores) {
1045 _node->_semaphores = std::make_unique<Node::Semaphores>();
1046 }
1047 _node->_semaphores->to_release.push_back(&s);
1048 return *this;
1049}
1050
1051// Function: release
1052 template <typename I>
1053 Task& Task::release(I first, I last) {
1054 if(!_node->_semaphores) {
1055 _node->_semaphores = std::make_unique<Node::Semaphores>();
1056 }
1057 _node->_semaphores->to_release.reserve(
1058 _node->_semaphores->to_release.size() + std::distance(first, last)
1059 );
1060 for(auto s = first; s != last; ++s) {
1061 _node->_semaphores->to_release.push_back(&(*s));
1062 }
1063 return *this;
1064}
1065
1066// Procedure: reset
1067 inline void Task::reset() {
1068 _node = nullptr;
1069}
1070
1071// Procedure: reset_work
1072 inline void Task::reset_work() {
1073 _node->_handle.emplace<std::monostate>();
1074}
1075
1076// Function: name
1077 inline const std::string& Task::name() const {
1078 return _node->_name;
1079}
1080
1081// Function: num_predecessors
1082 inline size_t Task::num_predecessors() const {
1083 return _node->num_predecessors();
1084}
1085
1086// Function: num_strong_dependencies
1087 inline size_t Task::num_strong_dependencies() const {
1088 return _node->num_strong_dependencies();
1089}
1090
1091// Function: num_weak_dependencies
1092 inline size_t Task::num_weak_dependencies() const {
1093 return _node->num_weak_dependencies();
1094}
1095
1096// Function: num_successors
1097 inline size_t Task::num_successors() const {
1098 return _node->num_successors();
1099}
1100
1101// Function: empty
1102 inline bool Task::empty() const {
1103 return _node == nullptr;
1104}
1105
1106// Function: has_work
1107 inline bool Task::has_work() const {
1108 return _node ? _node->_handle.index() != 0 : false;
1109}
1110
1111// Function: exception
1112 inline std::exception_ptr Task::exception_ptr() const {
1113 return _node ? _node->_exception_ptr : nullptr;
1114}
1115
1116// Function: has_exception
1117 inline bool Task::has_exception_ptr() const {
1118 return _node ? (_node->_exception_ptr != nullptr) : false;
1119}
1120
1121// Function: task_type
1122 inline TaskType Task::type() const {
1123 switch(_node->_handle.index()) {
1124 case Node::PLACEHOLDER: return TaskType::PLACEHOLDER;
1125 case Node::STATIC: return TaskType::STATIC;
1126 case Node::RUNTIME: return TaskType::RUNTIME;
1127 case Node::NONPREEMPTIVE_RUNTIME: return TaskType::RUNTIME;
1128 case Node::SUBFLOW: return TaskType::SUBFLOW;
1129 case Node::CONDITION: return TaskType::CONDITION;
1130 case Node::MULTI_CONDITION: return TaskType::CONDITION;
1131 case Node::MODULE: return TaskType::MODULE;
1132 case Node::ADOPTED_MODULE: return TaskType::MODULE;
1133 case Node::ASYNC: return TaskType::ASYNC;
1134 case Node::DEPENDENT_ASYNC: return TaskType::ASYNC;
1135 default: return TaskType::UNDEFINED;
1136 }
1137}
1138
1139// Function: for_each_successor
1140 template <typename V>
1141 void Task::for_each_successor(V&& visitor) const {
1142 for(size_t i=0; i<_node->_num_successors; ++i) {
1143 visitor(Task(_node->_edges[i]));
1144 }
1145}
1146
1147// Function: for_each_predecessor
1148 template <typename V>
1149 void Task::for_each_predecessor(V&& visitor) const {
1150 for(size_t i=_node->_num_successors; i<_node->_edges.size(); ++i) {
1151 visitor(Task(_node->_edges[i]));
1152 }
1153}
1154
1155// Function: for_each_subflow_task
1156 template <typename V>
1157 void Task::for_each_subflow_task(V&& visitor) const {
1158 if(auto ptr = std::get_if<Node::Subflow>(&_node->_handle); ptr) {
1159 for(auto itr = ptr->subgraph.begin(); itr != ptr->subgraph.end(); ++itr) {
1160 visitor(Task(*itr));
1161 }
1162 }
1163}
1164
1165// Function: hash_value
1166 inline size_t Task::hash_value() const {
1167 return std::hash<Node*>{}(_node);
1168}
1169
1170// Procedure: dump
1171 inline void Task::dump(std::ostream& os) const {
1172 os << "task ";
1173 if(name().empty()) os << _node;
1174 else os << name();
1175 os << " [type=" << to_string(type()) << ']';
1176}
1177
1178// Function: work
1179 template <typename C>
1180 Task& Task::work(C&& c) {
1181
1182 if constexpr(is_static_task_v<C>) {
1183 _node->_handle.emplace<Node::Static>(std::forward<C>(c));
1184 }
1185 else if constexpr(is_runtime_task_v<C>) {
1186 _node->_handle.emplace<Node::Runtime>(std::forward<C>(c));
1187 }
1188 else if constexpr(is_subflow_task_v<C>) {
1189 _node->_handle.emplace<Node::Subflow>(std::forward<C>(c));
1190 }
1191 else if constexpr(is_condition_task_v<C>) {
1192 _node->_handle.emplace<Node::Condition>(std::forward<C>(c));
1193 }
1194 else if constexpr(is_multi_condition_task_v<C>) {
1195 _node->_handle.emplace<Node::MultiCondition>(std::forward<C>(c));
1196 }
1197 else {
1198 static_assert(dependent_false_v<C>, "invalid task callable");
1199 }
1200 return *this;
1201}
1202
1203// Function: data
1204 inline void* Task::data() const {
1205 return _node->_data;
1206}
1207
1208// Function: data
1209 inline Task& Task::data(void* data) {
1210 _node->_data = data;
1211 return *this;
1212}
1213
1214// ----------------------------------------------------------------------------
1215// global ostream
1216// ----------------------------------------------------------------------------
1217
1221 inline std::ostream& operator << (std::ostream& os, const Task& task) {
1222 task.dump(os);
1223 return os;
1224}
1225
1226// ----------------------------------------------------------------------------
1227// Task View
1228// ----------------------------------------------------------------------------
1229
1235 class TaskView {
1236
1237 friend class Executor;
1238
1239 public:
1240
1244 const std::string& name() const;
1245
1249 size_t num_successors() const;
1250
1254 size_t num_predecessors() const;
1255
1259 size_t num_strong_dependencies() const;
1260
1264 size_t num_weak_dependencies() const;
1265
1274 template <typename V>
1275 void for_each_successor(V&& visitor) const;
1276
1285 template <typename V>
1286 void for_each_predecessor(V&& visitor) const;
1287
1291 TaskType type() const;
1292
1296 size_t hash_value() const;
1297
1298 private:
1299
1300 TaskView(const Node&);
1301 TaskView(const TaskView&) = default;
1302
1303 const Node& _node;
1304};
1305
1306// Constructor
1307 inline TaskView::TaskView(const Node& node) : _node {node} {
1308}
1309
1310// Function: name
1311 inline const std::string& TaskView::name() const {
1312 return _node._name;
1313}
1314
1315// Function: num_predecessors
1316 inline size_t TaskView::num_predecessors() const {
1317 return _node.num_predecessors();
1318}
1319
1320// Function: num_strong_dependencies
1321 inline size_t TaskView::num_strong_dependencies() const {
1322 return _node.num_strong_dependencies();
1323}
1324
1325// Function: num_weak_dependencies
1326 inline size_t TaskView::num_weak_dependencies() const {
1327 return _node.num_weak_dependencies();
1328}
1329
1330// Function: num_successors
1331 inline size_t TaskView::num_successors() const {
1332 return _node.num_successors();
1333}
1334
1335// Function: type
1336 inline TaskType TaskView::type() const {
1337 switch(_node._handle.index()) {
1338 case Node::PLACEHOLDER: return TaskType::PLACEHOLDER;
1339 case Node::STATIC: return TaskType::STATIC;
1340 case Node::RUNTIME: return TaskType::RUNTIME;
1341 case Node::NONPREEMPTIVE_RUNTIME: return TaskType::RUNTIME;
1342 case Node::SUBFLOW: return TaskType::SUBFLOW;
1343 case Node::CONDITION: return TaskType::CONDITION;
1344 case Node::MULTI_CONDITION: return TaskType::CONDITION;
1345 case Node::MODULE: return TaskType::MODULE;
1346 case Node::ADOPTED_MODULE: return TaskType::MODULE;
1347 case Node::ASYNC: return TaskType::ASYNC;
1348 case Node::DEPENDENT_ASYNC: return TaskType::ASYNC;
1349 default: return TaskType::UNDEFINED;
1350 }
1351}
1352
1353// Function: hash_value
1354 inline size_t TaskView::hash_value() const {
1355 return std::hash<const Node*>{}(&_node);
1356}
1357
1358// Function: for_each_successor
1359 template <typename V>
1360 void TaskView::for_each_successor(V&& visitor) const {
1361 for(size_t i=0; i<_node._num_successors; ++i) {
1362 visitor(TaskView(*_node._edges[i]));
1363 }
1364 //for(size_t i=0; i<_node._successors.size(); ++i) {
1365 // visitor(TaskView(*_node._successors[i]));
1366 //}
1367}
1368
1369// Function: for_each_predecessor
1370 template <typename V>
1371 void TaskView::for_each_predecessor(V&& visitor) const {
1372 for(size_t i=_node._num_successors; i<_node._edges.size(); ++i) {
1373 visitor(TaskView(*_node._edges[i]));
1374 }
1375 //for(size_t i=0; i<_node._predecessors.size(); ++i) {
1376 // visitor(TaskView(*_node._predecessors[i]));
1377 //}
1378}
1379
1380} // end of namespace tf. ----------------------------------------------------
1381
1382 namespace std {
1383
1389 template <>
1390 struct hash<tf::Task> {
1391 auto operator() (const tf::Task& task) const noexcept {
1392 return task.hash_value();
1393 }
1394};
1395
1401 template <>
1402 struct hash<tf::TaskView> {
1403 auto operator() (const tf::TaskView& task_view) const noexcept {
1404 return task_view.hash_value();
1405 }
1406};
1407
1408} // end of namespace std ----------------------------------------------------
tf::Graph
class to create a graph object
Definition graph.hpp:47
tf::Semaphore
class to create a semophore object for building a concurrency constraint
Definition semaphore.hpp:68
tf::SmallVector
class to define a vector optimized for small array
Definition small_vector.hpp:931
tf::TaskView
class to access task information from the observer interface
Definition task.hpp:1235
tf::TaskView::num_predecessors
size_t num_predecessors() const
queries the number of predecessors of the task
Definition task.hpp:1316
tf::TaskView::for_each_predecessor
void for_each_predecessor(V &&visitor) const
applies an visitor callable to each predecessor of the task
Definition task.hpp:1371
tf::TaskView::for_each_successor
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition task.hpp:1360
tf::TaskView::type
TaskType type() const
queries the task type
Definition task.hpp:1336
tf::TaskView::num_weak_dependencies
size_t num_weak_dependencies() const
queries the number of weak dependencies of the task
Definition task.hpp:1326
tf::TaskView::hash_value
size_t hash_value() const
obtains a hash value of the underlying node
Definition task.hpp:1354
tf::TaskView::name
const std::string & name() const
queries the name of the task
Definition task.hpp:1311
tf::TaskView::num_strong_dependencies
size_t num_strong_dependencies() const
queries the number of strong dependencies of the task
Definition task.hpp:1321
tf::TaskView::num_successors
size_t num_successors() const
queries the number of successors of the task
Definition task.hpp:1331
tf::Task
class to create a task handle over a taskflow node
Definition task.hpp:263
tf::Task::acquire
Task & acquire(Semaphore &semaphore)
makes the task acquire the given semaphore
Definition task.hpp:1019
tf::Task::name
const std::string & name() const
queries the name of the task
Definition task.hpp:1077
tf::Task::num_strong_dependencies
size_t num_strong_dependencies() const
queries the number of strong dependencies of the task
Definition task.hpp:1087
tf::Task::remove_successors
Task & remove_successors(Ts &&... tasks)
removes successor links from this to other tasks
Definition task.hpp:971
tf::Task::num_successors
size_t num_successors() const
queries the number of successors of the task
Definition task.hpp:1097
tf::Task::hash_value
size_t hash_value() const
obtains a hash value of the underlying node
Definition task.hpp:1166
tf::Task::for_each_subflow_task
void for_each_subflow_task(V &&visitor) const
applies an visitor callable to each subflow task
Definition task.hpp:1157
tf::Task::release
Task & release(Semaphore &semaphore)
makes the task release the given semaphore
Definition task.hpp:1043
tf::Task::work
Task & work(C &&callable)
assigns a callable
Definition task.hpp:1180
tf::Task::exception_ptr
std::exception_ptr exception_ptr() const
retrieves the exception pointer of this task
Definition task.hpp:1112
tf::Task::reset
void reset()
resets the task handle to null
Definition task.hpp:1067
tf::Task::for_each_predecessor
void for_each_predecessor(V &&visitor) const
applies an visitor callable to each predecessor of the task
Definition task.hpp:1149
tf::Task::data
void * data() const
queries pointer to user data
Definition task.hpp:1204
tf::Task::dump
void dump(std::ostream &ostream) const
dumps the task through an output stream
Definition task.hpp:1171
tf::Task::succeed
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition task.hpp:955
tf::Task::operator=
Task & operator=(const Task &other)
replaces the contents with a copy of the other task
Definition task.hpp:991
tf::Task::Task
Task()=default
constructs an empty task
tf::Task::empty
bool empty() const
queries if the task handle is associated with a taskflow node
Definition task.hpp:1102
tf::Task::precede
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition task.hpp:947
tf::Task::has_exception_ptr
bool has_exception_ptr() const
queries if the task has an exception pointer
Definition task.hpp:1117
tf::Task::adopt
Task & adopt(tf::Graph &&graph)
creates an adopted module task from the given graph with move semantics
Definition task.hpp:985
tf::Task::composed_of
Task & composed_of(T &object)
creates a module task from a taskflow
Definition task.hpp:979
tf::Task::remove_predecessors
Task & remove_predecessors(Ts &&... tasks)
removes predecessor links from other tasks to this
Definition task.hpp:963
tf::Task::num_weak_dependencies
size_t num_weak_dependencies() const
queries the number of weak dependencies of the task
Definition task.hpp:1092
tf::Task::operator==
bool operator==(const Task &rhs) const
compares if two tasks are associated with the same taskflow node
Definition task.hpp:1003
tf::Task::num_predecessors
size_t num_predecessors() const
queries the number of predecessors of the task
Definition task.hpp:1082
tf::Task::reset_work
void reset_work()
resets the associated work to a placeholder
Definition task.hpp:1072
tf::Task::type
TaskType type() const
returns the task type
Definition task.hpp:1122
tf::Task::operator!=
bool operator!=(const Task &rhs) const
compares if two tasks are not associated with the same taskflow node
Definition task.hpp:1008
tf::Task::has_work
bool has_work() const
queries if the task has a work assigned
Definition task.hpp:1107
tf::Task::data
Task & data(void *data)
assigns pointer to user data
Definition task.hpp:1209
tf::Task::for_each_successor
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition task.hpp:1141
tf::ConditionTask
determines if a callable is a condition task
Definition task.hpp:168
tf::MultiConditionTask
determines if a callable is a multi-condition task
Definition task.hpp:188
tf::RuntimeTask
determines if a callable is a runtime task
Definition task.hpp:141
tf::StaticTask
determines if a callable is a static task
Definition task.hpp:94
tf::SubflowTask
determines if a callable is a subflow task
Definition task.hpp:117
tf
taskflow namespace
Definition small_vector.hpp:20
tf::is_condition_task_v
constexpr bool is_condition_task_v
determines if a callable is a condition task (variable template)
Definition task.hpp:179
tf::is_static_task_v
constexpr bool is_static_task_v
determines if a callable is a static task (variable template)
Definition task.hpp:105
tf::TaskType
TaskType
enumeration of all task types
Definition task.hpp:21
tf::TaskType::UNDEFINED
@ UNDEFINED
undefined task type (for internal use only)
Definition task.hpp:37
tf::TaskType::MODULE
@ MODULE
module task type
Definition task.hpp:33
tf::TaskType::SUBFLOW
@ SUBFLOW
dynamic (subflow) task type
Definition task.hpp:29
tf::TaskType::CONDITION
@ CONDITION
condition task type
Definition task.hpp:31
tf::TaskType::ASYNC
@ ASYNC
asynchronous task type
Definition task.hpp:35
tf::TaskType::PLACEHOLDER
@ PLACEHOLDER
placeholder task type
Definition task.hpp:23
tf::TaskType::RUNTIME
@ RUNTIME
runtime task type
Definition task.hpp:27
tf::TaskType::STATIC
@ STATIC
static task type
Definition task.hpp:25
tf::to_string
const char * to_string(TaskType type)
convert a task type to a human-readable string
Definition task.hpp:66
tf::retrieve_graph
auto & retrieve_graph(T &t)
retrieves a reference to the underlying tf::Graph from an object
Definition graph.hpp:987
tf::is_multi_condition_task_v
constexpr bool is_multi_condition_task_v
determines if a callable is a multi-condition task (variable template)
Definition task.hpp:199
tf::operator<<
std::ostream & operator<<(std::ostream &os, const Task &task)
overload of ostream inserter operator for Task
Definition task.hpp:1221
tf::is_subflow_task_v
constexpr bool is_subflow_task_v
determines if a callable is a subflow task (variable template)
Definition task.hpp:128
tf::is_runtime_task_v
constexpr bool is_runtime_task_v
determines if a callable is a runtime task (variable template)
Definition task.hpp:155
hash
hash specialization for std::hash<tf::Task>