2** EPITECH PROJECT, 2025
11** Copyright (c) 2025 Robin Toillon
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:
21** The above copyright notice and this permission notice shall be
22** included in all copies or substantial portions of the Software.
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.
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.
46 template <Component T>
47 void SparseArray<T>::erase(Entity entity) noexcept
49 if (!this->has(entity))
52 size_t indexRemoved = this->_sparse[entity.index()];
53 size_t indexLast = this->_data.size() - 1;
54 Entity entityLast = this->_dense[indexLast];
56 if (indexRemoved != indexLast) {
57 this->_data[indexRemoved] = std::move(this->_data.back());
58 this->_dense[indexRemoved] = entityLast;
59 this->_sparse[entityLast.index()] = indexRemoved;
62 this->_data.pop_back();
63 this->_dense.pop_back();
65 this->_sparse[entity.index()] = NullIndex;
68 template <Component T>
69 bool SparseArray<T>::has(Entity entity) const noexcept
71 return entity.index() < this->_sparse.size()
72 && this->_sparse[entity.index()] != NullIndex
73 && this->_dense[this->_sparse[entity.index()]] == entity;
76 template <Component T>
77 void SparseArray<T>::clear(void) noexcept
81 std::fill(this->_sparse.begin(), this->_sparse.end(), NullIndex);
84 template <Component T>
85 template <typename Self>
86 auto &&SparseArray<T>::operator[](this Self &self, Entity entity) noexcept
88 RTP_ASSERT(self.has(entity),
89 "SparseArray: Entity {} does not have component " \
90 "(Index out of bounds)", entity.index());
92 size_t index = self._sparse[entity.index()];
94 return std::forward_like<Self>(self)._data[index];
97 template <Component T>
98 template <typename... Args>
99 T &SparseArray<T>::emplace(Entity entity, Args &&...args)
101 if (entity.index() >= this->_sparse.size())
102 this->_sparse.resize(entity.index() + 1, NullIndex);
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];
110 index = this->_data.size();
111 this->_sparse[entity.index()] = index;
112 this->_dense.push_back(entity);
114 return this->_data.emplace_back(std::forward<Args>(args)...);
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
123 if constexpr (std::is_const_v<std::remove_reference_t<Self>>) {
124 return std::span<const T>{self._data};
126 return std::span<T>{self._data};
130 // Traditional overloads for MSVC
131 template <Component T>
132 std::span<T> SparseArray<T>::data() noexcept
134 return std::span<T>{_data};
137 template <Component T>
138 std::span<const T> SparseArray<T>::data() const noexcept
140 return std::span<const T>{_data};
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
150 if constexpr (std::is_const_v<std::remove_reference_t<Self>>) {
151 return std::span<const Entity>{self._dense};
153 return std::span<Entity>{self._dense};
157 // Traditional overloads for MSVC
158 template <Component T>
159 std::span<Entity> SparseArray<T>::entities() noexcept
161 return std::span<Entity>{_dense};
164 template <Component T>
165 std::span<const Entity> SparseArray<T>::entities() const noexcept
167 return std::span<const Entity>{_dense};
171 template <Component T>
172 std::size_t SparseArray<T>::size(void) const noexcept
174 return this->_data.size();
177 template <Component T>
178 bool SparseArray<T>::empty(void) const noexcept
180 return this->_data.empty();