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