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

Loading...
Searching...
No Matches
graph.hpp
1#pragma once
2
3#include "../utility/macros.hpp"
4#include "../utility/traits.hpp"
5#include "../utility/iterator.hpp"
6
7#ifdef TF_ENABLE_TASK_POOL
8#include "../utility/object_pool.hpp"
9#endif
10
11#include "../utility/os.hpp"
12#include "../utility/math.hpp"
13#include "../utility/small_vector.hpp"
14#include "../utility/serializer.hpp"
15#include "../utility/lazy_string.hpp"
16#include "error.hpp"
17#include "declarations.hpp"
18#include "environment.hpp"
19#include "semaphore.hpp"
20#include "topology.hpp"
21#include "wsq.hpp"
22
23
29 namespace tf {
30
31// ----------------------------------------------------------------------------
32// Class: Graph
33// ----------------------------------------------------------------------------
34
47 class Graph {
48
49 friend class Node;
50 friend class FlowBuilder;
51 friend class Subflow;
52 friend class Taskflow;
53 friend class Executor;
54
55 public:
56
60 Graph() = default;
61
65 ~Graph();
66
70 Graph(const Graph&) = delete;
71
75 Graph(Graph&&);
76
80 Graph& operator = (const Graph&) = delete;
81
85 Graph& operator = (Graph&&);
86
90 void clear();
91
95 size_t size() const;
96
100 bool empty() const;
101
105 auto begin();
106
110 auto end();
111
115 auto begin() const;
116
120 auto end() const;
121
122 private:
123
124 std::vector<Node*> _nodes;
125
126 void _erase(Node*);
127
131 template <typename ...ArgsT>
132 Node* _emplace_back(ArgsT&&...);
133};
134
135// ----------------------------------------------------------------------------
136// TaskParams
137// ----------------------------------------------------------------------------
138
161 template <typename T>
162 concept StringLike = std::convertible_to<T, std::string_view>;
163
171 class TaskParams {
172
173 public:
174
178 std::string name;
179
183 void* data {nullptr};
184};
185
191 class DefaultTaskParams {};
192
201 template <typename P>
202 concept TaskParamsLike =
203 std::same_as<std::decay_t<P>, TaskParams> ||
204 std::same_as<std::decay_t<P>, DefaultTaskParams> ||
205 StringLike<P>;
206
214 template <typename P>
215 constexpr bool is_task_params_v = TaskParamsLike<P>;
216
217// ----------------------------------------------------------------------------
218// NodeBase
219// ----------------------------------------------------------------------------
220
224 class NodeBase {
225
226 friend class Node;
227 friend class Graph;
228 friend class Task;
229 friend class AsyncTask;
230 friend class TaskView;
231 friend class Taskflow;
232 friend class Executor;
233 friend class FlowBuilder;
234 friend class Subflow;
235 friend class Runtime;
236 friend class NonpreemptiveRuntime;
237 friend class ExplicitAnchorGuard;
238 friend class TaskGroup;
239 friend class Algorithm;
240
241 protected:
242
243 nstate_t _nstate {NSTATE::NONE};
244 std::atomic<estate_t> _estate {ESTATE::NONE};
245
246 NodeBase* _parent {nullptr};
247 std::atomic<size_t> _join_counter {0};
248
249 std::exception_ptr _exception_ptr {nullptr};
250
251 NodeBase() = default;
252
253 NodeBase(nstate_t nstate, estate_t estate, NodeBase* parent, size_t join_counter) :
254 _nstate {nstate},
255 _estate {estate},
256 _parent {parent},
257 _join_counter {join_counter} {
258 }
259
260 void _rethrow_exception() {
261 if(_exception_ptr) {
262 auto e = _exception_ptr;
263 _exception_ptr = nullptr;
264 _estate.fetch_and(~(ESTATE::EXCEPTION | ESTATE::CAUGHT), std::memory_order_relaxed);
265 std::rethrow_exception(e);
266 }
267 }
268};
269
270// ----------------------------------------------------------------------------
271// Topology
272// ----------------------------------------------------------------------------
273
277 class Topology : public NodeBase {
278
279 friend class Executor;
280 friend class Subflow;
281 friend class Runtime;
282 friend class NonpreemptiveRuntime;
283 friend class Node;
284
285 template <typename T>
286 friend class Future;
287
288 public:
289
290 template <typename Predicate, typename OnFinish>
291 Topology(Taskflow&, Predicate&&, OnFinish&&);
292
293 bool cancelled() const;
294
295 private:
296
297 Taskflow& _taskflow;
298
299 std::promise<void> _promise;
300
301 std::function<bool()> _predicate;
302 std::function<void()> _on_finish;
303
304 void _carry_out_promise();
305};
306
307// Constructor
308 template <typename Predicate, typename OnFinish>
309Topology::Topology(Taskflow& tf, Predicate&& predicate, OnFinish&& on_finish):
310 NodeBase(NSTATE::NONE, ESTATE::EXPLICITLY_ANCHORED, nullptr, 0),
311 _taskflow(tf),
312 _predicate(std::forward<Predicate>(predicate)),
313 _on_finish(std::forward<OnFinish> (on_finish)) {
314}
315
316// Procedure
317 inline void Topology::_carry_out_promise() {
318 if(_exception_ptr) {
319 auto e = _exception_ptr;
320 _exception_ptr = nullptr;
321 _promise.set_exception(e);
322 }
323 else {
324 _promise.set_value();
325 }
326}
327
328// Function: cancelled
329 inline bool Topology::cancelled() const {
330 return _estate.load(std::memory_order_relaxed) & (ESTATE::CANCELLED | ESTATE::EXCEPTION);
331}
332
333
334// ----------------------------------------------------------------------------
335// Node
336// ----------------------------------------------------------------------------
337
341 class Node : public NodeBase {
342
343 friend class Graph;
344 friend class Task;
345 friend class AsyncTask;
346 friend class TaskView;
347 friend class Taskflow;
348 friend class Executor;
349 friend class FlowBuilder;
350 friend class Subflow;
351 friend class Runtime;
352 friend class NonpreemptiveRuntime;
353 friend class ExplicitAnchorGuard;
354 friend class TaskGroup;
355 friend class Algorithm;
356
357 using Placeholder = std::monostate;
358
359 // static work handle
360 struct Static {
361
362 template <typename C>
363 Static(C&&);
364
365 std::function<void()> work;
366 };
367
368 // runtime work handle
369 struct Runtime {
370
371 template <typename C>
372 Runtime(C&&);
373
374 std::function<void(tf::Runtime&)> work;
375 };
376
377 struct NonpreemptiveRuntime {
378
379 template <typename C>
380 NonpreemptiveRuntime(C&&);
381
382 std::function<void(tf::NonpreemptiveRuntime&)> work;
383 };
384
385 // subflow work handle
386 struct Subflow {
387
388 template <typename C>
389 Subflow(C&&);
390
391 std::function<void(tf::Subflow&)> work;
392 Graph subgraph;
393 };
394
395 // condition work handle
396 struct Condition {
397
398 template <typename C>
399 Condition(C&&);
400
401 std::function<int()> work;
402 };
403
404 // multi-condition work handle
405 struct MultiCondition {
406
407 template <typename C>
408 MultiCondition(C&&);
409
410 std::function<SmallVector<int>()> work;
411 };
412
413 // module work handle
414 struct Module {
415
416 Module(Graph&);
417
418 Graph& graph;
419 };
420
421 // adopted module work handle
422 struct AdoptedModule {
423
424 AdoptedModule(Graph&&);
425
426 Graph graph;
427 };
428
429 // Async work
430 struct Async {
431
432 template <typename T>
433 Async(T&&);
434
435 std::variant<
436 std::function<void()>,
437 std::function<void(tf::Runtime&)>, // silent async
438 std::function<void(tf::Runtime&, bool)> // async
439 > work;
440 };
441
442 // silent dependent async
443 struct DependentAsync {
444
445 template <typename C>
446 DependentAsync(C&&);
447
448 std::variant<
449 std::function<void()>,
450 std::function<void(tf::Runtime&)>, // silent async
451 std::function<void(tf::Runtime&, bool)> // async
452 > work;
453
454 // use_count is packed into the lower 24 bits of NodeBase::_estate
455 // (ESTATE::REFCOUNT_MASK) to avoid a separate atomic and a std::get_if
456 // call on every AsyncTask copy/move/destroy. see ESTATE::REFCOUNT_ONE.
457 };
458
459 using handle_t = std::variant<
460 Placeholder, // placeholder
461 Static, // static tasking
462 Runtime, // runtime tasking
463 NonpreemptiveRuntime, // runtime (non-preemptive) tasking
464 Subflow, // subflow tasking
465 Condition, // conditional tasking
466 MultiCondition, // multi-conditional tasking
467 Module, // composable tasking
468 AdoptedModule, // composable tasking with move semantics
469 Async, // async tasking
470 DependentAsync // dependent async tasking
471 >;
472
473 struct Semaphores {
474 SmallVector<Semaphore*> to_acquire;
475 SmallVector<Semaphore*> to_release;
476 };
477
478 public:
479
480 // variant index
481 constexpr static auto PLACEHOLDER = get_index_v<Placeholder, handle_t>;
482 constexpr static auto STATIC = get_index_v<Static, handle_t>;
483 constexpr static auto RUNTIME = get_index_v<Runtime, handle_t>;
484 constexpr static auto NONPREEMPTIVE_RUNTIME = get_index_v<NonpreemptiveRuntime, handle_t>;
485 constexpr static auto SUBFLOW = get_index_v<Subflow, handle_t>;
486 constexpr static auto CONDITION = get_index_v<Condition, handle_t>;
487 constexpr static auto MULTI_CONDITION = get_index_v<MultiCondition, handle_t>;
488 constexpr static auto MODULE = get_index_v<Module, handle_t>;
489 constexpr static auto ADOPTED_MODULE = get_index_v<AdoptedModule, handle_t>;
490 constexpr static auto ASYNC = get_index_v<Async, handle_t>;
491 constexpr static auto DEPENDENT_ASYNC = get_index_v<DependentAsync, handle_t>;
492
493 Node() = default;
494
495 template <typename... Args>
496 Node(nstate_t, estate_t, const TaskParams&, Topology*, NodeBase*, size_t, Args&&...);
497
498 template <typename... Args>
499 Node(nstate_t, estate_t, const DefaultTaskParams&, Topology*, NodeBase*, size_t, Args&&...);
500
501 template <StringLike S, typename... Args>
502 Node(nstate_t, estate_t, S&&, Topology*, NodeBase*, size_t, Args&&...);
503
504 size_t num_successors() const;
505 size_t num_predecessors() const;
506 size_t num_strong_dependencies() const;
507 size_t num_weak_dependencies() const;
508
509 const std::string& name() const;
510
511 private:
512
513 std::string _name;
514
515 void* _data {nullptr};
516
517 Topology* _topology {nullptr};
518
519 size_t _num_successors {0};
520 SmallVector<Node*, 4> _edges;
521
522 handle_t _handle;
523
524 std::unique_ptr<Semaphores> _semaphores;
525
526 bool _is_parent_cancelled() const;
527 bool _is_conditioner() const;
528 bool _acquire_all(SmallVector<Node*>&);
529 void _release_all(SmallVector<Node*>&);
530 void _precede(Node*);
531 void _set_up_join_counter();
532
533 void _remove_successors(Node*);
534 void _remove_predecessors(Node*);
535};
536
537
538// ----------------------------------------------------------------------------
539// Definition for Node::Static
540// ----------------------------------------------------------------------------
541
542// Constructor
543 template <typename C>
544Node::Static::Static(C&& c) : work {std::forward<C>(c)} {
545}
546
547// ----------------------------------------------------------------------------
548// Definition for Node::Runtime
549// ----------------------------------------------------------------------------
550
551// Constructor
552 template <typename C>
553Node::Runtime::Runtime(C&& c) : work {std::forward<C>(c)} {
554}
555
556// Constructor
557 template <typename C>
558Node::NonpreemptiveRuntime::NonpreemptiveRuntime(C&& c) : work {std::forward<C>(c)} {
559}
560
561// ----------------------------------------------------------------------------
562// Definition for Node::Subflow
563// ----------------------------------------------------------------------------
564
565// Constructor
566 template <typename C>
567Node::Subflow::Subflow(C&& c) : work {std::forward<C>(c)} {
568}
569
570// ----------------------------------------------------------------------------
571// Definition for Node::Condition
572// ----------------------------------------------------------------------------
573
574// Constructor
575 template <typename C>
576Node::Condition::Condition(C&& c) : work {std::forward<C>(c)} {
577}
578
579// ----------------------------------------------------------------------------
580// Definition for Node::MultiCondition
581// ----------------------------------------------------------------------------
582
583// Constructor
584 template <typename C>
585Node::MultiCondition::MultiCondition(C&& c) : work {std::forward<C>(c)} {
586}
587
588// ----------------------------------------------------------------------------
589// Definition for Node::Module
590// ----------------------------------------------------------------------------
591
592// Constructor
593 inline Node::Module::Module(Graph& g) : graph(g){
594}
595
596// Constructor
597 inline Node::AdoptedModule::AdoptedModule(Graph&& g) : graph(std::move(g)){
598}
599
600// ----------------------------------------------------------------------------
601// Definition for Node::Async
602// ----------------------------------------------------------------------------
603
604// Constructor
605 template <typename C>
606Node::Async::Async(C&& c) : work {std::forward<C>(c)} {
607}
608
609// ----------------------------------------------------------------------------
610// Definition for Node::DependentAsync
611// ----------------------------------------------------------------------------
612
613// Constructor
614 template <typename C>
615Node::DependentAsync::DependentAsync(C&& c) : work {std::forward<C>(c)} {
616}
617
618// ----------------------------------------------------------------------------
619// Definition for Node
620// ----------------------------------------------------------------------------
621
622// Constructor
623 template <typename... Args>
624Node::Node(
625 nstate_t nstate,
626 estate_t estate,
627 const TaskParams& params,
628 Topology* topology,
629 NodeBase* parent,
630 size_t join_counter,
631 Args&&... args
632) :
633 NodeBase(nstate, estate, parent, join_counter),
634 _name {params.name},
635 _data {params.data},
636 _topology {topology},
637 _handle {std::forward<Args>(args)...} {
638}
639
640// Constructor
641 template <typename... Args>
642Node::Node(
643 nstate_t nstate,
644 estate_t estate,
645 const DefaultTaskParams&,
646 Topology* topology,
647 NodeBase* parent,
648 size_t join_counter,
649 Args&&... args
650) :
651 NodeBase(nstate, estate, parent, join_counter),
652 _topology {topology},
653 _handle {std::forward<Args>(args)...} {
654}
655
656// Constructor
657 template <StringLike S, typename... Args>
658Node::Node(
659 nstate_t nstate,
660 estate_t estate,
661 S&& name,
662 Topology* topology,
663 NodeBase* parent,
664 size_t join_counter,
665 Args&&... args
666) :
667 NodeBase(nstate, estate, parent, join_counter),
668 _name {std::forward<S>(name)},
669 _topology {topology},
670 _handle {std::forward<Args>(args)...} {
671}
672
674//template <typename T, typename... Args>
675//void Node::reset(
676// nstate_t nstate,
677// estate_t estate,
678// const TaskParams& params,
679// Topology* topology,
680// NodeBase* parent,
681// size_t join_counter,
682// std::in_place_type_t<T>,
683// Args&&... args
684//) {
685// _nstate = nstate;
686// _estate = estate;
687// _parent = parent;
688// _join_counter.store(join_counter, std::memory_order_relaxed);
689// _exception_ptr = nullptr;
690// _name = params.name;
691// _data = params.data;
692// _topology = topology;
693// _handle.emplace<T>(std::forward<Args>(args)...);
694// _num_successors = 0;
695// _edges.clear();
696// _semaphores.reset();
697//}
698//
700//template <typename T, typename... Args>
701//void Node::reset(
702// nstate_t nstate,
703// estate_t estate,
704// const DefaultTaskParams&,
705// Topology* topology,
706// NodeBase* parent,
707// size_t join_counter,
708// std::in_place_type_t<T>,
709// Args&&... args
710//) {
711// _nstate = nstate;
712// _estate = estate;
713// _parent = parent;
714// _join_counter.store(join_counter, std::memory_order_relaxed);
715// _exception_ptr = nullptr;
716// _name.clear();
717// _data = nullptr;
718// _topology = topology;
719// _handle.emplace<T>(std::forward<Args>(args)...);
720// _num_successors = 0;
721// _edges.clear();
722// _semaphores.reset();
723//}
724
725// Procedure: _precede
726/*
727 u edges layout: s1, s2, s3, p1, p2 (num_successors = 3)
728 v edges layout: s1, p1, p2
729
730 add a new successor: u->v
731 u successor layout:
732 s1, s2, s3, p1, p2, v (push_back v)
733 s1, s2, s3, v, p2, p1 (swap edges[num_successors] with edges[n-1])
734 v predecessor layout:
735 s1, p1, p2, u (push_back u)
736*/
737 inline void Node::_precede(Node* v) {
738 _edges.push_back(v);
739 std::swap(_edges[_num_successors++], _edges[_edges.size() - 1]);
740 v->_edges.push_back(this);
741}
742
743// Function: _remove_successors
744 inline void Node::_remove_successors(Node* node) {
745 auto sit = std::remove(_edges.begin(), _edges.begin() + _num_successors, node);
746 size_t new_num_successors = std::distance(_edges.begin(), sit);
747 std::move(_edges.begin() + _num_successors, _edges.end(), sit);
748 _edges.resize(_edges.size() - (_num_successors - new_num_successors));
749 _num_successors = new_num_successors;
750}
751
752// Function: _remove_predecessors
753 inline void Node::_remove_predecessors(Node* node) {
754 _edges.erase(
755 std::remove(_edges.begin() + _num_successors, _edges.end(), node), _edges.end()
756 );
757}
758
759// Function: num_successors
760 inline size_t Node::num_successors() const {
761 return _num_successors;
762}
763
764// Function: predecessors
765 inline size_t Node::num_predecessors() const {
766 return _edges.size() - _num_successors;
767}
768
769// Function: num_weak_dependencies
770 inline size_t Node::num_weak_dependencies() const {
771 size_t n = 0;
772 for(size_t i=_num_successors; i<_edges.size(); i++) {
773 n += _edges[i]->_is_conditioner();
774 }
775 return n;
776}
777
778// Function: num_strong_dependencies
779 inline size_t Node::num_strong_dependencies() const {
780 size_t n = 0;
781 for(size_t i=_num_successors; i<_edges.size(); i++) {
782 n += !_edges[i]->_is_conditioner();
783 }
784 return n;
785}
786
787// Function: name
788 inline const std::string& Node::name() const {
789 return _name;
790}
791
792// Function: _is_conditioner
793 inline bool Node::_is_conditioner() const {
794 return _handle.index() == Node::CONDITION ||
795 _handle.index() == Node::MULTI_CONDITION;
796}
797
798// Function: _is_parent_cancelled
799 inline bool Node::_is_parent_cancelled() const {
800 return (_topology && (_topology->_estate.load(std::memory_order_relaxed) & (ESTATE::CANCELLED | ESTATE::EXCEPTION)))
801 ||
802 (_parent && (_parent->_estate.load(std::memory_order_relaxed) & (ESTATE::CANCELLED | ESTATE::EXCEPTION)));
803}
804
805// Procedure: _set_up_join_counter
806 inline void Node::_set_up_join_counter() {
807 //assert(_nstate == NSTATE::NONE);
808 for(size_t i=_num_successors; i<_edges.size(); i++) {
809 _nstate += !_edges[i]->_is_conditioner();
810 }
811 _join_counter.store(_nstate & NSTATE::STRONG_DEPENDENCIES_MASK, std::memory_order_relaxed);
812}
813
814
815// Function: _acquire_all
816 inline bool Node::_acquire_all(SmallVector<Node*>& nodes) {
817 // assert(_semaphores != nullptr);
818 auto& to_acquire = _semaphores->to_acquire;
819 for(size_t i = 0; i < to_acquire.size(); ++i) {
820 if(!to_acquire[i]->_try_acquire_or_wait(this)) {
821 for(size_t j = 1; j <= i; ++j) {
822 to_acquire[i-j]->_release(nodes);
823 }
824 return false;
825 }
826 }
827 return true;
828}
829
830// Function: _release_all
831 inline void Node::_release_all(SmallVector<Node*>& nodes) {
832 // assert(_semaphores != nullptr);
833 auto& to_release = _semaphores->to_release;
834 for(const auto& sem : to_release) {
835 sem->_release(nodes);
836 }
837}
838
839
840
841// ----------------------------------------------------------------------------
842// ExplicitAnchorGuard
843// ----------------------------------------------------------------------------
844
848 class ExplicitAnchorGuard {
849
850 public:
851
852 // Explicit anchor must sit in estate as it may be accessed by multiple threads
853 // (e.g., corun's parent with tear_down_async's parent).
854 ExplicitAnchorGuard(NodeBase* node_base) : _node_base{node_base} {
855 _node_base->_estate.fetch_or(ESTATE::EXPLICITLY_ANCHORED, std::memory_order_relaxed);
856 }
857
858 ~ExplicitAnchorGuard() {
859 _node_base->_estate.fetch_and(~ESTATE::EXPLICITLY_ANCHORED, std::memory_order_relaxed);
860 }
861
862 private:
863
864 NodeBase* _node_base;
865};
866
867// ----------------------------------------------------------------------------
868// Node Object Pool
869// ----------------------------------------------------------------------------
870
871#ifdef TF_ENABLE_TASK_POOL
875 using NodePool = std::conditional_t
876 std::atomic<tf::TaggedHead128>::is_always_lock_free,
877 ObjectPool<Node, tf::TaggedHead128>,
878 ObjectPool<Node, tf::TaggedHead64<>>
879>;
880 inline NodePool _node_pool;
881#endif
882
886 template <typename... ArgsT>
887TF_FORCE_INLINE Node* animate(ArgsT&&... args) {
888#ifdef TF_ENABLE_TASK_POOL
889 return _node_pool.animate(std::forward<ArgsT>(args)...);
890#else
891 return new Node(std::forward<ArgsT>(args)...);
892#endif
893}
894
898TF_FORCE_INLINE void recycle(Node* ptr) {
899#ifdef TF_ENABLE_TASK_POOL
900 _node_pool.recycle(ptr);
901#else
902 delete ptr;
903#endif
904}
905
906
907// ----------------------------------------------------------------------------
908// Graph definition
909// ----------------------------------------------------------------------------
910
911// Destructor
912 inline Graph::~Graph() {
913 clear();
914}
915
916// Move constructor
917 inline Graph::Graph(Graph&& other) :
918 _nodes {std::move(other._nodes)} {
919}
920
921// Move assignment
922 inline Graph& Graph::operator = (Graph&& other) {
923 clear();
924 _nodes = std::move(other._nodes);
925 return *this;
926}
927
928// Procedure: clear
929 inline void Graph::clear() {
930 for(auto node : _nodes) {
931 recycle(node);
932 }
933 _nodes.clear();
934}
935
936// Function: size
937 inline size_t Graph::size() const {
938 return _nodes.size();
939}
940
941// Function: empty
942 inline bool Graph::empty() const {
943 return _nodes.empty();
944}
945
946// Function: begin
947 inline auto Graph::begin() {
948 return _nodes.begin();
949}
950
951// Function: end
952 inline auto Graph::end() {
953 return _nodes.end();
954}
955
956// Function: begin
957 inline auto Graph::begin() const {
958 return _nodes.begin();
959}
960
961// Function: end
962 inline auto Graph::end() const {
963 return _nodes.end();
964}
965
966// Function: erase
967 inline void Graph::_erase(Node* node) {
968 //erase(
969 // std::remove_if(begin(), end(), [&](auto& p){ return p.get() == node; }),
970 // end()
971 //);
972 _nodes.erase(
973 std::remove_if(_nodes.begin(), _nodes.end(), [&](auto& p){
974 if(p == node) {
975 recycle(p);
976 return true;
977 }
978 return false;
979 }),
980 _nodes.end()
981 );
982}
983
987 template <typename ...ArgsT>
988Node* Graph::_emplace_back(ArgsT&&... args) {
989 _nodes.push_back(animate(std::forward<ArgsT>(args)...));
990 return _nodes.back();
991}
992
993// ----------------------------------------------------------------------------
994// Graph checker
995// ----------------------------------------------------------------------------
996
997
1027 template <typename T>
1028 concept GraphLike = std::derived_from<T, Graph> ||
1029 requires(T& t) {
1030 { t.graph() } -> std::convertible_to<Graph&>;
1031 };
1032
1066 template <GraphLike T>
1067 Graph& retrieve_graph(T& target) {
1068 if constexpr (requires { target.graph(); }) {
1069 return target.graph();
1070 } else {
1071 return static_cast<Graph&>(target);
1072 }
1073}
1074
1075} // end of namespace tf. ----------------------------------------------------
tf::AsyncTask
class to hold a dependent asynchronous task with shared ownership
Definition async_task.hpp:45
tf::DefaultTaskParams
class to create an empty task parameter for compile-time optimization
Definition graph.hpp:191
tf::Executor
class to create an executor
Definition executor.hpp:62
tf::FlowBuilder
class to build a task dependency graph
Definition flow_builder.hpp:114
tf::Graph
class to create a graph object
Definition graph.hpp:47
tf::Graph::operator=
Graph & operator=(const Graph &)=delete
disabled copy assignment operator
tf::Graph::Graph
Graph()=default
constructs the graph object
tf::Graph::empty
bool empty() const
queries the emptiness of the graph
Definition graph.hpp:942
tf::Graph::~Graph
~Graph()
destroys the graph object
Definition graph.hpp:912
tf::Graph::end
auto end()
returns an iterator past the last element of this graph
Definition graph.hpp:952
tf::Graph::size
size_t size() const
returns the number of nodes in the graph
Definition graph.hpp:937
tf::Graph::clear
void clear()
clears the graph
Definition graph.hpp:929
tf::Graph::begin
auto begin()
returns an iterator to the first node of this graph
Definition graph.hpp:947
tf::Graph::Graph
Graph(const Graph &)=delete
disabled copy constructor
tf::Runtime
class to create a runtime task
Definition runtime.hpp:47
tf::Subflow
class to construct a subflow graph from the execution of a dynamic task
Definition flow_builder.hpp:1913
tf::TaskGroup
class to create a task group from a task
Definition task_group.hpp:61
tf::TaskParams
class to create a task parameter object
Definition graph.hpp:171
tf::TaskParams::name
std::string name
name of the task
Definition graph.hpp:178
tf::TaskParams::data
void * data
C-styled pointer to user data.
Definition graph.hpp:183
tf::TaskView
class to access task information from the observer interface
Definition task.hpp:1546
tf::Task
class to create a task handle over a taskflow node
Definition task.hpp:569
tf::Taskflow
class to create a taskflow object
Definition taskflow.hpp:64
tf::GraphLike
concept that determines if a type owns or provides access to a tf::Graph
Definition graph.hpp:1028
tf::StringLike
concept that determines if a type is string-like
Definition graph.hpp:162
tf::TaskParamsLike
concept that determines if a type is a task parameter type
Definition graph.hpp:202
tf
taskflow namespace
Definition small_vector.hpp:20
tf::TaskType::MODULE
@ MODULE
module task type
tf::TaskType::SUBFLOW
@ SUBFLOW
dynamic (subflow) task type
tf::TaskType::CONDITION
@ CONDITION
condition task type
tf::TaskType::ASYNC
@ ASYNC
asynchronous task type
tf::TaskType::PLACEHOLDER
@ PLACEHOLDER
placeholder task type
tf::TaskType::RUNTIME
@ RUNTIME
runtime task type
tf::TaskType::STATIC
@ STATIC
static task type
tf::retrieve_graph
Graph & retrieve_graph(T &target)
retrieves a reference to the underlying tf::Graph from an object
Definition graph.hpp:1067
tf::is_task_params_v
constexpr bool is_task_params_v
concept that determines if a type is a task parameter type (variable template)
Definition graph.hpp:215