EnTT 3.16.0
Loading...
Searching...
No Matches
organizer.hpp
1#ifndef ENTT_ENTITY_ORGANIZER_HPP
2#define ENTT_ENTITY_ORGANIZER_HPP
3
4#include <cstddef>
5#include <type_traits>
6#include <utility>
7#include <vector>
8#include "../core/type_info.hpp"
9#include "../core/type_traits.hpp"
10#include "../core/utility.hpp"
11#include "../graph/adjacency_matrix.hpp"
12#include "../graph/flow.hpp"
13#include "fwd.hpp"
14#include "helper.hpp"
15
16namespace entt {
17
19namespace internal {
20
21template<typename>
22struct is_view: std::false_type {};
23
24template<typename... Args>
25struct is_view<basic_view<Args...>>: std::true_type {};
26
27template<typename Type>
28inline constexpr bool is_view_v = is_view<Type>::value;
29
30template<typename>
31struct is_group: std::false_type {};
32
33template<typename... Args>
34struct is_group<basic_group<Args...>>: std::true_type {};
35
36template<typename Type>
37inline constexpr bool is_group_v = is_group<Type>::value;
38
39template<typename Type, typename Override>
40struct unpack_type {
41 using ro = std::conditional_t<
42 type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
43 type_list<std::remove_const_t<Type>>,
44 type_list<>>;
45
46 using rw = std::conditional_t<
47 type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
48 type_list<Type>,
49 type_list<>>;
50};
51
52template<typename... Args, typename... Override>
53struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
54 using ro = type_list<>;
55 using rw = type_list<>;
56};
57
58template<typename... Args, typename... Override>
59struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
60 : unpack_type<basic_registry<Args...>, type_list<Override...>> {};
61
62template<typename... Get, typename... Exclude, typename... Override>
63struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
64 using ro = type_list_cat_t<type_list<typename Exclude::element_type...>, typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::ro...>;
65 using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::rw...>;
66};
67
68template<typename... Get, typename... Exclude, typename... Override>
69struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
70 : unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
71
72template<typename... Owned, typename... Get, typename... Exclude, typename... Override>
73struct unpack_type<basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
74 using ro = type_list_cat_t<type_list<typename Exclude::element_type...>, typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::ro..., typename unpack_type<constness_as_t<typename Owned::element_type, Owned>, type_list<Override...>>::ro...>;
75 using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::rw..., typename unpack_type<constness_as_t<typename Owned::element_type, Owned>, type_list<Override...>>::rw...>;
76};
77
78template<typename... Owned, typename... Get, typename... Exclude, typename... Override>
79struct unpack_type<const basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
80 : unpack_type<basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
81
82template<typename, typename, typename>
83struct resource_traits;
84
85template<typename Registry, typename... Args, typename... Req>
86struct resource_traits<Registry, type_list<Args...>, type_list<Req...>> {
87 using args = type_list<std::remove_const_t<Args>...>;
88 using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
89 using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
90 static constexpr auto sync_point = (std::is_same_v<Args, Registry> || ...);
91};
92
93template<typename Registry, typename... Req, typename Ret, typename... Args>
94resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
95
96template<typename Registry, typename... Req, typename Ret, typename Type, typename... Args>
97resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
98
99template<typename Registry, typename... Req, typename Ret, typename Class, typename... Args>
100resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
101
102template<typename Registry, typename... Req, typename Ret, typename Class, typename... Args>
103resource_traits<Registry, type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
104
105} // namespace internal
107
119template<typename Registry>
120class basic_organizer final {
121 using callback_type = void(const void *, Registry &);
122 using prepare_type = void(Registry &);
123 using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
124
125 struct vertex_data final {
126 std::size_t ro_count{};
127 std::size_t rw_count{};
128 const char *name{};
129 const void *payload{};
130 callback_type *callback{};
131 dependency_type *dependency{};
132 prepare_type *prepare{};
133 const type_info *info{};
134 };
135
136 template<typename Type>
137 [[nodiscard]] static decltype(auto) extract(Registry &reg) {
138 if constexpr(std::is_same_v<Type, Registry>) {
139 return reg;
140 } else if constexpr(internal::is_view_v<Type>) {
141 return static_cast<Type>(as_view{reg});
142 } else if constexpr(internal::is_group_v<Type>) {
143 return static_cast<Type>(as_group{reg});
144 } else {
145 return reg.ctx().template emplace<std::remove_reference_t<Type>>();
146 }
147 }
148
149 template<typename... Args>
150 [[nodiscard]] static auto to_args(Registry &reg, type_list<Args...>) {
151 return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
152 }
153
154 template<typename... Type>
155 [[nodiscard]] static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
156 if constexpr(sizeof...(Type) == 0u) {
157 return {};
158 } else {
159 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
160 const type_info *info[]{&type_id<Type>()...};
161 const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
162
163 for(std::size_t pos{}; pos < length; ++pos) {
164 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
165 buffer[pos] = info[pos];
166 }
167
168 return length;
169 }
170 }
171
172 template<typename... RO, typename... RW>
173 void track_dependencies(std::size_t index, const bool sync_point, type_list<RO...>, type_list<RW...>) {
174 builder.bind(static_cast<id_type>(index));
175 builder.set(type_hash<Registry>::value(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u));
176 (builder.ro(type_hash<RO>::value()), ...);
177 (builder.rw(type_hash<RW>::value()), ...);
178 }
179
180public:
182 using registry_type = Registry;
186 using size_type = std::size_t;
188 using function_type = callback_type;
189
191 struct vertex {
198 vertex(vertex_data data, std::vector<std::size_t> from, std::vector<std::size_t> to)
199 : node{std::move(data)},
200 in{std::move(from)},
201 out{std::move(to)} {}
202
210 [[nodiscard]] size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
211 return node.dependency(false, buffer, length);
212 }
213
221 [[nodiscard]] size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
222 return node.dependency(true, buffer, length);
223 }
224
229 [[nodiscard]] size_type ro_count() const noexcept {
230 return node.ro_count;
231 }
232
237 [[nodiscard]] size_type rw_count() const noexcept {
238 return node.rw_count;
239 }
240
245 [[nodiscard]] bool top_level() const noexcept {
246 return in.empty();
247 }
248
253 [[nodiscard]] const type_info &info() const noexcept {
254 return *node.info;
255 }
256
261 [[nodiscard]] const char *name() const noexcept {
262 return node.name;
263 }
264
269 [[nodiscard]] function_type *callback() const noexcept {
270 return node.callback;
271 }
272
277 [[nodiscard]] const void *data() const noexcept {
278 return node.payload;
279 }
280
285 [[nodiscard]] const std::vector<std::size_t> &in_edges() const noexcept {
286 return in;
287 }
288
293 [[nodiscard]] const std::vector<std::size_t> &out_edges() const noexcept {
294 return out;
295 }
296
302 void prepare(registry_type &reg) const {
303 node.prepare ? node.prepare(reg) : void();
304 }
305
306 private:
307 vertex_data node;
308 std::vector<std::size_t> in;
309 std::vector<std::size_t> out;
310 };
311
318 template<auto Candidate, typename... Req>
319 void emplace(const char *name = nullptr) {
320 using resource_type = decltype(internal::free_function_to_resource_traits<registry_type, Req...>(Candidate));
321
322 callback_type *callback = +[](const void *, registry_type &reg) {
323 std::apply(Candidate, to_args(reg, typename resource_type::args{}));
324 };
325
326 vertex_data vdata{
327 resource_type::ro::size,
328 resource_type::rw::size,
329 name,
330 nullptr,
331 callback,
332 +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
333 +[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
334 &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
335
336 track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
337 vertices.push_back(std::move(vdata));
338 }
339
349 template<auto Candidate, typename... Req, typename Type>
350 void emplace(Type &value_or_instance, const char *name = nullptr) {
351 using resource_type = decltype(internal::constrained_function_to_resource_traits<registry_type, Req...>(Candidate));
352
353 callback_type *callback = +[](const void *payload, registry_type &reg) {
354 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
355 std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
356 };
357
358 vertex_data vdata{
359 resource_type::ro::size,
360 resource_type::rw::size,
361 name,
362 &value_or_instance,
363 callback,
364 +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
365 +[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
366 &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
367
368 track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
369 vertices.push_back(std::move(vdata));
370 }
371
380 template<typename... Req>
381 void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
382 using resource_type = internal::resource_traits<registry_type, type_list<>, type_list<Req...>>;
383 track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
384
385 vertex_data vdata{
386 resource_type::ro::size,
387 resource_type::rw::size,
388 name,
389 payload,
390 func,
391 +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
392 nullptr,
393 &type_id<void>()};
394
395 vertices.push_back(std::move(vdata));
396 }
397
402 [[nodiscard]] std::vector<vertex> graph() const {
403 std::vector<vertex> adjacency_list{};
404 adjacency_list.reserve(vertices.size());
405 auto adjacency_matrix = builder.graph();
406
407 for(auto curr: adjacency_matrix.vertices()) {
408 std::vector<std::size_t> in{};
409 std::vector<std::size_t> out{};
410
411 for(auto &&edge: adjacency_matrix.in_edges(curr)) {
412 in.push_back(edge.first);
413 }
414
415 for(auto &&edge: adjacency_matrix.out_edges(curr)) {
416 out.push_back(edge.second);
417 }
418
419 adjacency_list.emplace_back(vertices[curr], std::move(in), std::move(out));
420 }
421
422 return adjacency_list;
423 }
424
426 void clear() {
427 builder.clear();
428 vertices.clear();
429 }
430
431private:
432 std::vector<vertex_data> vertices;
433 flow builder;
434};
435
436} // namespace entt
437
438#endif
Basic implementation of a directed adjacency matrix.
iterable_adaptor< out_edge_iterator > out_edges(const vertex_type vertex) const noexcept
Returns an iterable object to visit all out-edges of a vertex.
iterable_adaptor< in_edge_iterator > in_edges(const vertex_type vertex) const noexcept
Returns an iterable object to visit all in-edges of a vertex.
iterable_adaptor< vertex_iterator > vertices() const noexcept
Returns an iterable object to visit all vertices of a matrix.
Converts a registry to a group.
Definition helper.hpp:61
Converts a registry to a view.
Definition helper.hpp:22
Utility class for creating a static task graph.
std::vector< vertex > graph() const
Generates a task graph for the current content.
void clear()
Erases all elements from a container.
void emplace(const char *name=nullptr)
Adds a free function to the task list.
void emplace(function_type *func, const void *payload=nullptr, const char *name=nullptr)
Adds an user defined function with optional payload to the task list.
void emplace(Type &value_or_instance, const char *name=nullptr)
Adds a free function with payload or a member function with an instance to the task list.
typename registry_type::entity_type entity_type
typename traits_type::value_type entity_type
Definition registry.hpp:308
EnTT default namespace.
Definition dense_map.hpp:22
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
typename type_list_cat< List... >::type type_list_cat_t
Helper type.
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:29
basic_flow<> flow
Alias declaration for the most common use case.
Definition fwd.hpp:23
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept
Fills a buffer with the type info objects for the writable resources of a vertex.
size_type ro_count() const noexcept
Returns the number of read-only resources of a vertex.
const type_info & info() const noexcept
Returns a type info object associated with a vertex.
function_type * callback() const noexcept
Returns the function associated with a vertex.
const std::vector< std::size_t > & in_edges() const noexcept
Returns the list of in-edges of a vertex.
const std::vector< std::size_t > & out_edges() const noexcept
Returns the list of out-edges of a vertex.
void prepare(registry_type &reg) const
Prepares a registry and assures that all required resources are properly instantiated before using th...
size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept
Fills a buffer with the type info objects for the read-only resources of a vertex.
const char * name() const noexcept
Returns a user defined name associated with a vertex, if any.
const void * data() const noexcept
Returns the payload associated with a vertex, if any.
vertex(vertex_data data, std::vector< std::size_t > from, std::vector< std::size_t > to)
Constructs a vertex of the task graph.
size_type rw_count() const noexcept
Returns the number of writable resources of a vertex.
bool top_level() const noexcept
Checks if a vertex is also a top-level one.
static constexpr id_type value() noexcept
Returns the numeric representation of a given type.
Implementation specific information about a type.
A class to use to push around lists of types, nothing more.