1#ifndef LIBSBX_CONTAINERS_TASK_GRAPH_HPP_
2#define LIBSBX_CONTAINERS_TASK_GRAPH_HPP_
13namespace sbx::containers {
17enum class node_state : std::uint32_t {
19 conditioned = 0x10000000,
20 preempted = 0x20000000,
21 retain_subflow = 0x40000000,
22 joined_subflow = 0x80000000
25enum class error_state : std::uint32_t {
27 exception = 0x10000000,
28 cancelled = 0x20000000,
32template<
typename T,
typename>
35template<std::size_t I,
typename... Ts>
38template<std::size_t I,
typename T,
typename... Ts>
39struct get_index_impl<I, T, T, Ts...> : std::integral_constant<std::size_t, I>{};
41template<std::size_t I,
typename T,
typename U,
typename... Ts>
44template<
typename T,
typename... Ts>
47template<
typename T,
typename... Ts>
48constexpr auto get_index_v =
get_index<T, Ts...>::value;
56class graph_base : std::vector<std::unique_ptr<graph_node>> {
61 using base = std::vector<std::unique_ptr<graph_node>>;
77 auto _reserve(
const std::size_t capacity) -> void;
81 template<
typename... Args>
82 auto _emplace_back(Args&&... args) ->
graph_node*;
93template<
typename Type>
94constexpr bool is_task_params_v = std::is_same_v<std::decay_t<Type>,
task_parameters> || std::is_same_v<std::decay_t<Type>,
default_task_parameters> || std::is_constructible_v<std::string, Type>;
96template<
typename Callable,
typename =
void>
99template<
typename Callable>
100struct is_static_task<Callable, std::enable_if_t<std::is_invocable_v<Callable>>> : std::is_same<std::invoke_result_t<Callable>, void> { };
102template <
typename Callable>
110 using placeholder_task = std::monostate;
114 template<
typename Callable>
115 static_task(Callable&& callable);
117 std::function<void()> work;
122 template<
typename Callable>
123 sub_graph(Callable&& callable);
125 std::function<void(sub_graph&)> work;
130 using task_handle = std::variant<placeholder_task, static_task>;
134 inline static constexpr auto placeholder = get_index_v<placeholder_task, task_handle>;
135 inline static constexpr auto static_work = get_index_v<static_task, task_handle>;
139 template<
typename... Args>
142 template<
typename... Args>
145 auto num_successors()
const -> std::size_t;
146 auto num_predecessors()
const -> std::size_t;
148 auto name()
const ->
const std::string&;
161 std::size_t _num_successors;
162 std::vector<graph_node*> _edges;
173 auto name()
const ->
const std::string&;
175 auto num_predecessors()
const -> std::size_t;
176 auto num_successors()
const -> std::size_t;
178 template<
typename... Tasks>
179 auto precede(Tasks&&... tasks) ->
task&;
181 template<
typename... Tasks>
182 auto succeed(Tasks&&... tasks) ->
task&;
198 template <
typename Callable>
199 requires (is_static_task_v<Callable>)
200 auto emplace(Callable&& callable) ->
task;
202 template<
typename... Callables>
203 requires (
sizeof...(Callables) > 1u)
204 auto emplace(Callables&&... callables) ->
decltype(
auto);
228auto graph_base::_reserve(
const std::size_t capacity) ->
void {
229 base::reserve(capacity);
232auto graph_base::_erase(graph_node*
node) ->
void {
233 base::erase(std::remove_if(base::begin(), base::end(), [&](
auto& entry){
return entry.get() ==
node; }), base::end() );
236template<
typename... Args>
237auto graph_base::_emplace_back(Args&&... args) -> graph_node* {
238 base::push_back(std::make_unique<graph_node>(std::forward<Args>(args)...));
242template<
typename Callable>
243graph_node::static_task::static_task(Callable&& callable)
244: work{std::forward<Callable>(callable)} { }
246template<
typename Callable>
247graph_node::sub_graph::sub_graph(Callable&& callable)
248: work{std::forward<Callable>(callable)} { }
250graph_node::graph_node()
251: _state{node_state::none},
254 _num_successors{0u} { }
256template<
typename... Args>
257graph_node::graph_node(node_state node_state,
const task_parameters& parameters, graph_node* parent, Args&&... args)
259 _name{parameters.name},
260 _data{parameters.data},
263 _handle{std::forward<Args>(args)...} { }
265template<
typename... Args>
266graph_node::graph_node(node_state node_state,
const default_task_parameters& parameters, graph_node* parent, Args&&...args)
271 _handle{std::forward<Args>(args)...} { }
273auto graph_node::num_successors() const -> std::
size_t {
274 return _num_successors;
277auto graph_node::num_predecessors() const -> std::
size_t {
278 return _edges.size() - _num_successors;
281auto graph_node::name() const -> const std::
string& {
285auto graph_node::_precede(graph_node*
node) ->
void {
286 _edges.push_back(
node);
287 std::swap(_edges[_num_successors++], _edges[_edges.size() - 1]);
288 node->_edges.push_back(
this);
291auto graph_node::_remove_successors(graph_node*
node) ->
void {
292 auto sit = std::remove(_edges.begin(), _edges.begin() + _num_successors,
node);
293 size_t new_num_successors = std::distance(_edges.begin(), sit);
294 std::move(_edges.begin() + _num_successors, _edges.end(), sit);
295 _edges.resize(_edges.size() - (_num_successors - new_num_successors));
296 _num_successors = new_num_successors;
299auto graph_node::_remove_predecessors(graph_node*
node) ->
void {
300 _edges.erase(std::remove(_edges.begin() + _num_successors, _edges.end(),
node), _edges.end());
303auto task::name() const -> const std::
string& {
304 return _node->name();
307auto task::num_predecessors() const -> std::
size_t {
308 return _node->num_predecessors();
311auto task::num_successors() const -> std::
size_t {
312 return _node->num_predecessors();
315template<
typename... Tasks>
316auto task::precede(Tasks&&... tasks) -> task& {
317 (_node->_precede(tasks._node), ...);
321template<
typename... Tasks>
322auto task::succeed(Tasks&&... tasks) -> task& {
323 (tasks._node->_precede(_node), ...);
327task::task(graph_node*
node)
330graph_builder::graph_builder(graph_base& graph)
333template <
typename Callable>
334requires (is_static_task_v<Callable>)
335auto graph_builder::emplace(Callable&& callable) -> task {
336 return task{_graph._emplace_back(node_state::none, default_task_parameters{},
nullptr, std::in_place_type_t<graph_node::static_task>{}, std::forward<Callable>(callable) )};
339template<
typename... Callables>
340requires (
sizeof...(Callables) > 1u)
341auto graph_builder::emplace(Callables&&... callables) ->
decltype(
auto) {
342 _graph.reserve(
sizeof...(Callables));
343 return std::make_tuple(emplace(std::forward<Callables>(callables))...);
Definition: task_graph.hpp:56
Definition: task_graph.hpp:192
Definition: task_graph.hpp:105
Definition: task_graph.hpp:214
Definition: task_graph.hpp:167
Definition: task_graph.hpp:348
Definition: task_graph.hpp:91
Definition: task_graph.hpp:36
Definition: task_graph.hpp:33
Definition: task_graph.hpp:97
Definition: task_graph.hpp:86