Loading...
Searching...
No Matches
tf::FlowBuilder Class Reference

class to build a task dependency graph More...

#include <taskflow/core/flow_builder.hpp>

Inheritance diagram for tf::FlowBuilder:
[legend]

Public Member Functions

 FlowBuilder (Graph &graph)
 constructs a flow builder with a graph
 
template<StaticTask C>
Task emplace (C &&callable)
 creates a static task
 
template<RuntimeTask C>
Task emplace (C &&callable)
 creates a runtime task
 
template<SubflowTask C>
Task emplace (C &&callable)
 creates a dynamic task
 
template<ConditionTask C>
Task emplace (C &&callable)
 creates a condition task
 
template<MultiConditionTask C>
Task emplace (C &&callable)
 creates a multi-condition task
 
template<typename... C>
requires (sizeof...(C) > 1)
auto emplace (C &&... callables)
 creates multiple tasks from a list of callable objects
 
void erase (Task task)
 removes a task from a taskflow
 
template<HasGraph T>
Task composed_of (T &object)
 creates a module task for the target object
 
Task adopt (Graph &&graph)
 creates a module task from a graph by taking over its ownership
 
Task placeholder ()
 creates a placeholder task
 
void linearize (std::vector< Task > &tasks)
 adds adjacent dependency links to a linear list of tasks
 
void linearize (std::initializer_list< Task > tasks)
 adds adjacent dependency links to a linear list of tasks
 
template<typename B , typename E , typename C , Partitioner P = DefaultPartitioner>
Task for_each (B first, E last, C callable, P part=P())
 constructs an STL-styled parallel-for task
 
template<typename B , typename E , typename S , typename C , Partitioner P = DefaultPartitioner>
Task for_each_index (B first, E last, S step, C callable, P part=P())
 constructs an index-based parallel-for task
 
template<IndexRange1DLike R, typename C , Partitioner P = DefaultPartitioner>
Task for_each_by_index (R range, C callable, P part=P())
 constructs a parallel-for task over a one-dimensional index range
 
template<IndexRangeMDLike R, typename C , Partitioner P = DefaultPartitioner>
Task for_each_by_index (R range, C callable, P part=P())
 constructs a parallel-for task over a multi-dimensional index range
 
template<typename B , typename E , typename O , typename C , Partitioner P = DefaultPartitioner>
Task transform (B first1, E last1, O d_first, C c, P part=P())
 constructs a parallel-transform task
 
template<typename B1 , typename E1 , typename B2 , typename O , typename C , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<C>>)
Task transform (B1 first1, E1 last1, B2 first2, O d_first, C c, P part=P())
 constructs a parallel-transform task
 
template<typename B , typename E , typename T , typename O , Partitioner P = DefaultPartitioner>
Task reduce (B first, E last, T &init, O bop, P part=P())
 constructs an STL-styled parallel-reduction task
 
template<IndexRangeLike R, typename T , typename L , typename G , Partitioner P = DefaultPartitioner>
Task reduce_by_index (R range, T &init, L lop, G gop, P part=P())
 constructs an index range-based parallel-reduction task
 
template<typename B , typename E , typename T , typename BOP , typename UOP , Partitioner P = DefaultPartitioner>
Task transform_reduce (B first, E last, T &init, BOP bop, UOP uop, P part=P())
 constructs an STL-styled parallel transform-reduce task
 
template<typename B1 , typename E1 , typename B2 , typename T , typename BOP_R , typename BOP_T , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<BOP_T>>)
Task transform_reduce (B1 first1, E1 last1, B2 first2, T &init, BOP_R bop_r, BOP_T bop_t, P part=P())
 constructs an STL-styled parallel transform-reduce task
 
template<typename B , typename E , typename D , typename BOP >
Task inclusive_scan (B first, E last, D d_first, BOP bop)
 creates an STL-styled parallel inclusive-scan task
 
template<typename B , typename E , typename D , typename BOP , typename T >
Task inclusive_scan (B first, E last, D d_first, BOP bop, T init)
 creates an STL-styled parallel inclusive-scan task with an initial value
 
template<typename B , typename E , typename D , typename T , typename BOP >
Task exclusive_scan (B first, E last, D d_first, T init, BOP bop)
 creates an STL-styled parallel exclusive-scan task
 
template<typename B , typename E , typename D , typename BOP , typename UOP >
Task transform_inclusive_scan (B first, E last, D d_first, BOP bop, UOP uop)
 creates an STL-styled parallel transform-inclusive scan task
 
template<typename B , typename E , typename D , typename BOP , typename UOP , typename T >
Task transform_inclusive_scan (B first, E last, D d_first, BOP bop, UOP uop, T init)
 creates an STL-styled parallel transform-inclusive scan task
 
template<typename B , typename E , typename D , typename T , typename BOP , typename UOP >
Task transform_exclusive_scan (B first, E last, D d_first, T init, BOP bop, UOP uop)
 creates an STL-styled parallel transform-exclusive scan task
 
template<typename B , typename E , typename T , typename UOP , Partitioner P = DefaultPartitioner>
Task find_if (B first, E last, T &result, UOP predicate, P part=P())
 constructs a task to perform STL-styled find-if algorithm
 
template<typename B , typename E , typename T , typename UOP , Partitioner P = DefaultPartitioner>
Task find_if_not (B first, E last, T &result, UOP predicate, P part=P())
 constructs a task to perform STL-styled find-if-not algorithm
 
