EnTT 3.13.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 Type, typename Override>
31struct unpack_type {
32 using ro = std::conditional_t<
33 type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
34 type_list<std::remove_const_t<Type>>,
35 type_list<>>;
36
37 using rw = std::conditional_t<
38 type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
39 type_list<Type>,
40 type_list<>>;
41};
42
43template<typename... Args, typename... Override>
44struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
45 using ro = type_list<>;
46 using rw = type_list<>;
47};
48
49template<typename... Args, typename... Override>
50struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
51 : unpack_type<basic_registry<Args...>, type_list<Override...>> {};
52
53template<typename... Get, typename... Exclude, typename... Override>
54struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
55 using ro = type_list_cat_t<type_list<typename Exclude::value_type...>, typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::ro...>;
56 using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::rw...>;
57};
58
59template<typename... Get, typename... Exclude, typename... Override>
60struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
61 : unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
62
63template<typename, typename>
64struct resource_traits;
65
66template<typename... Args, typename... Req>
67struct resource_traits<type_list<Args...>, type_list<Req...>> {
68 using args = type_list<std::remove_const_t<Args>...>;
69 using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
70 using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
71};
72
73template<typename... Req, typename Ret, typename... Args>
74resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
75
76template<typename... Req, typename Ret, typename Type, typename... Args>
77resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
78
79template<typename... Req, typename Ret, typename Class, typename... Args>
80resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
81
82template<typename... Req, typename Ret, typename Class, typename... Args>
83resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
84
85} // namespace internal
99template<typename Registry>
100class basic_organizer final {
101 using callback_type = void(const void *, Registry &);
102 using prepare_type = void(Registry &);
103 using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
104
105 struct vertex_data final {
106 std::size_t ro_count{};
107 std::size_t rw_count{};
108 const char *name{};
109 const void *payload{};
110 callback_type *callback{};
111 dependency_type *dependency;
112 prepare_type *prepare{};
113 const type_info *info{};
114 };
115
116 template<typename Type>
117 [[nodiscard]] static decltype(auto) extract(Registry &reg) {
118 if constexpr(std::is_same_v<Type, Registry>) {
119 return reg;
120 } else if constexpr(internal::is_view_v<Type>) {
121 return static_cast<Type>(as_view{reg});
122 } else {
123 return reg.ctx().template emplace<std::remove_reference_t<Type>>();
124 }
125 }
126
127 template<typename... Args>
128 [[nodiscard]] static auto to_args(Registry &reg, type_list<Args...>) {
129 return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
130 }
131
132 template<typename... Type>
133 static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
134 if constexpr(sizeof...(Type) == 0u) {
135 return {};
136 } else {
137 const type_info *info[sizeof...(Type)]{&type_id<Type>()...};
138 const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
139
140 for(std::size_t pos{}; pos < length; ++pos) {
141 buffer[pos] = info[pos];
142 }
143
144 return length;
145 }
146 }
147
148 template<typename... RO, typename... RW>
149 void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
150 builder.bind(static_cast<id_type>(index));
151 builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
152 (builder.ro(type_hash<RO>::value()), ...);
153 (builder.rw(type_hash<RW>::value()), ...);
154 }
155
156public:
158 using registry_type = Registry;
160 using entity_type = typename registry_type::entity_type;
162 using size_type = std::size_t;
164 using function_type = callback_type;
165
167 struct vertex {
174 vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges)
175 : is_top_level{vtype},
176 node{std::move(data)},
177 reachable{std::move(edges)} {}
178
186 size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
187 return node.dependency(false, buffer, length);
188 }
189
197 size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
198 return node.dependency(true, buffer, length);
199 }
200
205 size_type ro_count() const noexcept {
206 return node.ro_count;
207 }
208
213 size_type rw_count() const noexcept {
214 return node.rw_count;
215 }
216
221 bool top_level() const noexcept {
222 return is_top_level;
223 }
224
229 const type_info &info() const noexcept {
230 return *node.info;
231 }
232
237 const char *name() const noexcept {
238 return node.name;
239 }
240
245 function_type *callback() const noexcept {
246 return node.callback;
247 }
248
253 const void *data() const noexcept {
254 return node.payload;
255 }
256
261 const std::vector<std::size_t> &children() const noexcept {
262 return reachable;
263 }
264
270 void prepare(registry_type &reg) const {
271 node.prepare ? node.prepare(reg) : void();
272 }
273
274 private:
275 bool is_top_level;
276 vertex_data node;
277 std::vector<std::size_t> reachable;
278 };
279
286 template<auto Candidate, typename... Req>
287 void emplace(const char *name = nullptr) {
288 using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
289 constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
290
291 callback_type *callback = +[](const void *, registry_type &reg) {
292 std::apply(Candidate, to_args(reg, typename resource_type::args{}));
293 };
294
295 vertex_data vdata{
296 resource_type::ro::size,
297 resource_type::rw::size,
298 name,
299 nullptr,
300 callback,
301 +[](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); },
302 +[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
303 &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
304
305 track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
306 vertices.push_back(std::move(vdata));
307 }
308
318 template<auto Candidate, typename... Req, typename Type>
319 void emplace(Type &value_or_instance, const char *name = nullptr) {
320 using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
321 constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
322
323 callback_type *callback = +[](const void *payload, registry_type &reg) {
324 Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
325 std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
326 };
327
328 vertex_data vdata{
329 resource_type::ro::size,
330 resource_type::rw::size,
331 name,
332 &value_or_instance,
333 callback,
334 +[](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); },
335 +[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
336 &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
337
338 track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
339 vertices.push_back(std::move(vdata));
340 }
341
350 template<typename... Req>
351 void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
352 using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
353 track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
354
355 vertex_data vdata{
356 resource_type::ro::size,
357 resource_type::rw::size,
358 name,
359 payload,
360 func,
361 +[](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); },
362 nullptr,
363 &type_id<void>()};
364
365 vertices.push_back(std::move(vdata));
366 }
367
372 std::vector<vertex> graph() {
373 std::vector<vertex> adjacency_list{};
374 adjacency_list.reserve(vertices.size());
375 auto adjacency_matrix = builder.graph();
376
377 for(auto curr: adjacency_matrix.vertices()) {
378 const auto iterable = adjacency_matrix.in_edges(curr);
379 std::vector<std::size_t> reachable{};
380
381 for(auto &&edge: adjacency_matrix.out_edges(curr)) {
382 reachable.push_back(edge.second);
383 }
384
385 adjacency_list.emplace_back(iterable.cbegin() == iterable.cend(), vertices[curr], std::move(reachable));
386 }
387
388 return adjacency_list;
389 }
390
392 void clear() {
393 builder.clear();
394 vertices.clear();
395 }
396
397private:
398 std::vector<vertex_data> vertices;
399 flow builder;
400};
401
402} // namespace entt
403
404#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 view.
Definition helper.hpp:22
void clear() noexcept
Clears the flow builder.
Definition flow.hpp:199
basic_flow & rw(const id_type res)
Assigns a writable resource to the current task.
Definition flow.hpp:296
graph_type graph() const
Generates a task graph for the current content.
Definition flow.hpp:322
basic_flow & ro(const id_type res)
Assigns a read-only resource to the current task.
Definition flow.hpp:269
basic_flow & bind(const id_type value)
Binds a task to a flow builder.
Definition flow.hpp:231
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:259
Utility class for creating a static task graph.
std::vector< vertex > graph()
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.
callback_type function_type
Raw task function type.
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
Underlying entity identifier.
std::size_t size_type
Unsigned integer type.
EnTT default namespace.
Definition dense_map.hpp:21
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
std::uint32_t id_type
Alias declaration for type identifiers.
Definition fwd.hpp:13
typename type_list_cat< List... >::type type_list_cat_t
Helper type.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
Vertex type of a task graph defined as an adjacency list.
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 > & children() const noexcept
Returns the list of nodes reachable from a given 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.
vertex(const bool vtype, vertex_data data, std::vector< std::size_t > edges)
Constructs a vertex of the task graph.
const void * data() const noexcept
Returns the payload associated with a vertex, if any.
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.
Type hash.
Definition type_info.hpp:92
Implementation specific information about a type.
A class to use to push around lists of types, nothing more.