Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/storage/sparse_set.rs
6604 views
1
use crate::{
2
change_detection::MaybeLocation,
3
component::{CheckChangeTicks, ComponentId, ComponentInfo, ComponentTicks, Tick, TickCells},
4
entity::{Entity, EntityRow},
5
storage::{Column, TableRow},
6
};
7
use alloc::{boxed::Box, vec::Vec};
8
use bevy_ptr::{OwningPtr, Ptr};
9
use core::{cell::UnsafeCell, hash::Hash, marker::PhantomData, panic::Location};
10
use nonmax::{NonMaxU32, NonMaxUsize};
11
12
#[derive(Debug)]
13
pub(crate) struct SparseArray<I, V = I> {
14
values: Vec<Option<V>>,
15
marker: PhantomData<I>,
16
}
17
18
/// A space-optimized version of [`SparseArray`] that cannot be changed
19
/// after construction.
20
#[derive(Debug)]
21
pub(crate) struct ImmutableSparseArray<I, V = I> {
22
values: Box<[Option<V>]>,
23
marker: PhantomData<I>,
24
}
25
26
impl<I: SparseSetIndex, V> Default for SparseArray<I, V> {
27
fn default() -> Self {
28
Self::new()
29
}
30
}
31
32
impl<I, V> SparseArray<I, V> {
33
#[inline]
34
pub const fn new() -> Self {
35
Self {
36
values: Vec::new(),
37
marker: PhantomData,
38
}
39
}
40
}
41
42
macro_rules! impl_sparse_array {
43
($ty:ident) => {
44
impl<I: SparseSetIndex, V> $ty<I, V> {
45
/// Returns `true` if the collection contains a value for the specified `index`.
46
#[inline]
47
pub fn contains(&self, index: I) -> bool {
48
let index = index.sparse_set_index();
49
self.values.get(index).is_some_and(Option::is_some)
50
}
51
52
/// Returns a reference to the value at `index`.
53
///
54
/// Returns `None` if `index` does not have a value or if `index` is out of bounds.
55
#[inline]
56
pub fn get(&self, index: I) -> Option<&V> {
57
let index = index.sparse_set_index();
58
self.values.get(index).and_then(Option::as_ref)
59
}
60
}
61
};
62
}
63
64
impl_sparse_array!(SparseArray);
65
impl_sparse_array!(ImmutableSparseArray);
66
67
impl<I: SparseSetIndex, V> SparseArray<I, V> {
68
/// Inserts `value` at `index` in the array.
69
///
70
/// If `index` is out-of-bounds, this will enlarge the buffer to accommodate it.
71
#[inline]
72
pub fn insert(&mut self, index: I, value: V) {
73
let index = index.sparse_set_index();
74
if index >= self.values.len() {
75
self.values.resize_with(index + 1, || None);
76
}
77
self.values[index] = Some(value);
78
}
79
80
/// Returns a mutable reference to the value at `index`.
81
///
82
/// Returns `None` if `index` does not have a value or if `index` is out of bounds.
83
#[inline]
84
pub fn get_mut(&mut self, index: I) -> Option<&mut V> {
85
let index = index.sparse_set_index();
86
self.values.get_mut(index).and_then(Option::as_mut)
87
}
88
89
/// Removes and returns the value stored at `index`.
90
///
91
/// Returns `None` if `index` did not have a value or if `index` is out of bounds.
92
#[inline]
93
pub fn remove(&mut self, index: I) -> Option<V> {
94
let index = index.sparse_set_index();
95
self.values.get_mut(index).and_then(Option::take)
96
}
97
98
/// Removes all of the values stored within.
99
pub fn clear(&mut self) {
100
self.values.clear();
101
}
102
103
/// Converts the [`SparseArray`] into an immutable variant.
104
pub(crate) fn into_immutable(self) -> ImmutableSparseArray<I, V> {
105
ImmutableSparseArray {
106
values: self.values.into_boxed_slice(),
107
marker: PhantomData,
108
}
109
}
110
}
111
112
/// A sparse data structure of [`Component`](crate::component::Component)s.
113
///
114
/// Designed for relatively fast insertions and deletions.
115
#[derive(Debug)]
116
pub struct ComponentSparseSet {
117
dense: Column,
118
// Internally this only relies on the Entity index to keep track of where the component data is
119
// stored for entities that are alive. The generation is not required, but is stored
120
// in debug builds to validate that access is correct.
121
#[cfg(not(debug_assertions))]
122
entities: Vec<EntityRow>,
123
#[cfg(debug_assertions)]
124
entities: Vec<Entity>,
125
sparse: SparseArray<EntityRow, TableRow>,
126
}
127
128
impl ComponentSparseSet {
129
/// Creates a new [`ComponentSparseSet`] with a given component type layout and
130
/// initial `capacity`.
131
pub(crate) fn new(component_info: &ComponentInfo, capacity: usize) -> Self {
132
Self {
133
dense: Column::with_capacity(component_info, capacity),
134
entities: Vec::with_capacity(capacity),
135
sparse: Default::default(),
136
}
137
}
138
139
/// Removes all of the values stored within.
140
pub(crate) fn clear(&mut self) {
141
self.dense.clear();
142
self.entities.clear();
143
self.sparse.clear();
144
}
145
146
/// Returns the number of component values in the sparse set.
147
#[inline]
148
pub fn len(&self) -> usize {
149
self.dense.len()
150
}
151
152
/// Returns `true` if the sparse set contains no component values.
153
#[inline]
154
pub fn is_empty(&self) -> bool {
155
self.dense.len() == 0
156
}
157
158
/// Inserts the `entity` key and component `value` pair into this sparse
159
/// set.
160
///
161
/// # Safety
162
/// The `value` pointer must point to a valid address that matches the [`Layout`](std::alloc::Layout)
163
/// inside the [`ComponentInfo`] given when constructing this sparse set.
164
pub(crate) unsafe fn insert(
165
&mut self,
166
entity: Entity,
167
value: OwningPtr<'_>,
168
change_tick: Tick,
169
caller: MaybeLocation,
170
) {
171
if let Some(&dense_index) = self.sparse.get(entity.row()) {
172
#[cfg(debug_assertions)]
173
assert_eq!(entity, self.entities[dense_index.index()]);
174
self.dense.replace(dense_index, value, change_tick, caller);
175
} else {
176
let dense_index = self.dense.len();
177
self.dense
178
.push(value, ComponentTicks::new(change_tick), caller);
179
180
// SAFETY: This entity row does not exist here yet, so there are no duplicates,
181
// and the entity index can not be the max, so the length must not be max either.
182
// To do so would have caused a panic in the entity alloxator.
183
let table_row = unsafe { TableRow::new(NonMaxU32::new_unchecked(dense_index as u32)) };
184
185
self.sparse.insert(entity.row(), table_row);
186
#[cfg(debug_assertions)]
187
assert_eq!(self.entities.len(), dense_index);
188
#[cfg(not(debug_assertions))]
189
self.entities.push(entity.row());
190
#[cfg(debug_assertions)]
191
self.entities.push(entity);
192
}
193
}
194
195
/// Returns `true` if the sparse set has a component value for the provided `entity`.
196
#[inline]
197
pub fn contains(&self, entity: Entity) -> bool {
198
#[cfg(debug_assertions)]
199
{
200
if let Some(&dense_index) = self.sparse.get(entity.row()) {
201
#[cfg(debug_assertions)]
202
assert_eq!(entity, self.entities[dense_index.index()]);
203
true
204
} else {
205
false
206
}
207
}
208
#[cfg(not(debug_assertions))]
209
self.sparse.contains(entity.row())
210
}
211
212
/// Returns a reference to the entity's component value.
213
///
214
/// Returns `None` if `entity` does not have a component in the sparse set.
215
#[inline]
216
pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
217
self.sparse.get(entity.row()).map(|&dense_index| {
218
#[cfg(debug_assertions)]
219
assert_eq!(entity, self.entities[dense_index.index()]);
220
// SAFETY: if the sparse index points to something in the dense vec, it exists
221
unsafe { self.dense.get_data_unchecked(dense_index) }
222
})
223
}
224
225
/// Returns references to the entity's component value and its added and changed ticks.
226
///
227
/// Returns `None` if `entity` does not have a component in the sparse set.
228
#[inline]
229
pub fn get_with_ticks(
230
&self,
231
entity: Entity,
232
) -> Option<(
233
Ptr<'_>,
234
TickCells<'_>,
235
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
236
)> {
237
let dense_index = *self.sparse.get(entity.row())?;
238
#[cfg(debug_assertions)]
239
assert_eq!(entity, self.entities[dense_index.index()]);
240
// SAFETY: if the sparse index points to something in the dense vec, it exists
241
unsafe {
242
Some((
243
self.dense.get_data_unchecked(dense_index),
244
TickCells {
245
added: self.dense.get_added_tick_unchecked(dense_index),
246
changed: self.dense.get_changed_tick_unchecked(dense_index),
247
},
248
self.dense.get_changed_by_unchecked(dense_index),
249
))
250
}
251
}
252
253
/// Returns a reference to the "added" tick of the entity's component value.
254
///
255
/// Returns `None` if `entity` does not have a component in the sparse set.
256
#[inline]
257
pub fn get_added_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
258
let dense_index = *self.sparse.get(entity.row())?;
259
#[cfg(debug_assertions)]
260
assert_eq!(entity, self.entities[dense_index.index()]);
261
// SAFETY: if the sparse index points to something in the dense vec, it exists
262
unsafe { Some(self.dense.get_added_tick_unchecked(dense_index)) }
263
}
264
265
/// Returns a reference to the "changed" tick of the entity's component value.
266
///
267
/// Returns `None` if `entity` does not have a component in the sparse set.
268
#[inline]
269
pub fn get_changed_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
270
let dense_index = *self.sparse.get(entity.row())?;
271
#[cfg(debug_assertions)]
272
assert_eq!(entity, self.entities[dense_index.index()]);
273
// SAFETY: if the sparse index points to something in the dense vec, it exists
274
unsafe { Some(self.dense.get_changed_tick_unchecked(dense_index)) }
275
}
276
277
/// Returns a reference to the "added" and "changed" ticks of the entity's component value.
278
///
279
/// Returns `None` if `entity` does not have a component in the sparse set.
280
#[inline]
281
pub fn get_ticks(&self, entity: Entity) -> Option<ComponentTicks> {
282
let dense_index = *self.sparse.get(entity.row())?;
283
#[cfg(debug_assertions)]
284
assert_eq!(entity, self.entities[dense_index.index()]);
285
// SAFETY: if the sparse index points to something in the dense vec, it exists
286
unsafe { Some(self.dense.get_ticks_unchecked(dense_index)) }
287
}
288
289
/// Returns a reference to the calling location that last changed the entity's component value.
290
///
291
/// Returns `None` if `entity` does not have a component in the sparse set.
292
#[inline]
293
pub fn get_changed_by(
294
&self,
295
entity: Entity,
296
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
297
MaybeLocation::new_with_flattened(|| {
298
let dense_index = *self.sparse.get(entity.row())?;
299
#[cfg(debug_assertions)]
300
assert_eq!(entity, self.entities[dense_index.index()]);
301
// SAFETY: if the sparse index points to something in the dense vec, it exists
302
unsafe { Some(self.dense.get_changed_by_unchecked(dense_index)) }
303
})
304
}
305
306
/// Returns the drop function for the component type stored in the sparse set,
307
/// or `None` if it doesn't need to be dropped.
308
#[inline]
309
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
310
self.dense.get_drop()
311
}
312
313
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
314
/// it exists).
315
#[must_use = "The returned pointer must be used to drop the removed component."]
316
pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {
317
self.sparse.remove(entity.row()).map(|dense_index| {
318
#[cfg(debug_assertions)]
319
assert_eq!(entity, self.entities[dense_index.index()]);
320
self.entities.swap_remove(dense_index.index());
321
let is_last = dense_index.index() == self.dense.len() - 1;
322
// SAFETY: dense_index was just removed from `sparse`, which ensures that it is valid
323
let (value, _, _) = unsafe { self.dense.swap_remove_and_forget_unchecked(dense_index) };
324
if !is_last {
325
let swapped_entity = self.entities[dense_index.index()];
326
#[cfg(not(debug_assertions))]
327
let index = swapped_entity;
328
#[cfg(debug_assertions)]
329
let index = swapped_entity.row();
330
*self.sparse.get_mut(index).unwrap() = dense_index;
331
}
332
value
333
})
334
}
335
336
/// Removes (and drops) the entity's component value from the sparse set.
337
///
338
/// Returns `true` if `entity` had a component value in the sparse set.
339
pub(crate) fn remove(&mut self, entity: Entity) -> bool {
340
if let Some(dense_index) = self.sparse.remove(entity.row()) {
341
#[cfg(debug_assertions)]
342
assert_eq!(entity, self.entities[dense_index.index()]);
343
self.entities.swap_remove(dense_index.index());
344
let is_last = dense_index.index() == self.dense.len() - 1;
345
// SAFETY: if the sparse index points to something in the dense vec, it exists
346
unsafe {
347
self.dense.swap_remove_unchecked(dense_index);
348
}
349
if !is_last {
350
let swapped_entity = self.entities[dense_index.index()];
351
#[cfg(not(debug_assertions))]
352
let index = swapped_entity;
353
#[cfg(debug_assertions)]
354
let index = swapped_entity.row();
355
*self.sparse.get_mut(index).unwrap() = dense_index;
356
}
357
true
358
} else {
359
false
360
}
361
}
362
363
pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {
364
self.dense.check_change_ticks(check);
365
}
366
}
367
368
/// A data structure that blends dense and sparse storage
369
///
370
/// `I` is the type of the indices, while `V` is the type of data stored in the dense storage.
371
#[derive(Debug)]
372
pub struct SparseSet<I, V: 'static> {
373
dense: Vec<V>,
374
indices: Vec<I>,
375
sparse: SparseArray<I, NonMaxUsize>,
376
}
377
378
/// A space-optimized version of [`SparseSet`] that cannot be changed
379
/// after construction.
380
#[derive(Debug)]
381
pub(crate) struct ImmutableSparseSet<I, V: 'static> {
382
dense: Box<[V]>,
383
indices: Box<[I]>,
384
sparse: ImmutableSparseArray<I, NonMaxUsize>,
385
}
386
387
macro_rules! impl_sparse_set {
388
($ty:ident) => {
389
impl<I: SparseSetIndex, V> $ty<I, V> {
390
/// Returns the number of elements in the sparse set.
391
#[inline]
392
pub fn len(&self) -> usize {
393
self.dense.len()
394
}
395
396
/// Returns `true` if the sparse set contains a value for `index`.
397
#[inline]
398
pub fn contains(&self, index: I) -> bool {
399
self.sparse.contains(index)
400
}
401
402
/// Returns a reference to the value for `index`.
403
///
404
/// Returns `None` if `index` does not have a value in the sparse set.
405
pub fn get(&self, index: I) -> Option<&V> {
406
self.sparse.get(index).map(|dense_index| {
407
// SAFETY: if the sparse index points to something in the dense vec, it exists
408
unsafe { self.dense.get_unchecked(dense_index.get()) }
409
})
410
}
411
412
/// Returns a mutable reference to the value for `index`.
413
///
414
/// Returns `None` if `index` does not have a value in the sparse set.
415
pub fn get_mut(&mut self, index: I) -> Option<&mut V> {
416
let dense = &mut self.dense;
417
self.sparse.get(index).map(move |dense_index| {
418
// SAFETY: if the sparse index points to something in the dense vec, it exists
419
unsafe { dense.get_unchecked_mut(dense_index.get()) }
420
})
421
}
422
423
/// Returns an iterator visiting all keys (indices) in arbitrary order.
424
pub fn indices(&self) -> &[I] {
425
&self.indices
426
}
427
428
/// Returns an iterator visiting all values in arbitrary order.
429
pub fn values(&self) -> impl Iterator<Item = &V> {
430
self.dense.iter()
431
}
432
433
/// Returns an iterator visiting all values mutably in arbitrary order.
434
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
435
self.dense.iter_mut()
436
}
437
438
/// Returns an iterator visiting all key-value pairs in arbitrary order, with references to the values.
439
pub fn iter(&self) -> impl Iterator<Item = (&I, &V)> {
440
self.indices.iter().zip(self.dense.iter())
441
}
442
443
/// Returns an iterator visiting all key-value pairs in arbitrary order, with mutable references to the values.
444
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&I, &mut V)> {
445
self.indices.iter().zip(self.dense.iter_mut())
446
}
447
}
448
};
449
}
450
451
impl_sparse_set!(SparseSet);
452
impl_sparse_set!(ImmutableSparseSet);
453
454
impl<I: SparseSetIndex, V> Default for SparseSet<I, V> {
455
fn default() -> Self {
456
Self::new()
457
}
458
}
459
460
impl<I, V> SparseSet<I, V> {
461
/// Creates a new [`SparseSet`].
462
pub const fn new() -> Self {
463
Self {
464
dense: Vec::new(),
465
indices: Vec::new(),
466
sparse: SparseArray::new(),
467
}
468
}
469
}
470
471
impl<I: SparseSetIndex, V> SparseSet<I, V> {
472
/// Creates a new [`SparseSet`] with a specified initial capacity.
473
pub fn with_capacity(capacity: usize) -> Self {
474
Self {
475
dense: Vec::with_capacity(capacity),
476
indices: Vec::with_capacity(capacity),
477
sparse: Default::default(),
478
}
479
}
480
481
/// Returns the total number of elements the [`SparseSet`] can hold without needing to reallocate.
482
#[inline]
483
pub fn capacity(&self) -> usize {
484
self.dense.capacity()
485
}
486
487
/// Inserts `value` at `index`.
488
///
489
/// If a value was already present at `index`, it will be overwritten.
490
pub fn insert(&mut self, index: I, value: V) {
491
if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {
492
// SAFETY: dense indices stored in self.sparse always exist
493
unsafe {
494
*self.dense.get_unchecked_mut(dense_index.get()) = value;
495
}
496
} else {
497
self.sparse
498
.insert(index.clone(), NonMaxUsize::new(self.dense.len()).unwrap());
499
self.indices.push(index);
500
self.dense.push(value);
501
}
502
}
503
504
/// Returns a reference to the value for `index`, inserting one computed from `func`
505
/// if not already present.
506
pub fn get_or_insert_with(&mut self, index: I, func: impl FnOnce() -> V) -> &mut V {
507
if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {
508
// SAFETY: dense indices stored in self.sparse always exist
509
unsafe { self.dense.get_unchecked_mut(dense_index.get()) }
510
} else {
511
let value = func();
512
let dense_index = self.dense.len();
513
self.sparse
514
.insert(index.clone(), NonMaxUsize::new(dense_index).unwrap());
515
self.indices.push(index);
516
self.dense.push(value);
517
// SAFETY: dense index was just populated above
518
unsafe { self.dense.get_unchecked_mut(dense_index) }
519
}
520
}
521
522
/// Returns `true` if the sparse set contains no elements.
523
#[inline]
524
pub fn is_empty(&self) -> bool {
525
self.dense.len() == 0
526
}
527
528
/// Removes and returns the value for `index`.
529
///
530
/// Returns `None` if `index` does not have a value in the sparse set.
531
pub fn remove(&mut self, index: I) -> Option<V> {
532
self.sparse.remove(index).map(|dense_index| {
533
let index = dense_index.get();
534
let is_last = index == self.dense.len() - 1;
535
let value = self.dense.swap_remove(index);
536
self.indices.swap_remove(index);
537
if !is_last {
538
let swapped_index = self.indices[index].clone();
539
*self.sparse.get_mut(swapped_index).unwrap() = dense_index;
540
}
541
value
542
})
543
}
544
545
/// Clears all of the elements from the sparse set.
546
pub fn clear(&mut self) {
547
self.dense.clear();
548
self.indices.clear();
549
self.sparse.clear();
550
}
551
552
/// Converts the sparse set into its immutable variant.
553
pub(crate) fn into_immutable(self) -> ImmutableSparseSet<I, V> {
554
ImmutableSparseSet {
555
dense: self.dense.into_boxed_slice(),
556
indices: self.indices.into_boxed_slice(),
557
sparse: self.sparse.into_immutable(),
558
}
559
}
560
}
561
562
/// Represents something that can be stored in a [`SparseSet`] as an integer.
563
///
564
/// Ideally, the `usize` values should be very small (ie: incremented starting from
565
/// zero), as the number of bits needed to represent a `SparseSetIndex` in a `FixedBitSet`
566
/// is proportional to the **value** of those `usize`.
567
pub trait SparseSetIndex: Clone + PartialEq + Eq + Hash {
568
/// Gets the sparse set index corresponding to this instance.
569
fn sparse_set_index(&self) -> usize;
570
/// Creates a new instance of this type with the specified index.
571
fn get_sparse_set_index(value: usize) -> Self;
572
}
573
574
macro_rules! impl_sparse_set_index {
575
($($ty:ty),+) => {
576
$(impl SparseSetIndex for $ty {
577
#[inline]
578
fn sparse_set_index(&self) -> usize {
579
*self as usize
580
}
581
582
#[inline]
583
fn get_sparse_set_index(value: usize) -> Self {
584
value as $ty
585
}
586
})*
587
};
588
}
589
590
impl_sparse_set_index!(u8, u16, u32, u64, usize);
591
592
/// A collection of [`ComponentSparseSet`] storages, indexed by [`ComponentId`]
593
///
594
/// Can be accessed via [`Storages`](crate::storage::Storages)
595
#[derive(Default)]
596
pub struct SparseSets {
597
sets: SparseSet<ComponentId, ComponentSparseSet>,
598
}
599
600
impl SparseSets {
601
/// Returns the number of [`ComponentSparseSet`]s this collection contains.
602
#[inline]
603
pub fn len(&self) -> usize {
604
self.sets.len()
605
}
606
607
/// Returns true if this collection contains no [`ComponentSparseSet`]s.
608
#[inline]
609
pub fn is_empty(&self) -> bool {
610
self.sets.is_empty()
611
}
612
613
/// An Iterator visiting all ([`ComponentId`], [`ComponentSparseSet`]) pairs.
614
/// NOTE: Order is not guaranteed.
615
pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ComponentSparseSet)> {
616
self.sets.iter().map(|(id, data)| (*id, data))
617
}
618
619
/// Gets a reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.
620
#[inline]
621
pub fn get(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {
622
self.sets.get(component_id)
623
}
624
625
/// Gets a mutable reference of [`ComponentSparseSet`] of a [`ComponentInfo`].
626
/// Create a new [`ComponentSparseSet`] if not exists.
627
pub(crate) fn get_or_insert(
628
&mut self,
629
component_info: &ComponentInfo,
630
) -> &mut ComponentSparseSet {
631
if !self.sets.contains(component_info.id()) {
632
self.sets.insert(
633
component_info.id(),
634
ComponentSparseSet::new(component_info, 64),
635
);
636
}
637
638
self.sets.get_mut(component_info.id()).unwrap()
639
}
640
641
/// Gets a mutable reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.
642
pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ComponentSparseSet> {
643
self.sets.get_mut(component_id)
644
}
645
646
/// Clear entities stored in each [`ComponentSparseSet`]
647
pub(crate) fn clear_entities(&mut self) {
648
for set in self.sets.values_mut() {
649
set.clear();
650
}
651
}
652
653
pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {
654
for set in self.sets.values_mut() {
655
set.check_change_ticks(check);
656
}
657
}
658
}
659
660
#[cfg(test)]
661
mod tests {
662
use super::SparseSets;
663
use crate::{
664
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo},
665
entity::{Entity, EntityRow},
666
storage::SparseSet,
667
};
668
use alloc::{vec, vec::Vec};
669
use nonmax::NonMaxU32;
670
671
#[derive(Debug, Eq, PartialEq)]
672
struct Foo(usize);
673
674
#[test]
675
fn sparse_set() {
676
let mut set = SparseSet::<Entity, Foo>::default();
677
let e0 = Entity::from_raw(EntityRow::new(NonMaxU32::new(0).unwrap()));
678
let e1 = Entity::from_raw(EntityRow::new(NonMaxU32::new(1).unwrap()));
679
let e2 = Entity::from_raw(EntityRow::new(NonMaxU32::new(2).unwrap()));
680
let e3 = Entity::from_raw(EntityRow::new(NonMaxU32::new(3).unwrap()));
681
let e4 = Entity::from_raw(EntityRow::new(NonMaxU32::new(4).unwrap()));
682
683
set.insert(e1, Foo(1));
684
set.insert(e2, Foo(2));
685
set.insert(e3, Foo(3));
686
687
assert_eq!(set.get(e0), None);
688
assert_eq!(set.get(e1), Some(&Foo(1)));
689
assert_eq!(set.get(e2), Some(&Foo(2)));
690
assert_eq!(set.get(e3), Some(&Foo(3)));
691
assert_eq!(set.get(e4), None);
692
693
{
694
let iter_results = set.values().collect::<Vec<_>>();
695
assert_eq!(iter_results, vec![&Foo(1), &Foo(2), &Foo(3)]);
696
}
697
698
assert_eq!(set.remove(e2), Some(Foo(2)));
699
assert_eq!(set.remove(e2), None);
700
701
assert_eq!(set.get(e0), None);
702
assert_eq!(set.get(e1), Some(&Foo(1)));
703
assert_eq!(set.get(e2), None);
704
assert_eq!(set.get(e3), Some(&Foo(3)));
705
assert_eq!(set.get(e4), None);
706
707
assert_eq!(set.remove(e1), Some(Foo(1)));
708
709
assert_eq!(set.get(e0), None);
710
assert_eq!(set.get(e1), None);
711
assert_eq!(set.get(e2), None);
712
assert_eq!(set.get(e3), Some(&Foo(3)));
713
assert_eq!(set.get(e4), None);
714
715
set.insert(e1, Foo(10));
716
717
assert_eq!(set.get(e1), Some(&Foo(10)));
718
719
*set.get_mut(e1).unwrap() = Foo(11);
720
assert_eq!(set.get(e1), Some(&Foo(11)));
721
}
722
723
#[test]
724
fn sparse_sets() {
725
let mut sets = SparseSets::default();
726
727
#[derive(Component, Default, Debug)]
728
struct TestComponent1;
729
730
#[derive(Component, Default, Debug)]
731
struct TestComponent2;
732
733
assert_eq!(sets.len(), 0);
734
assert!(sets.is_empty());
735
736
register_component::<TestComponent1>(&mut sets, 1);
737
assert_eq!(sets.len(), 1);
738
739
register_component::<TestComponent2>(&mut sets, 2);
740
assert_eq!(sets.len(), 2);
741
742
// check its shape by iter
743
let mut collected_sets = sets
744
.iter()
745
.map(|(id, set)| (id, set.len()))
746
.collect::<Vec<_>>();
747
collected_sets.sort();
748
assert_eq!(
749
collected_sets,
750
vec![(ComponentId::new(1), 0), (ComponentId::new(2), 0),]
751
);
752
753
fn register_component<T: Component>(sets: &mut SparseSets, id: usize) {
754
let descriptor = ComponentDescriptor::new::<T>();
755
let id = ComponentId::new(id);
756
let info = ComponentInfo::new(id, descriptor);
757
sets.get_or_insert(&info);
758
}
759
}
760
}
761
762