template<typename B , typename E , typename T , typename C , Partitioner P>
Task min_element (B first, E last, T &result, C comp, P part)
 constructs a task to perform STL-styled min-element algorithm
 
template<typename B , typename E , typename T , typename C , Partitioner P>
Task max_element (B first, E last, T &result, C comp, P part)
 constructs a task to perform STL-styled max-element algorithm
 
template<typename B , typename E , typename C >
Task sort (B first, E last, C cmp)
 constructs a dynamic task to perform STL-styled parallel sort
 
template<typename B , typename E >
Task sort (B first, E last)
 constructs a dynamic task to perform STL-styled parallel sort using the std::less<T> comparator, where T is the element type
 
template<typename B1 , typename E1 , typename B2 , typename E2 , typename O , Partitioner P = DefaultPartitioner>
Task merge (B1 first1, E1 last1, B2 first2, E2 last2, O d_first, P part=P())
 merges two sorted ranges into a single sorted output using the std::less comparator
 
template<typename B1 , typename E1 , typename B2 , typename E2 , typename O , typename C , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<C>>)
Task merge (B1 first1, E1 last1, B2 first2, E2 last2, O d_first, C cmp, P part=P())
 merges two sorted ranges into a single sorted output using the supplied comparator
 

Friends

class Executor
 

Detailed Description

class to build a task dependency graph

The class provides essential methods to construct a task dependency graph from which tf::Taskflow and tf::Subflow are derived.

Member Function Documentation

◆ adopt()

Task tf::FlowBuilder::adopt ( Graph && graph)
inline

creates a module task from a graph by taking over its ownership

Parameters
graphthe graph to adopt (moved into the task)
Returns
a Task handle to the adopted module task

Unlike tf::FlowBuilder::composed_of, which references an externally-owned tf::Taskflow, adopt transfers ownership of the given tf::Graph into the task. The graph's lifetime is managed by the executor once adopted, and the caller has no access to the moved-from graph afterward.

tf::Taskflow taskflow;
tf::FlowBuilder{g}.emplace([]{ std::cout << "task in adopted graph\n"; });
taskflow.adopt(std::move(g)).name("adopted");
class to build a task dependency graph
Definition flow_builder.hpp:22
Task adopt(Graph &&graph)
creates a module task from a graph by taking over its ownership
Definition flow_builder.hpp:1492
Task emplace(C &&callable)
creates a static task
Definition flow_builder.hpp:1435
class to create a graph object
Definition graph.hpp:47
const std::string & name() const
queries the name of the task
Definition task.hpp:1082
class to create a taskflow object
Definition taskflow.hpp:64
Note
Please refer to Composable Tasking for details.

◆ composed_of()

template<HasGraph T>
Task tf::FlowBuilder::composed_of ( T & object)

creates a module task for the target object

Template Parameters
Ttype satisfying tf::HasGraph
Parameters
objecta custom object that defines the method T::graph()
Returns
a tf::Task handle

The example below demonstrates a taskflow composition using the composed_of method.

tf::Taskflow t1, t2;
t1.emplace([](){ std::cout << "t1"; });
// t2 is partially composed of t1
tf::Task comp = t2.composed_of(t1);
tf::Task init = t2.emplace([](){ std::cout << "t2"; });
init.precede(comp);
Task composed_of(T &object)
creates a module task for the target object
Definition flow_builder.hpp:1485
class to create a task handle over a taskflow node
Definition task.hpp:263
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition task.hpp:952

The taskflow object t2 is composed of another taskflow object t1, preceded by another static task init. When taskflow t2 is submitted to an executor, init will run first and then comp which spawns its definition in taskflow t1.

The target object being composed must define the method T::graph() that returns a reference to a graph object of type tf::Graph such that it can interact with the executor. For example:

// custom struct
struct MyObj {
tf::Graph graph;
MyObj() {
tf::FlowBuilder builder(graph);
tf::Task task = builder.emplace([](){
std::cout << "a task\n"; // static task
});
}
Graph& graph() { return graph; }
};
MyObj obj;
tf::Task comp = taskflow.composed_of(obj);
Task & composed_of(T &object)
creates a module task from a taskflow
Definition task.hpp:984

Or, simply expose the graph object and pass it to composed_of:

tf::Graph graph;
tf::FlowBuilder builder(graph);
tf::Task task = builder.emplace([](){
std::cout << "a task\n"; // static task
});
tf::Task comp = taskflow.composed_of(graph);
Note
Please refer to Composable Tasking for details.

◆ emplace() [1/6]

template<typename... C>
requires (sizeof...(C) > 1)
auto tf::FlowBuilder::emplace ( C &&... callables)

creates multiple tasks from a list of callable objects

Template Parameters
Ccallable types
Parameters
callablesone or multiple callable objects constructible from each task category
Returns
a tf::Task handle

The method returns a tuple of tasks each corresponding to the given callable target. You can use structured binding to get the return tasks one by one. The following example creates four static tasks and assign them to A, B, C, and D using structured binding.

auto [A, B, C, D] = taskflow.emplace(
[] () { std::cout << "A"; },
[] () { std::cout << "B"; },
[] () { std::cout << "C"; },
[] () { std::cout << "D"; }
);

◆ emplace() [2/6]

template<MultiConditionTask C>
Task tf::FlowBuilder::emplace ( C && callable)

creates a static task

