Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
Registry.tpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** R-Type
4** File description:
5** Registry.tpp
6*/
7
8#include "Registry.hpp"
9
10namespace rtp::ecs
11{
12 ///////////////////////////////////////////////////////////////////////////
13 // Public API
14 ///////////////////////////////////////////////////////////////////////////
15
16 template <Component T, typename Self>
17 auto Registry::subscribe(this Self &self)
18 -> std::expected<std::reference_wrapper<ConstLike<Self,
19 SparseArray<T>>>,
20 rtp::Error>
21 {
22 std::unique_lock lock(self._mutex);
23 std::type_index type = typeid(T);
24
25 if (self._arrays.contains(type)) [[unlikely]]
26 return std::unexpected{Error::failure(ErrorCode::InternalRuntimeError,
27 "Component already registered: {}",
28 type.name())};
29
30 auto [it, inserted] = self._arrays.emplace(
31 type, std::make_unique<SparseArray<T>>());
32 if (!inserted) [[unlikely]]
33 return std::unexpected{Error::failure(ErrorCode::InternalRuntimeError,
34 "Failed to register component: {}",
35 type.name())};
36
37 auto *rawPtr = static_cast<ConstLike<Self, SparseArray<T>> *>(it->second.get());
38 return std::ref(*rawPtr);
39 }
40
41 template <Component T, typename... Args>
42 auto Registry::add(Entity entity, Args &&...args)
43 -> std::expected<std::reference_wrapper<T>, rtp::Error>
44 {
45 std::unique_lock lock(this->_mutex);
46 std::type_index type = typeid(T);
47
48 if (!this->_arrays.contains(type)) [[unlikely]]
49 return std::unexpected{Error::failure(ErrorCode::ComponentMissing,
50 "Missing component: {}",
51 type.name())};
52
53 auto &ptr = this->_arrays.at(type);
54 auto *rawPtr = static_cast<SparseArray<T> *>(ptr.get());
55
56 return std::ref(rawPtr->emplace(entity, std::forward<Args>(args)...));
57 }
58
59 template <Component T, typename Self>
60 auto Registry::get(this const Self &self)
61 -> std::expected<std::reference_wrapper<ConstLike<Self,
62 SparseArray<T>>>,
63 rtp::Error>
64 {
65 std::shared_lock lock{self._mutex};
66 std::type_index type = typeid(T);
67
68 if (!self._arrays.contains(type)) [[unlikely]]
69 return std::unexpected{Error::failure(ErrorCode::ComponentMissing,
70 "Missing component: {}",
71 type.name())};
72
73 auto &ptr = self._arrays.find(type)->second;
74 auto *rawPtr = static_cast<SparseArray<T> *>(ptr.get());
75
76 return std::ref(*rawPtr);
77 }
78
79 template <Component T>
80 bool Registry::has(Entity entity) const noexcept
81 {
82 std::shared_lock lock{this->_mutex};
83 std::type_index type = typeid(T);
84
85 if (!this->_arrays.contains(type))
86 return false;
87
88 auto &ptr = this->_arrays.find(type)->second;
89 auto *rawPtr = static_cast<SparseArray<T> *>(ptr.get());
90
91 return rawPtr->has(entity);
92 }
93
94 template <Component T>
95 void Registry::remove(Entity entity) noexcept
96 {
97 std::type_index type = typeid(T);
98
99 {
100 std::shared_lock lock{this->_mutex};
101
102 if (!this->_arrays.contains(type)) [[unlikely]]
103 return;
104 }
105
106 {
107 std::unique_lock lock{this->_mutex};
108
109 if (!this->_arrays.contains(type)) [[unlikely]]
110 return;
111 auto &ptr = this->_arrays.find(type)->second;
112 auto *rawPtr = static_cast<SparseArray<T> *>(ptr.get());
113
114 rawPtr->erase(entity);
115 }
116 }
117
118 template <Component... Ts, typename Self>
119 auto Registry::view(this Self &self)
120 {
121 std::shared_lock lock{self._mutex};
122
123 if constexpr (sizeof...(Ts) == 1) {
124 using T = std::tuple_element_t<0, std::tuple<Ts...>>;
125 auto result = self.template get<T>();
126 if (!result.has_value()) {
127 return std::span<ConstLike<Self, T>>{};
128 }
129 return result->get().data();
130 } else {
131 auto &base = self.template getSmallestArray<Ts...>();
132 return std::views::iota(std::size_t{0}, base.size())
133 | std::views::transform([&](std::size_t i) {
134 Entity e = base.entities()[i];
135 return std::tuple<Entity, Ts&...>(
136 e, self.template getArray<Ts>()[e]...);
137 })
138 | std::views::filter([&](auto const &t) {
139 Entity e = std::get<0>(t);
140 return (self.template getArray<Ts>().has(e) && ...);
141 });
142 }
143 }
144
145 template <Component... Ts, typename Self>
146 auto Registry::zipView(this Self &self)
147 {
148 std::shared_lock lock{self._mutex};
149
150 auto get_array = [&]<typename T>() -> ConstLikeRef<Self, SparseArray<T>> {
151 std::type_index index(typeid(T));
152
153 if (self._arrays.find(index) == self._arrays.end()) {
154 throw rtp::Error::failure(ErrorCode::ComponentMissing,
155 "Component not registered in zipView: {}",
156 typeid(T).name());
157 }
158
159 return static_cast<ConstLikeRef<Self, SparseArray<T>>>(*self._arrays.at(index));
160 };
161
162 return ZipView<ConstLikeRef<Self, SparseArray<Ts>>...>(
163 get_array.template operator()<Ts>()...);
164 }
165
166 ///////////////////////////////////////////////////////////////////////////
167 // Private API
168 ///////////////////////////////////////////////////////////////////////////
169
170 template <Component T, typename Self>
171 auto Registry::getArray(this Self &self) -> ConstLikeRef<Self, SparseArray<T>>
172 {
173 std::shared_lock lock{self._mutex};
174
175 auto it = self._arrays.find(typeid(T));
176 if (it == self._arrays.end()) [[unlikely]]
177 throw rtp::Error::failure(ErrorCode::ComponentMissing,
178 "Component not registered: {}",
179 typeid(T).name());
180
181 return static_cast<ConstLikeRef<Self, SparseArray<T>>>(*it->second);
182 }
183
184 template <Component T, Component... Ts, typename Self>
185 auto &Registry::getSmallestArray(this Self &self)
186 {
187 if constexpr (sizeof...(Ts) == 0) {
188 return self.template getArray<T>();
189 } else {
190 auto &firstArray = self.template getArray<T>();
191 auto &restSmallest = self.template getSmallestArray<Ts...>();
192
193 return (firstArray.size() < restSmallest.size()) ? firstArray
194 : restSmallest;
195 }
196 }
197
198 template <Component... Ts>
199 bool Registry::hasAllComponents(Entity entity) const noexcept
200 {
201 return (... && this->has<Ts>(entity));
202 }
203}