EnTT: src/entt/graph/flow.hpp Source File

EnTT 3.16.0

Loading...
Searching...
No Matches
flow.hpp
1#ifndef ENTT_GRAPH_FLOW_HPP
2#define ENTT_GRAPH_FLOW_HPP
3
4#include <algorithm>
5#include <cstddef>
6#include <functional>
7#include <iterator>
8#include <memory>
9#include <type_traits>
10#include <utility>
11#include <vector>
12#include "../config/config.h"
13#include "../container/dense_map.hpp"
14#include "../container/dense_set.hpp"
15#include "../core/compressed_pair.hpp"
16#include "../core/fwd.hpp"
17#include "../core/iterator.hpp"
18#include "../core/utility.hpp"
19#include "adjacency_matrix.hpp"
20#include "fwd.hpp"
21
22namespace entt {
23
28template<typename Allocator>
29 class basic_flow {
30 using alloc_traits = std::allocator_traits<Allocator>;
31 static_assert(std::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
32 using task_container_type = dense_set<id_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
33 using ro_rw_container_type = std::vector<std::pair<std::size_t, bool>, typename alloc_traits::template rebind_alloc<std::pair<std::size_t, bool>>>;
34 using deps_container_type = dense_map<id_type, ro_rw_container_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
35 using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<std::size_t>>;
36
37 void emplace(const id_type res, const bool is_rw) {
38 ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
39
40 if(!deps.contains(res) && sync_on != vertices.size()) {
41 deps[res].emplace_back(sync_on, true);
42 }
43
44 deps[res].emplace_back(index.first(), is_rw);
45 }
46
47 void setup_graph(adjacency_matrix_type &matrix) const {
48 for(const auto &elem: deps) {
49 const auto last = elem.second.cend();
50 auto it = elem.second.cbegin();
51
52 while(it != last) {
53 if(it->second) {
54 // rw item
55 if(auto curr = it++; it != last) {
56 if(it->second) {
57 matrix.insert(curr->first, it->first);
58 } else if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
59 for(; it != next; ++it) {
60 matrix.insert(curr->first, it->first);
61 matrix.insert(it->first, next->first);
62 }
63 } else {
64 for(; it != next; ++it) {
65 matrix.insert(curr->first, it->first);
66 }
67 }
68 }
69 } else {
70 // ro item (first iteration only)
71 if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
72 for(; it != next; ++it) {
73 matrix.insert(it->first, next->first);
74 }
75 } else {
76 it = last;
77 }
78 }
79 }
80 }
81 }
82
83 void transitive_closure(adjacency_matrix_type &matrix) const {
84 const auto length = matrix.size();
85
86 for(std::size_t vk{}; vk < length; ++vk) {
87 for(std::size_t vi{}; vi < length; ++vi) {
88 for(std::size_t vj{}; vj < length; ++vj) {
89 if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
90 matrix.insert(vi, vj);
91 }
92 }
93 }
94 }
95 }
96
97 void transitive_reduction(adjacency_matrix_type &matrix) const {
98 const auto length = matrix.size();
99
100 for(std::size_t vert{}; vert < length; ++vert) {
101 matrix.erase(vert, vert);
102 }
103
104 for(std::size_t vj{}; vj < length; ++vj) {
105 for(std::size_t vi{}; vi < length; ++vi) {
106 if(matrix.contains(vi, vj)) {
107 for(std::size_t vk{}; vk < length; ++vk) {
108 if(matrix.contains(vj, vk)) {
109 matrix.erase(vi, vk);
110 }
111 }
112 }
113 }
114 }
115 }
116
117public:
119 using allocator_type = Allocator;
121 using size_type = std::size_t;
123 using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
125 using graph_type = adjacency_matrix_type;
126
128 basic_flow()
129 : basic_flow{allocator_type{}} {}
130
135 explicit basic_flow(const allocator_type &allocator)
136 : index{0u, allocator},
137 vertices{allocator},
138 deps{allocator} {}
139
141 basic_flow(const basic_flow &) = default;
142
148 basic_flow(const basic_flow &other, const allocator_type &allocator)
149 : index{other.index.first(), allocator},
150 vertices{other.vertices, allocator},
151 deps{other.deps, allocator},
152 sync_on{other.sync_on} {}
153
155 basic_flow(basic_flow &&) noexcept = default;
156
162 basic_flow(basic_flow &&other, const allocator_type &allocator)
163 : index{other.index.first(), allocator},
164 vertices{std::move(other.vertices), allocator},
165 deps{std::move(other.deps), allocator},
166 sync_on{other.sync_on} {}
167
169 ~basic_flow() = default;
170
175 basic_flow &operator=(const basic_flow &) = default;
176
181 basic_flow &operator=(basic_flow &&) noexcept = default;
182
187 void swap(basic_flow &other) noexcept {
188 using std::swap;
189 std::swap(index, other.index);
190 std::swap(vertices, other.vertices);
191 std::swap(deps, other.deps);
192 std::swap(sync_on, other.sync_on);
193 }
194
199 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
200 return allocator_type{index.second()};
201 }
202
208 [[nodiscard]] id_type operator[](const size_type pos) const {
209 return vertices.cbegin()[static_cast<typename task_container_type::difference_type>(pos)];
210 }
211
213 void clear() noexcept {
214 index.first() = {};
215 vertices.clear();
216 deps.clear();
217 sync_on = {};
218 }
219
224 [[nodiscard]] bool empty() const noexcept {
225 return vertices.empty();
226 }
227
232 [[nodiscard]] size_type size() const noexcept {
233 return vertices.size();
234 }
235
241 basic_flow &bind(const id_type value) {
242 sync_on += (sync_on == vertices.size());
243 const auto it = vertices.emplace(value).first;
244 index.first() = size_type(it - vertices.begin());
245 return *this;
246 }
247
252 basic_flow &sync() {
253 ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
254 sync_on = index.first();
255
256 for(const auto &elem: deps) {
257 elem.second.emplace_back(sync_on, true);
258 }
259
260 return *this;
261 }
262
269 basic_flow &set(const id_type res, bool is_rw = false) {
270 emplace(res, is_rw);
271 return *this;
272 }
273
279 basic_flow &ro(const id_type res) {
280 emplace(res, false);
281 return *this;
282 }
283
291 template<typename It>
292 std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
293 ro(It first, It last) {
294 for(; first != last; ++first) {
295 emplace(*first, false);
296 }
297
298 return *this;
299 }
300
306 basic_flow &rw(const id_type res) {
307 emplace(res, true);
308 return *this;
309 }
310
318 template<typename It>
319 std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
320 rw(It first, It last) {
321 for(; first != last; ++first) {
322 emplace(*first, true);
323 }
324
325 return *this;
326 }
327
332 [[nodiscard]] graph_type graph() const {
333 graph_type matrix{vertices.size(), get_allocator()};
334
335 setup_graph(matrix);
336 transitive_closure(matrix);
337 transitive_reduction(matrix);
338
339 return matrix;
340 }
341
342private:
343 compressed_pair<size_type, allocator_type> index;
344 task_container_type vertices;
345 deps_container_type deps;
346 size_type sync_on{};
347};
348
349} // namespace entt
350
351#endif
entt::adjacency_matrix
Basic implementation of a directed adjacency matrix.
Definition adjacency_matrix.hpp:96
entt::adjacency_matrix::insert
std::pair< edge_iterator, bool > insert(const vertex_type lhs, const vertex_type rhs)
Inserts an edge into the adjacency matrix, if it does not exist.
Definition adjacency_matrix.hpp:292
entt::adjacency_matrix::size
size_type size() const noexcept
Returns the number of vertices.
Definition adjacency_matrix.hpp:224
entt::adjacency_matrix::contains
bool contains(const vertex_type lhs, const vertex_type rhs) const
Checks if an adjacency matrix contains a given edge.
Definition adjacency_matrix.hpp:329
entt::adjacency_matrix::erase
size_type erase(const vertex_type lhs, const vertex_type rhs)
Removes the edge associated with a pair of given vertices.
Definition adjacency_matrix.hpp:311
entt::basic_flow
Utility class for creating task graphs.
Definition flow.hpp:29
entt::basic_flow::clear
void clear() noexcept
Clears the flow builder.
Definition flow.hpp:213
entt::basic_flow::operator[]
id_type operator[](const size_type pos) const
Returns the identifier at specified location.
Definition flow.hpp:208
entt::basic_flow::allocator_type
Allocator allocator_type
Allocator type.
Definition flow.hpp:119
entt::basic_flow::size
size_type size() const noexcept
Returns the number of tasks.
Definition flow.hpp:232
entt::basic_flow::iterable
iterable_adaptor< typename task_container_type::const_iterator > iterable
Iterable task list.
Definition flow.hpp:123
entt::basic_flow::size_type
std::size_t size_type
Unsigned integer type.
Definition flow.hpp:121
entt::basic_flow::sync
basic_flow & sync()
Turns the current task into a sync point.
Definition flow.hpp:252
entt::basic_flow::rw
basic_flow & rw(const id_type res)
Assigns a writable resource to the current task.
Definition flow.hpp:306
entt::basic_flow::rw
std::enable_if_t< std::is_same_v< std::remove_const_t< typename std::iterator_traits< It >::value_type >, id_type >, basic_flow & > rw(It first, It last)
Assigns a range of writable resources to the current task.
Definition flow.hpp:320
entt::basic_flow::get_allocator
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Definition flow.hpp:199
entt::basic_flow::graph
graph_type graph() const
Generates a task graph for the current content.
Definition flow.hpp:332
entt::basic_flow::basic_flow
basic_flow(const allocator_type &allocator)
Constructs a flow builder with a given allocator.
Definition flow.hpp:135
entt::basic_flow::graph_type
adjacency_matrix_type graph_type
Adjacency matrix type.
Definition flow.hpp:125
entt::basic_flow::~basic_flow
~basic_flow()=default
Default destructor.
entt::basic_flow::ro
basic_flow & ro(const id_type res)
Assigns a read-only resource to the current task.
Definition flow.hpp:279
entt::basic_flow::basic_flow
basic_flow(basic_flow &&) noexcept=default
Default move constructor.
entt::basic_flow::bind
basic_flow & bind(const id_type value)
Binds a task to a flow builder.
Definition flow.hpp:241
entt::basic_flow::set
basic_flow & set(const id_type res, bool is_rw=false)
Assigns a resource to the current task with a given access mode.
Definition flow.hpp:269
entt::basic_flow::operator=
basic_flow & operator=(basic_flow &&) noexcept=default
Default move assignment operator.
entt::basic_flow::basic_flow
basic_flow()
Default constructor.
Definition flow.hpp:128
entt::basic_flow::basic_flow
basic_flow(const basic_flow &other, const allocator_type &allocator)
Allocator-extended copy constructor.
Definition flow.hpp:148
entt::basic_flow<>::swap
void swap(basic_flow &other) noexcept
Definition flow.hpp:187
entt::basic_flow::empty
bool empty() const noexcept
Returns true if a flow builder contains no tasks, false otherwise.
Definition flow.hpp:224
entt::basic_flow::ro
std::enable_if_t< std::is_same_v< std::remove_const_t< typename std::iterator_traits< It >::value_type >, id_type >, basic_flow & > ro(It first, It last)
Assigns a range of read-only resources to the current task.
Definition flow.hpp:293
entt::basic_flow::operator=
basic_flow & operator=(const basic_flow &)=default
Default copy assignment operator.
entt::basic_flow::basic_flow
basic_flow(const basic_flow &)=default
Default copy constructor.
entt::compressed_pair
A compressed pair.
Definition compressed_pair.hpp:87
entt::dense_map
Associative container for key-value pairs with unique keys.
Definition dense_map.hpp:260
entt::dense_set
Associative container for unique objects of a given type.
Definition dense_set.hpp:220
entt::dense_set< id_type, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc< id_type > >::difference_type
std::ptrdiff_t difference_type
Definition dense_set.hpp:300
entt
EnTT default namespace.
Definition dense_map.hpp:22
entt::id_type
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
entt::iterable_adaptor
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:141