Template Parameters
Ccallable type satisfying tf::StaticTask
Parameters
callablecallable to construct a static task
Returns
a tf::Task handle

The following example creates a static task.

tf::Task static_task = taskflow.emplace([](){});
Note
Please refer to Static Tasking for details.

◆ emplace() [3/6]

template<RuntimeTask C>
Task tf::FlowBuilder::emplace ( C && callable)

creates a runtime task

Template Parameters
Ccallable type satisfying tf::RuntimeTask
Parameters
callablecallable to construct a runtime task
Returns
a tf::Task handle

The following example creates a runtime task.

tf::Task static_task = taskflow.emplace([](tf::Runtime&){});
class to create a runtime task
Definition runtime.hpp:47
Note
Please refer to Runtime Tasking for details.

◆ emplace() [4/6]

template<SubflowTask C>
Task tf::FlowBuilder::emplace ( C && callable)

creates a dynamic task

Template Parameters
Ccallable type satisfying tf::SubflowTask
Parameters
callablecallable to construct a dynamic task
Returns
a tf::Task handle

The following example creates a dynamic task (tf::Subflow) that spawns two static tasks.

tf::Task dynamic_task = taskflow.emplace([](tf::Subflow& sf){
tf::Task static_task1 = sf.emplace([](){});
tf::Task static_task2 = sf.emplace([](){});
});
class to construct a subflow graph from the execution of a dynamic task
Definition flow_builder.hpp:1599
Note
Please refer to Subflow Tasking for details.

◆ emplace() [5/6]

template<ConditionTask C>
Task tf::FlowBuilder::emplace ( C && callable)

creates a condition task

Template Parameters
Ccallable type satisfying tf::ConditionTask
Parameters
callablecallable to construct a condition task
Returns
a tf::Task handle

The following example creates an if-else block using one condition task and three static tasks.

tf::Taskflow taskflow;
auto [init, cond, yes, no] = taskflow.emplace(
[] () { },
[] () { return 0; },
[] () { std::cout << "yes\n"; },
[] () { std::cout << "no\n"; }
);
// executes yes if cond returns 0, or no if cond returns 1
cond.precede(yes, no);
cond.succeed(init);
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition task.hpp:960
Note
Please refer to Conditional Tasking for details.

◆ emplace() [6/6]

template<MultiConditionTask C>
Task tf::FlowBuilder::emplace ( C && callable)

creates a multi-condition task

Template Parameters
Ccallable type satisfying tf::MultiConditionTask
Parameters
callablecallable to construct a multi-condition task
Returns
a tf::Task handle

The following example creates a multi-condition task that selectively jumps to two successor tasks.

tf::Taskflow taskflow;
auto [init, cond, branch1, branch2, branch3] = taskflow.emplace(
[] () { },
[] () { return tf::SmallVector{0, 2}; },
[] () { std::cout << "branch1\n"; },
[] () { std::cout << "branch2\n"; },
[] () { std::cout << "branch3\n"; }
);
// executes branch1 and branch3 when cond returns 0 and 2
cond.precede(branch1, branch2, branch3);
cond.succeed(init);
class to define a vector optimized for small array
Definition small_vector.hpp:931
Note
Please refer to Conditional Tasking for details.

◆ erase()

void tf::FlowBuilder::erase ( Task task)
inline

removes a task from a taskflow

Parameters
tasktask to remove

Removes a task and its input and output dependencies from the graph associated with the flow builder. If the task does not belong to the graph, nothing will happen.

tf::Task A = taskflow.emplace([](){ std::cout << "A"; });
tf::Task B = taskflow.emplace([](){ std::cout << "B"; });
tf::Task C = taskflow.emplace([](){ std::cout << "C"; });
tf::Task D = taskflow.emplace([](){ std::cout << "D"; });
A.precede(B, C, D);
// erase A from the taskflow and its dependencies to B, C, and D
taskflow.erase(A);

◆ exclusive_scan()

template<typename B , typename E , typename D , typename T , typename BOP >
Task tf::FlowBuilder::exclusive_scan ( B first,
E last,
D d_first,
T init,
BOP bop )

creates an STL-styled parallel exclusive-scan task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
Tinitial value type
BOPsummation operator type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
initinitial value
bopfunction to perform summation

Performs the cumulative sum (aka prefix sum, aka scan) of the input range and writes the result to the output range. Each element of the output range contains the running total of all earlier elements (and the initial value) using the given binary operator for summation.

This function generates an exclusive scan, meaning the N-th element of the output range is the sum of the first N-1 input elements, so the N-th input element is not included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.exclusive_scan(
input.begin(), input.end(), input.begin(), -1, std::plus<int>{}
);
executor.run(taskflow).wait();
// input is {-1, 0, 2, 5, 9}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ find_if()

template<typename B , typename E , typename T , typename UOP , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::find_if ( B first,
E last,
T & result,
UOP predicate,
P part = P() )

constructs a task to perform STL-styled find-if algorithm

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresulting iterator type
UOPunary predicate type
Ppartitioner type
Parameters
firststart of the input range
lastend of the input range
resultresulting iterator to the found element in the input range
predicateunary predicate which returns true for the required element
partpartitioning algorithm (default tf::DefaultPartitioner)

Returns an iterator to the first element in the range [first, last) that satisfies the given criteria (or last if there is no such iterator). This method is equivalent to the parallel execution of the following loop:

