Air-Trap 1.0.0
A multiplayer R-Type clone game engine built with C++23 and ECS architecture
Loading...
Searching...
No Matches
SparseArray.tpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** R-Type
4** File description:
5** SparseArray.tpp
6*/
7
8/*
9** MIT License
10**
11** Copyright (c) 2025 Robin Toillon
12**
13** Permission is hereby granted, free of charge, to any person obtaining
14** a copy of this software and associated documentation files (the
15** "Software"), to deal in the Software without restriction, including
16** without limitation the rights to use, copy, modify, merge, publish,
17** distribute, sublicense, and/or sell copies of the Software, and to
18** permit persons to whom the Software is furnished to do so, subject to
19** the following conditions:
20**
21** The above copyright notice and this permission notice shall be
22** included in all copies or substantial portions of the Software.
23**
24** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31*/
32
33/**
34 * @file SparseArray.tpp
35 * @brief SparseArray template implementations
36 * @author Robin Toillon
37 * @details Implements the sparse set data structure operations
38 * including insertion, removal, lookup, and iteration over components
39 * with O(1) access by entity ID.
40 */
41
42#include <algorithm>
43
44namespace rtp::ecs
45{
46 template <Component T>
47 void SparseArray<T>::erase(Entity entity) noexcept
48 {
49 if (!this->has(entity))
50 return;
51
52 size_t indexRemoved = this->_sparse[entity.index()];
53 size_t indexLast = this->_data.size() - 1;
54 Entity entityLast = this->_dense[indexLast];
55
56 if (indexRemoved != indexLast) {
57 this->_data[indexRemoved] = std::move(this->_data.back());
58 this->_dense[indexRemoved] = entityLast;
59 this->_sparse[entityLast.index()] = indexRemoved;
60 }
61
62 this->_data.pop_back();
63 this->_dense.pop_back();
64
65 this->_sparse[entity.index()] = NullIndex;
66 }
67
68 template <Component T>
69 bool SparseArray<T>::has(Entity entity) const noexcept
70 {
71 return entity.index() < this->_sparse.size()
72 && this->_sparse[entity.index()] != NullIndex
73 && this->_dense[this->_sparse[entity.index()]] == entity;
74 }
75
76 template <Component T>
77 void SparseArray<T>::clear(void) noexcept
78 {
79 this->_data.clear();
80 this->_dense.clear();
81 std::fill(this->_sparse.begin(), this->_sparse.end(), NullIndex);
82 }
83
84 template <Component T>
85 template <typename Self>
86 auto &&SparseArray<T>::operator[](this Self &self, Entity entity) noexcept
87 {
88 RTP_ASSERT(self.has(entity),
89 "SparseArray: Entity {} does not have component " \
90 "(Index out of bounds)", entity.index());
91
92 size_t index = self._sparse[entity.index()];
93
94 return std::forward_like<Self>(self)._data[index];
95 }
96
97 template <Component T>
98 template <typename... Args>
99 T &SparseArray<T>::emplace(Entity entity, Args &&...args)
100 {
101 if (entity.index() >= this->_sparse.size())
102 this->_sparse.resize(entity.index() + 1, NullIndex);
103
104 size_t index = this->_sparse[entity.index()];
105 if (index != NullIndex) {
106 this->_data[index] = T(std::forward<Args>(args)...);
107 return this->_data[index];
108 }
109
110 index = this->_data.size();
111 this->_sparse[entity.index()] = index;
112 this->_dense.push_back(entity);
113
114 return this->_data.emplace_back(std::forward<Args>(args)...);
115 }
116
117#if defined(__GNUC__) || defined(__clang__)
118 // C++23 explicit object parameter implementation
119 template <Component T>
120 template <typename Self>
121 auto SparseArray<T>::data(this Self &&self) noexcept
122 {
123 if constexpr (std::is_const_v<std::remove_reference_t<Self>>) {
124 return std::span<const T>{self._data};
125 } else {
126 return std::span<T>{self._data};
127 }
128 }
129#else
130 // Traditional overloads for MSVC
131 template <Component T>
132 std::span<T> SparseArray<T>::data() noexcept
133 {
134 return std::span<T>{_data};
135 }
136
137 template <Component T>
138 std::span<const T> SparseArray<T>::data() const noexcept
139 {
140 return std::span<const T>{_data};
141 }
142#endif
143
144#if defined(__GNUC__) || defined(__clang__)
145 // C++23 explicit object parameter implementation
146 template <Component T>
147 template <typename Self>
148 auto SparseArray<T>::entities(this Self &&self) noexcept
149 {
150 if constexpr (std::is_const_v<std::remove_reference_t<Self>>) {
151 return std::span<const Entity>{self._dense};
152 } else {
153 return std::span<Entity>{self._dense};
154 }
155 }
156#else
157 // Traditional overloads for MSVC
158 template <Component T>
159 std::span<Entity> SparseArray<T>::entities() noexcept
160 {
161 return std::span<Entity>{_dense};
162 }
163
164 template <Component T>
165 std::span<const Entity> SparseArray<T>::entities() const noexcept
166 {
167 return std::span<const Entity>{_dense};
168 }
169#endif
170
171 template <Component T>
172 std::size_t SparseArray<T>::size(void) const noexcept
173 {
174 return this->_data.size();
175 }
176
177 template <Component T>
178 bool SparseArray<T>::empty(void) const noexcept
179 {
180 return this->_data.empty();
181 }
182}