goud_engine/ecs/sparse_set/core.rs
1//! Core sparse set data structure for component storage.
2//!
3//! A sparse set provides O(1) insertion, deletion, and lookup while maintaining
4//! cache-friendly iteration over dense data. This is the foundation for ECS
5//! component storage.
6//!
7//! # Design Pattern: Sparse Set
8//!
9//! The sparse set uses two arrays:
10//!
11//! - **Sparse**: Maps entity indices to dense array indices (may have gaps)
12//! - **Dense**: Packed array of entities for cache-friendly iteration
13//! - **Values**: Packed array of component values, parallel to dense
14//!
15//! ```text
16//! Entity(3) has component "A"
17//! Entity(7) has component "B"
18//! Entity(1) has component "C"
19//!
20//! Sparse: [_, Some(2), _, Some(0), _, _, _, Some(1)]
21//! 0 1 2 3 4 5 6 7
22//!
23//! Dense: [Entity(3), Entity(7), Entity(1)]
24//! 0 1 2
25//!
26//! Values: ["A", "B", "C"]
27//! 0 1 2
28//! ```
29//!
30//! # Performance Characteristics
31//!
32//! | Operation | Time Complexity | Notes |
33//! |-----------|-----------------|-------|
34//! | insert | O(1) amortized | May grow sparse vec |
35//! | remove | O(1) | Uses swap-remove |
36//! | get | O(1) | |
37//! | contains | O(1) | |
38//! | iterate | O(n) | Cache-friendly, contiguous |
39//!
40//! # Example
41//!
42//! ```
43//! use goud_engine::ecs::{Entity, SparseSet};
44//!
45//! let mut set: SparseSet<String> = SparseSet::new();
46//!
47//! let e1 = Entity::new(0, 1);
48//! let e2 = Entity::new(5, 1);
49//!
50//! set.insert(e1, "Hello".to_string());
51//! set.insert(e2, "World".to_string());
52//!
53//! assert_eq!(set.get(e1), Some(&"Hello".to_string()));
54//! assert!(set.contains(e2));
55//!
56//! // Cache-friendly iteration
57//! for (entity, value) in set.iter() {
58//! println!("{}: {}", entity, value);
59//! }
60//! ```
61//!
62//! # Thread Safety
63//!
64//! `SparseSet<T>` is `Send` if `T: Send` and `Sync` if `T: Sync`.
65//! The sparse set itself is not internally synchronized - wrap in
66//! `RwLock` or similar for concurrent access.
67
68use super::super::Entity;
69
70/// A sparse set storing values of type `T` indexed by [`Entity`].
71///
72/// Provides O(1) access operations while maintaining cache-friendly iteration.
73/// This is the primary storage backend for ECS components.
74///
75/// # Type Parameters
76///
77/// - `T`: The value type stored in the set
78///
79/// # Memory Layout
80///
81/// The sparse set trades memory for performance:
82///
83/// - Sparse vec grows to max entity index seen (sparse memory usage)
84/// - Dense and values vecs are tightly packed (no gaps)
85///
86/// For entities with indices 0, 100, 1000, the sparse vec will have 1001 entries,
87/// but dense/values will only have 3 entries.
88#[derive(Debug)]
89pub struct SparseSet<T> {
90 /// Maps entity index to position in dense array.
91 /// `sparse[entity.index()]` = Some(dense_index) if entity has a value.
92 pub(super) sparse: Vec<Option<usize>>,
93
94 /// Packed array of entities that have values.
95 /// Enables O(1) removal via swap-remove.
96 pub(super) dense: Vec<Entity>,
97
98 /// Packed array of values, parallel to `dense`.
99 /// `values[i]` is the value for `dense[i]`.
100 pub(super) values: Vec<T>,
101}
102
103impl<T> SparseSet<T> {
104 /// Creates a new, empty sparse set.
105 ///
106 /// # Example
107 ///
108 /// ```
109 /// use goud_engine::ecs::SparseSet;
110 ///
111 /// let set: SparseSet<i32> = SparseSet::new();
112 /// assert!(set.is_empty());
113 /// assert_eq!(set.len(), 0);
114 /// ```
115 #[inline]
116 pub fn new() -> Self {
117 Self {
118 sparse: Vec::new(),
119 dense: Vec::new(),
120 values: Vec::new(),
121 }
122 }
123
124 /// Creates a sparse set with pre-allocated capacity.
125 ///
126 /// This pre-allocates the dense and values vectors, but not the sparse
127 /// vector (which grows on demand based on entity indices).
128 ///
129 /// # Arguments
130 ///
131 /// * `capacity` - Number of elements to pre-allocate
132 ///
133 /// # Example
134 ///
135 /// ```
136 /// use goud_engine::ecs::SparseSet;
137 ///
138 /// let set: SparseSet<String> = SparseSet::with_capacity(1000);
139 /// assert!(set.is_empty());
140 /// ```
141 #[inline]
142 pub fn with_capacity(capacity: usize) -> Self {
143 Self {
144 sparse: Vec::new(),
145 dense: Vec::with_capacity(capacity),
146 values: Vec::with_capacity(capacity),
147 }
148 }
149
150 /// Inserts a value for the given entity.
151 ///
152 /// If the entity already has a value, it is replaced and the old value
153 /// is returned. Otherwise, `None` is returned.
154 ///
155 /// # Arguments
156 ///
157 /// * `entity` - The entity to associate with the value
158 /// * `value` - The value to store
159 ///
160 /// # Returns
161 ///
162 /// The previous value if one existed, or `None`.
163 ///
164 /// # Panics
165 ///
166 /// Panics if the entity is a placeholder (`Entity::PLACEHOLDER`).
167 ///
168 /// # Example
169 ///
170 /// ```
171 /// use goud_engine::ecs::{Entity, SparseSet};
172 ///
173 /// let mut set = SparseSet::new();
174 /// let entity = Entity::new(0, 1);
175 ///
176 /// assert_eq!(set.insert(entity, 42), None);
177 /// assert_eq!(set.insert(entity, 99), Some(42)); // Returns old value
178 /// assert_eq!(set.get(entity), Some(&99));
179 /// ```
180 pub fn insert(&mut self, entity: Entity, value: T) -> Option<T> {
181 assert!(
182 !entity.is_placeholder(),
183 "Cannot insert with placeholder entity"
184 );
185
186 let index = entity.index() as usize;
187
188 // Grow sparse vec if needed
189 if index >= self.sparse.len() {
190 self.sparse.resize(index + 1, None);
191 }
192
193 if let Some(dense_index) = self.sparse[index] {
194 // Entity already has a value - replace it
195 let old_value = std::mem::replace(&mut self.values[dense_index], value);
196 Some(old_value)
197 } else {
198 // New entity - add to dense arrays
199 let dense_index = self.dense.len();
200 self.sparse[index] = Some(dense_index);
201 self.dense.push(entity);
202 self.values.push(value);
203 None
204 }
205 }
206
207 /// Removes the value for the given entity.
208 ///
209 /// Uses swap-remove to maintain dense packing: the last element is
210 /// moved to fill the gap, keeping iteration cache-friendly.
211 ///
212 /// # Arguments
213 ///
214 /// * `entity` - The entity whose value to remove
215 ///
216 /// # Returns
217 ///
218 /// The removed value if one existed, or `None`.
219 ///
220 /// # Example
221 ///
222 /// ```
223 /// use goud_engine::ecs::{Entity, SparseSet};
224 ///
225 /// let mut set = SparseSet::new();
226 /// let entity = Entity::new(0, 1);
227 ///
228 /// set.insert(entity, "hello");
229 /// assert_eq!(set.remove(entity), Some("hello"));
230 /// assert_eq!(set.remove(entity), None); // Already removed
231 /// ```
232 pub fn remove(&mut self, entity: Entity) -> Option<T> {
233 if entity.is_placeholder() {
234 return None;
235 }
236
237 let index = entity.index() as usize;
238
239 // Check bounds
240 if index >= self.sparse.len() {
241 return None;
242 }
243
244 // Get dense index
245 let dense_index = self.sparse[index]?;
246 self.sparse[index] = None;
247
248 // Get the last entity in the dense array
249 let last_index = self.dense.len() - 1;
250
251 if dense_index != last_index {
252 // Swap with last element
253 let last_entity = self.dense[last_index];
254 self.dense.swap(dense_index, last_index);
255 self.values.swap(dense_index, last_index);
256
257 // Update sparse pointer for swapped entity
258 self.sparse[last_entity.index() as usize] = Some(dense_index);
259 }
260
261 // Remove last element (which is now our removed entity)
262 self.dense.pop();
263 self.values.pop()
264 }
265
266 /// Returns a reference to the value for the given entity.
267 ///
268 /// # Arguments
269 ///
270 /// * `entity` - The entity to look up
271 ///
272 /// # Returns
273 ///
274 /// A reference to the value if the entity has one, or `None`.
275 ///
276 /// # Example
277 ///
278 /// ```
279 /// use goud_engine::ecs::{Entity, SparseSet};
280 ///
281 /// let mut set = SparseSet::new();
282 /// let entity = Entity::new(0, 1);
283 ///
284 /// set.insert(entity, 42);
285 /// assert_eq!(set.get(entity), Some(&42));
286 ///
287 /// let missing = Entity::new(999, 1);
288 /// assert_eq!(set.get(missing), None);
289 /// ```
290 #[inline]
291 pub fn get(&self, entity: Entity) -> Option<&T> {
292 if entity.is_placeholder() {
293 return None;
294 }
295
296 let index = entity.index() as usize;
297
298 if index >= self.sparse.len() {
299 return None;
300 }
301
302 let dense_index = self.sparse[index]?;
303 Some(&self.values[dense_index])
304 }
305
306 /// Returns a mutable reference to the value for the given entity.
307 ///
308 /// # Arguments
309 ///
310 /// * `entity` - The entity to look up
311 ///
312 /// # Returns
313 ///
314 /// A mutable reference to the value if the entity has one, or `None`.
315 ///
316 /// # Example
317 ///
318 /// ```
319 /// use goud_engine::ecs::{Entity, SparseSet};
320 ///
321 /// let mut set = SparseSet::new();
322 /// let entity = Entity::new(0, 1);
323 ///
324 /// set.insert(entity, 42);
325 ///
326 /// if let Some(value) = set.get_mut(entity) {
327 /// *value = 100;
328 /// }
329 ///
330 /// assert_eq!(set.get(entity), Some(&100));
331 /// ```
332 #[inline]
333 pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
334 if entity.is_placeholder() {
335 return None;
336 }
337
338 let index = entity.index() as usize;
339
340 if index >= self.sparse.len() {
341 return None;
342 }
343
344 let dense_index = self.sparse[index]?;
345 Some(&mut self.values[dense_index])
346 }
347
348 /// Returns `true` if the entity has a value in this set.
349 ///
350 /// # Arguments
351 ///
352 /// * `entity` - The entity to check
353 ///
354 /// # Example
355 ///
356 /// ```
357 /// use goud_engine::ecs::{Entity, SparseSet};
358 ///
359 /// let mut set = SparseSet::new();
360 /// let entity = Entity::new(0, 1);
361 ///
362 /// assert!(!set.contains(entity));
363 /// set.insert(entity, "value");
364 /// assert!(set.contains(entity));
365 /// ```
366 #[inline]
367 pub fn contains(&self, entity: Entity) -> bool {
368 if entity.is_placeholder() {
369 return false;
370 }
371
372 let index = entity.index() as usize;
373
374 if index >= self.sparse.len() {
375 return false;
376 }
377
378 self.sparse[index].is_some()
379 }
380
381 /// Returns the number of entities with values in this set.
382 ///
383 /// # Example
384 ///
385 /// ```
386 /// use goud_engine::ecs::{Entity, SparseSet};
387 ///
388 /// let mut set = SparseSet::new();
389 /// assert_eq!(set.len(), 0);
390 ///
391 /// set.insert(Entity::new(0, 1), "a");
392 /// set.insert(Entity::new(5, 1), "b");
393 /// assert_eq!(set.len(), 2);
394 /// ```
395 #[inline]
396 pub fn len(&self) -> usize {
397 self.dense.len()
398 }
399
400 /// Returns `true` if the set contains no values.
401 ///
402 /// # Example
403 ///
404 /// ```
405 /// use goud_engine::ecs::{Entity, SparseSet};
406 ///
407 /// let mut set: SparseSet<i32> = SparseSet::new();
408 /// assert!(set.is_empty());
409 ///
410 /// set.insert(Entity::new(0, 1), 42);
411 /// assert!(!set.is_empty());
412 /// ```
413 #[inline]
414 pub fn is_empty(&self) -> bool {
415 self.dense.is_empty()
416 }
417
418 /// Removes all values from the set.
419 ///
420 /// This clears all three internal arrays. After calling `clear()`,
421 /// `len()` will return 0.
422 ///
423 /// # Example
424 ///
425 /// ```
426 /// use goud_engine::ecs::{Entity, SparseSet};
427 ///
428 /// let mut set = SparseSet::new();
429 /// set.insert(Entity::new(0, 1), "a");
430 /// set.insert(Entity::new(1, 1), "b");
431 /// assert_eq!(set.len(), 2);
432 ///
433 /// set.clear();
434 /// assert!(set.is_empty());
435 /// ```
436 pub fn clear(&mut self) {
437 self.sparse.clear();
438 self.dense.clear();
439 self.values.clear();
440 }
441
442 /// Reserves capacity for at least `additional` more elements.
443 ///
444 /// This affects the dense and values arrays, not the sparse array
445 /// (which grows based on entity indices).
446 ///
447 /// # Arguments
448 ///
449 /// * `additional` - Number of additional elements to reserve
450 ///
451 /// # Example
452 ///
453 /// ```
454 /// use goud_engine::ecs::SparseSet;
455 ///
456 /// let mut set: SparseSet<i32> = SparseSet::new();
457 /// set.reserve(1000);
458 /// ```
459 pub fn reserve(&mut self, additional: usize) {
460 self.dense.reserve(additional);
461 self.values.reserve(additional);
462 }
463}
464
465impl<T> Default for SparseSet<T> {
466 fn default() -> Self {
467 Self::new()
468 }
469}
470
471impl<T: Clone> Clone for SparseSet<T> {
472 fn clone(&self) -> Self {
473 Self {
474 sparse: self.sparse.clone(),
475 dense: self.dense.clone(),
476 values: self.values.clone(),
477 }
478 }
479}