auto find_if(InputIt first, InputIt last, UnaryPredicate p) {
for (; first != last; ++first) {
if (predicate(*first)){
return first;
}
}
return last;
}
Task find_if(B first, E last, T &result, UOP predicate, P part=P())
constructs a task to perform STL-styled find-if algorithm

For example, the code below find the element that satisfies the given criteria (value plus one is equal to 23) from an input range of 10 elements:

std::vector<int> input = {1, 6, 9, 10, 22, 5, 7, 8, 9, 11};
std::vector<int>::iterator result;
taskflow.find_if(
input.begin(), input.end(), [](int i){ return i+1 = 23; }, result
);
executor.run(taskflow).wait();
assert(*result == 22);

Iterators can be made stateful by using std::reference_wrapper

◆ find_if_not()

template<typename B , typename E , typename T , typename UOP , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::find_if_not ( B first,
E last,
T & result,
UOP predicate,
P part = P() )

constructs a task to perform STL-styled find-if-not algorithm

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresulting iterator type
UOPunary predicate type
Ppartitioner type
Parameters
firststart of the input range
lastend of the input range
resultresulting iterator to the found element in the input range
predicateunary predicate which returns false for the required element
partpartitioning algorithm (default tf::DefaultPartitioner)

Returns an iterator to the first element in the range [first, last) that satisfies the given criteria (or last if there is no such iterator). This method is equivalent to the parallel execution of the following loop:

auto find_if(InputIt first, InputIt last, UnaryPredicate p) {
for (; first != last; ++first) {
if (!predicate(*first)){
return first;
}
}
return last;
}

For example, the code below find the element that satisfies the given criteria (value is not equal to 1) from an input range of 10 elements:

std::vector<int> input = {1, 1, 1, 1, 22, 1, 1, 1, 1, 1};
std::vector<int>::iterator result;
taskflow.find_if_not(
input.begin(), input.end(), [](int i){ return i == 1; }, result
);
executor.run(taskflow).wait();
assert(*result == 22);

Iterators can be made stateful by using std::reference_wrapper

◆ for_each()

template<typename B , typename E , typename C , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::for_each ( B first,
E last,
C callable,
P part = P() )

constructs an STL-styled parallel-for task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ccallable type
Ptype satisfying tf::Partitioner
Parameters
firstiterator to the beginning (inclusive)
lastiterator to the end (exclusive)
callablecallable object to apply to the dereferenced iterator
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks that applies the callable object to each object obtained by dereferencing every iterator in the range [first, last). This method is equivalent to the parallel execution of the following loop:

for(auto itr=first; itr!=last; itr++) {
callable(*itr);
}

Iterators can be made stateful by using std::reference_wrapper The callable needs to take a single argument of the dereferenced iterator type.

Note
Please refer to Parallel Iterations for details.

◆ for_each_by_index() [1/2]

template<IndexRange1DLike R, typename C , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::for_each_by_index ( R range,
C callable,
P part = P() )

constructs a parallel-for task over a one-dimensional index range

Template Parameters
Rtype satisfying tf::IndexRangeLike
Ccallable type that is invocable with a single argument of type R
Ptype satisfying tf::Partitioner
Parameters
rangeindex range
callablecallable object to apply to each partitioned index range
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks that applies the callable object to in the range [first, last) with the step size.

// [0, 17) with a step size of 2 using tf::IndexRange
tf::IndexRange<int> range(0, 17, 2);
// parallelize the sequence [0, 2, 4, 6, 8, 10, 12, 14, 16]
taskflow.for_each_by_index(range, [](tf::IndexRange<int> range) {
// iterate each index in the subrange
for(int i=range.begin(); i<range.end(); i+=range.step_size()) {
printf("iterate %d\n", i);
}
});
executor.run(taskflow).wait();
class to create an N-dimensional index range of integral indices
Definition iterator.hpp:139

The callable needs to take a single argument of type tf::IndexRange.

Note
Please refer to Parallel Iterations for details.

◆ for_each_by_index() [2/2]

template<IndexRangeMDLike R, typename C , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::for_each_by_index ( R range,
C callable,
P part = P() )

constructs a parallel-for task over a multi-dimensional index range

Template Parameters
Rtype satisfying tf::IndexRangeMDLike (i.e., tf::IndexRange<T, N> with N > 1)
Ccallable type that is invocable with a single argument of type R
Ptype satisfying tf::Partitioner
Parameters
rangeindex range
callablecallable object to apply to each partitioned index range
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The function parallelises iteration over the Cartesian product of N independent 1D ranges. The total iteration space is linearized in row-major order (last dimension varies fastest) and divided among workers according to part. Each worker receives one or more orthogonal sub-boxes and invokes callable once per sub-box.

Each sub-box is guaranteed to be a valid hyper-rectangle: every dimension of the sub-box lies entirely within the corresponding dimension of range and preserves its original step size, including negative strides. The callable must iterate the sub-box using the step sizes reported by each dimension:

// 3D range: depth x height x width
);
taskflow.for_each_by_index(range, [](const tf::IndexRange<int, 3>& sub) {
for(auto d = sub.dim(0).begin(); d < sub.dim(0).end(); d += sub.dim(0).step_size()) {
for(auto h = sub.dim(1).begin(); h < sub.dim(1).end(); h += sub.dim(1).step_size()) {
for(auto w = sub.dim(2).begin(); w < sub.dim(2).end(); w += sub.dim(2).step_size()) {
// process element (d, h, w)
}
}
}
});
T begin() const
queries the starting index of the range
Definition iterator.hpp:510
T step_size() const
queries the step size of the range
Definition iterator.hpp:520
T end() const
queries the ending index of the range
Definition iterator.hpp:515
const IndexRange< T, 1 > & dim(size_t d) const
returns the 1D range for dimension d (read-only)
Definition iterator.hpp:190

When the range bounds are not known at task-graph construction time, pass the range by std::ref. An upstream task must set the bounds before this task runs:

);
auto init = taskflow.emplace([&](){
range.dim(0).reset(0, rows, 1);
range.dim(1).reset(0, cols, 1);
});
auto loop = taskflow.for_each_by_index(std::ref(range), callable);
init.precede(loop);

The loop condition inside the callable must respect the sign of each dimension's step size: use < for positive steps and > for negative steps.

Note
Please refer to Parallel Iterations for details.

◆ for_each_index()

template<typename B , typename E , typename S , typename C , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::for_each_index ( B first,
E last,
S step,
C callable,
P part = P() )

constructs an index-based parallel-for task

Template Parameters
Bbeginning index type (must be integral)
Eending index type (must be integral)
Sstep type (must be integral)
Ccallable type
Ptype satisfying tf::Partitioner
Parameters
firstindex of the beginning (inclusive)
lastindex of the end (exclusive)
stepstep size
callablecallable object to apply to each valid index
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks that applies the callable object to each index in the range [first, last) with the step size. This method is equivalent to the parallel execution of the following loop:

// case 1: step size is positive
for(auto i=first; i<last; i+=step) {
callable(i);
}
// case 2: step size is negative
for(auto i=first, i>last; i+=step) {
callable(i);
}

Iterators can be made stateful by using std::reference_wrapper The callable needs to take a single argument of the integral index type.

Note
Please refer to Parallel Iterations for details.

◆ inclusive_scan() [1/2]

template<typename B , typename E , typename D , typename BOP >
Task tf::FlowBuilder::inclusive_scan ( B first,
E last,
D d_first,
BOP bop )

creates an STL-styled parallel inclusive-scan task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
BOPsummation operator type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
bopfunction to perform summation

Performs the cumulative sum (aka prefix sum, aka scan) of the input range and writes the result to the output range. Each element of the output range contains the running total of all earlier elements using the given binary operator for summation.

This function generates an inclusive scan, meaning that the N-th element of the output range is the sum of the first N input elements, so the N-th input element is included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.inclusive_scan(
input.begin(), input.end(), input.begin(), std::plus<int>{}
);
executor.run(taskflow).wait();
// input is {1, 3, 6, 10, 15}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ inclusive_scan() [2/2]

template<typename B , typename E , typename D , typename BOP , typename T >
Task tf::FlowBuilder::inclusive_scan ( B first,
E last,
D d_first,
BOP bop,
T init )

creates an STL-styled parallel inclusive-scan task with an initial value

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
BOPsummation operator type
Tinitial value type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
bopfunction to perform summation
initinitial value

Performs the cumulative sum (aka prefix sum, aka scan) of the input range and writes the result to the output range. Each element of the output range contains the running total of all earlier elements (and the initial value) using the given binary operator for summation.

This function generates an inclusive scan, meaning the N-th element of the output range is the sum of the first N input elements, so the N-th input element is included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.inclusive_scan(
input.begin(), input.end(), input.begin(), std::plus<int>{}, -1
);
executor.run(taskflow).wait();
// input is {0, 2, 5, 9, 14}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ linearize() [1/2]

void tf::FlowBuilder::linearize ( std::initializer_list< Task > tasks)
inline

adds adjacent dependency links to a linear list of tasks

Parameters
tasksan initializer list of tasks

This member function creates linear dependencies over a list of tasks.

tf::Task A = taskflow.emplace([](){ std::cout << "A"; });
tf::Task B = taskflow.emplace([](){ std::cout << "B"; });
tf::Task C = taskflow.emplace([](){ std::cout << "C"; });
tf::Task D = taskflow.emplace([](){ std::cout << "D"; });
taskflow.linearize({A, B, C, D}); // A->B->C->D

◆ linearize() [2/2]

void tf::FlowBuilder::linearize ( std::vector< Task > & tasks)
inline

adds adjacent dependency links to a linear list of tasks

Parameters
tasksa vector of tasks

This member function creates linear dependencies over a vector of tasks.

tf::Task A = taskflow.emplace([](){ std::cout << "A"; });
tf::Task B = taskflow.emplace([](){ std::cout << "B"; });
tf::Task C = taskflow.emplace([](){ std::cout << "C"; });
tf::Task D = taskflow.emplace([](){ std::cout << "D"; });
std::vector<tf::Task> tasks {A, B, C, D}
taskflow.linearize(tasks); // A->B->C->D

◆ max_element()

template<typename B , typename E , typename T , typename C , Partitioner P>
Task tf::FlowBuilder::max_element ( B first,
E last,
T & result,
C comp,
P part )

constructs a task to perform STL-styled max-element algorithm

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresulting iterator type
Ccomparator type
Ppartitioner type
Parameters
firststart of the input range
lastend of the input range
resultresulting iterator to the found element in the input range
compcomparison function object
partpartitioning algorithm (default tf::DefaultPartitioner)

Finds the largest element in the [first, last) using the given comparison function object. The iterator to that largest element is stored in result. This method is equivalent to the parallel execution of the following loop:

if (first == last){
return last;
}
auto largest = first;
++first;
for (; first != last; ++first) {
if (comp(*largest, *first)) {
largest = first;
}
}
return largest;

For example, the code below find the largest element from an input range of 10 elements.

std::vector<int> input = {1, 1, 1, 1, 1, 2, 1, 1, 1, 1};
std::vector<int>::iterator result;
taskflow.max_element(
input.begin(), input.end(), std::less<int>(), result
);
executor.run(taskflow).wait();
assert(*result == 2);

Iterators can be made stateful by using std::reference_wrapper

◆ merge() [1/2]

template<typename B1 , typename E1 , typename B2 , typename E2 , typename O , typename C , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<C>>)
Task tf::FlowBuilder::merge ( B1 first1,
E1 last1,
B2 first2,
E2 last2,
O d_first,
C cmp,
P part = P() )

merges two sorted ranges into a single sorted output using the supplied comparator

Template Parameters
B1beginning iterator type of the first range
E1ending iterator type of the first range
B2beginning iterator type of the first range
E2ending iterator type of the first range
Odestination iterator type
Ccomparator type
Ppartitioner type
Parameters
first1iterator to the beginning of the first range (inclusive)
last1iterator to the end of the first range (exclusive)
first2iterator to the beginning of the second range (inclusive)
last2iterator to the end of the second range (exclusive)
d_firstiterator to the beginning of the output
cmpcomparator function
partpartitioning algorithm (default tf::DefaultPartitioner)

The task spawns asynchronous tasks to parallel merge elements of the two sorted ranges, [first1, last1) and [first2, last2), using the cmp comparator.

Note
Undefiened behavior if the ranges aren't sorted with respect to the cmp comparator.

◆ merge() [2/2]

template<typename B1 , typename E1 , typename B2 , typename E2 , typename O , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::merge ( B1 first1,
E1 last1,
B2 first2,
E2 last2,
O d_first,
P part = P() )

merges two sorted ranges into a single sorted output using the std::less comparator

Template Parameters
B1beginning iterator type of the first range
E1ending iterator type of the first range
B2beginning iterator type of the first range
E2ending iterator type of the first range
Odestination iterator type
Ppartitioner type
Parameters
first1iterator to the beginning of the first range (inclusive)
last1iterator to the end of the first range (exclusive)
first2iterator to the beginning of the second range (inclusive)
last2iterator to the end of the second range (exclusive)
d_firstiterator to the beginning of the output
partpartitioning algorithm (default tf::DefaultPartitioner)

The task spawns asynchronous tasks to parallel merge elements of the two sorted ranges, [first1, last1) and [first2, last2), using the std::less comparator.

Note
Undefiened behavior if the ranges aren't sorted ascendingly.

◆ min_element()

template<typename B , typename E , typename T , typename C , Partitioner P>
Task tf::FlowBuilder::min_element ( B first,
E last,
T & result,
C comp,
P part )

constructs a task to perform STL-styled min-element algorithm

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresulting iterator type
Ccomparator type
Ppartitioner type
Parameters
firststart of the input range
lastend of the input range
resultresulting iterator to the found element in the input range
compcomparison function object
partpartitioning algorithm (default tf::DefaultPartitioner)

Finds the smallest element in the [first, last) using the given comparison function object. The iterator to that smallest element is stored in result. This method is equivalent to the parallel execution of the following loop:

if (first == last) {
return last;
}
auto smallest = first;
++first;
for (; first != last; ++first) {
if (comp(*first, *smallest)) {
smallest = first;
}
}
return smallest;

For example, the code below find the smallest element from an input range of 10 elements.

std::vector<int> input = {1, 1, 1, 1, 1, -1, 1, 1, 1, 1};
std::vector<int>::iterator result;
taskflow.min_element(
input.begin(), input.end(), std::less<int>(), result
);
executor.run(taskflow).wait();
assert(*result == -1);

Iterators can be made stateful by using std::reference_wrapper

◆ placeholder()

Task tf::FlowBuilder::placeholder ( )
inline

creates a placeholder task

Returns
a tf::Task handle

A placeholder task maps to a node in the taskflow graph, but it does not have any callable work assigned yet. A placeholder task is different from an empty task handle that does not point to any node in a graph.

// create a placeholder task with no callable target assigned
tf::Task placeholder = taskflow.placeholder();
assert(placeholder.empty() == false && placeholder.has_work() == false);
// create an empty task handle
tf::Task task;
assert(task.empty() == true);
// assign the task handle to the placeholder task
task = placeholder;
assert(task.empty() == false && task.has_work() == false);
Task placeholder()
creates a placeholder task
Definition flow_builder.hpp:1499
bool empty() const
queries if the task handle is associated with a taskflow node
Definition task.hpp:1107
bool has_work() const
queries if the task has a work assigned
Definition task.hpp:1112

◆ reduce()

template<typename B , typename E , typename T , typename O , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::reduce ( B first,
E last,
T & init,
O bop,
P part = P() )

constructs an STL-styled parallel-reduction task

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresult type
Obinary reducer type
Ptype satisfying tf::Partitioner
Parameters
firstiterator to the beginning (inclusive)
lastiterator to the end (exclusive)
initinitial value of the reduction and the storage for the reduced result
bopbinary operator that will be applied
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks to perform parallel reduction over init and the elements in the range [first, last). The reduced result is store in init. This method is equivalent to the parallel execution of the following loop:

for(auto itr=first; itr!=last; itr++) {
init = bop(init, *itr);
}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Reduction for details.

◆ reduce_by_index()

template<IndexRangeLike R, typename T , typename L , typename G , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::reduce_by_index ( R range,
T & init,
L lop,
G gop,
P part = P() )

constructs an index range-based parallel-reduction task

Template Parameters
Rtype satisfying tf::IndexRangeLike
Tresult type
Llocal reducer type
Gglobal reducer type
Ptype satisfying tf::Partitioner
Parameters
rangeindex range
initinitial value of the reduction and the storage for the reduced result
lopbinary operator that will be applied locally per worker
gopbinary operator that will be applied globally among worker
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks to perform parallel reduction over a range with init. The reduced result is store in init. Unlike the iterator-based reduction, index range-based reduction is particularly useful for applications that benefit from SIMD optimizations or other range-based processing strategies.

const size_t N = 1000000;
std::vector<int> data(N); // uninitialized data vector
int res = 1; // res will participate in the reduction
taskflow.reduce_by_index(
// final result
res,
// local reducer
[&](tf::IndexRange<size_t> subrange, std::optional<int> running_total) -> int {
int residual = running_total ? *running_total : 0.0;
for(size_t i=subrange.begin(); i<subrange.end(); i+=subrange.step_size()) {
data[i] = 1.0;
residual += data[i];
}
printf("partial sum = %lf\n", residual);
return residual;
},
// global reducer
std::plus<int>()
);
executor.run(taskflow).wait();
assert(res = N + 1);

Range can be made stateful by using std::reference_wrapper.

Note
Please refer to Parallel Reduction for details.

◆ sort() [1/2]

template<typename B , typename E >
Task tf::FlowBuilder::sort ( B first,
E last )

constructs a dynamic task to perform STL-styled parallel sort using the std::less<T> comparator, where T is the element type

Template Parameters
Bbeginning iterator type (random-accessible)
Eending iterator type (random-accessible)
Parameters
firstiterator to the beginning (inclusive)
lastiterator to the end (exclusive)

The task spawns asynchronous tasks to parallel sort elements in the range [first, last) using the std::less<T> comparator, where T is the dereferenced iterator type.

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Sort for details.

◆ sort() [2/2]

template<typename B , typename E , typename C >
Task tf::FlowBuilder::sort ( B first,
E last,
C cmp )

constructs a dynamic task to perform STL-styled parallel sort

Template Parameters
Bbeginning iterator type (random-accessible)
Eending iterator type (random-accessible)
Ccomparator type
Parameters
firstiterator to the beginning (inclusive)
lastiterator to the end (exclusive)
cmpcomparison operator

The task spawns asynchronous tasks to sort elements in the range [first, last) in parallel.

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Sort for details.

◆ transform() [1/2]

template<typename B , typename E , typename O , typename C , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::transform ( B first1,
E last1,
O d_first,
C c,
P part = P() )

constructs a parallel-transform task

Template Parameters
Bbeginning input iterator type
Eending input iterator type
Ooutput iterator type
Ccallable type
Ptype satisfying tf::Partitioner
Parameters
first1iterator to the beginning of the first range
last1iterator to the end of the first range
d_firstiterator to the beginning of the output range
can unary callable to apply to dereferenced input elements
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks that applies the callable object to an input range and stores the result in another output range. This method is equivalent to the parallel execution of the following loop:

while (first1 != last1) {
*d_first++ = c(*first1++);
}

Iterators can be made stateful by using std::reference_wrapper The callable needs to take a single argument of the dereferenced iterator type.

Note
Please refer to Parallel Transforms for details.

◆ transform() [2/2]

template<typename B1 , typename E1 , typename B2 , typename O , typename C , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<C>>)
Task tf::FlowBuilder::transform ( B1 first1,
E1 last1,
B2 first2,
O d_first,
C c,
P part = P() )

constructs a parallel-transform task

Template Parameters
B1beginning input iterator type for the first input range
E1ending input iterator type for the first input range
B2beginning input iterator type for the first second range
Ooutput iterator type
Ccallable type
Ptype satisfying tf::Partitioner
Parameters
first1iterator to the beginning of the first input range
last1iterator to the end of the first input range
first2iterator to the beginning of the second input range
d_firstiterator to the beginning of the output range
ca binary operator to apply to dereferenced input elements
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks that applies the callable object to two input ranges and stores the result in another output range. This method is equivalent to the parallel execution of the following loop:

while (first1 != last1) {
*d_first++ = c(*first1++, *first2++);
}

Iterators can be made stateful by using std::reference_wrapper The callable needs to take two arguments of dereferenced elements from the two input ranges.

Note
Please refer to Parallel Transforms for details.

◆ transform_exclusive_scan()

template<typename B , typename E , typename D , typename T , typename BOP , typename UOP >
Task tf::FlowBuilder::transform_exclusive_scan ( B first,
E last,
D d_first,
T init,
BOP bop,
UOP uop )

creates an STL-styled parallel transform-exclusive scan task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
BOPsummation operator type
UOPtransform operator type
Tinitial value type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
bopfunction to perform summation
uopfunction to transform elements of the input range
initinitial value

Write the cumulative sum (aka prefix sum, aka scan) of the input range to the output range. Each element of the output range contains the running total of all earlier elements (including an initial value) using uop to transform the input elements and using bop for summation.

This function generates an exclusive scan, meaning the Nth element of the output range is the sum of the first N-1 input elements, so the Nth input element is not included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.transform_exclusive_scan(
input.begin(), input.end(), input.begin(), -1, std::plus<int>{},
[](int item) { return -item; }
);
executor.run(taskflow).wait();
// input is {-1, -2, -4, -7, -11}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ transform_inclusive_scan() [1/2]

template<typename B , typename E , typename D , typename BOP , typename UOP >
Task tf::FlowBuilder::transform_inclusive_scan ( B first,
E last,
D d_first,
BOP bop,
UOP uop )

creates an STL-styled parallel transform-inclusive scan task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
BOPsummation operator type
UOPtransform operator type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
bopfunction to perform summation
uopfunction to transform elements of the input range

Write the cumulative sum (aka prefix sum, aka scan) of the input range to the output range. Each element of the output range contains the running total of all earlier elements using uop to transform the input elements and using bop for summation.

This function generates an inclusive scan, meaning the Nth element of the output range is the sum of the first N input elements, so the Nth input element is included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.transform_inclusive_scan(
input.begin(), input.end(), input.begin(), std::plus<int>{},
[] (int item) { return -item; }
);
executor.run(taskflow).wait();
// input is {-1, -3, -6, -10, -15}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ transform_inclusive_scan() [2/2]

template<typename B , typename E , typename D , typename BOP , typename UOP , typename T >
Task tf::FlowBuilder::transform_inclusive_scan ( B first,
E last,
D d_first,
BOP bop,
UOP uop,
T init )

creates an STL-styled parallel transform-inclusive scan task

Template Parameters
Bbeginning iterator type
Eending iterator type
Ddestination iterator type
BOPsummation operator type
UOPtransform operator type
Tinitial value type
Parameters
firststart of input range
lastend of input range
d_firststart of output range (may be the same as input range)
bopfunction to perform summation
uopfunction to transform elements of the input range
initinitial value

Write the cumulative sum (aka prefix sum, aka scan) of the input range to the output range. Each element of the output range contains the running total of all earlier elements (including an initial value) using uop to transform the input elements and using bop for summation.

This function generates an inclusive scan, meaning the Nth element of the output range is the sum of the first N input elements, so the Nth input element is included.

std::vector<int> input = {1, 2, 3, 4, 5};
taskflow.transform_inclusive_scan(
input.begin(), input.end(), input.begin(), std::plus<int>{},
[] (int item) { return -item; },
-1
);
executor.run(taskflow).wait();
// input is {-2, -4, -7, -11, -16}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Scan for details.

◆ transform_reduce() [1/2]

template<typename B , typename E , typename T , typename BOP , typename UOP , Partitioner P = DefaultPartitioner>
Task tf::FlowBuilder::transform_reduce ( B first,
E last,
T & init,
BOP bop,
UOP uop,
P part = P() )

constructs an STL-styled parallel transform-reduce task

Template Parameters
Bbeginning iterator type
Eending iterator type
Tresult type
BOPbinary reducer type
UOPunary transformation type
Ptype satisfying tf::Partitioner
Parameters
firstiterator to the beginning (inclusive)
lastiterator to the end (exclusive)
initinitial value of the reduction and the storage for the reduced result
bopbinary operator that will be applied in unspecified order to the results of uop
uopunary operator that will be applied to transform each element in the range to the result type
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks to perform parallel reduction over init and the transformed elements in the range [first, last). The reduced result is store in init. This method is equivalent to the parallel execution of the following loop:

for(auto itr=first; itr!=last; itr++) {
init = bop(init, uop(*itr));
}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Reduction for details.

◆ transform_reduce() [2/2]

template<typename B1 , typename E1 , typename B2 , typename T , typename BOP_R , typename BOP_T , Partitioner P = DefaultPartitioner>
requires (!Partitioner<std::decay_t<BOP_T>>)
Task tf::FlowBuilder::transform_reduce ( B1 first1,
E1 last1,
B2 first2,
T & init,
BOP_R bop_r,
BOP_T bop_t,
P part = P() )

constructs an STL-styled parallel transform-reduce task

Template Parameters
B1first beginning iterator type
E1first ending iterator type
B2second beginning iterator type
Tresult type
BOP_Rbinary reducer type
BOP_Tbinary transformation type
Ptype satisfying tf::Partitioner
Parameters
first1iterator to the beginning of the first range (inclusive)
last1iterator to the end of the first range (exclusive)
first2iterator to the beginning of the second range
initinitial value of the reduction and the storage for the reduced result
bop_rbinary operator that will be applied in unspecified order to the results of bop_t
bop_tbinary operator that will be applied to transform each element in the range to the result type
partpartitioning algorithm to schedule parallel iterations
Returns
a tf::Task handle

The task spawns asynchronous tasks to perform parallel reduction over init and transformed elements in the range [first, last). The reduced result is store in init. This method is equivalent to the parallel execution of the following loop:

for(auto itr1=first1, itr2=first2; itr1!=last1; itr1++, itr2++) {
init = bop_r(init, bop_t(*itr1, *itr2));
}

Iterators can be made stateful by using std::reference_wrapper

Note
Please refer to Parallel Reduction for details.

The documentation for this class was generated from the following file: