add len, is_empty, iter method on SparseSets, make SparseSets inspect… (#7638)

…able like Table. Rename clear to clear_entities to clarify that metadata keeps, only value cleared

# Objective

- Provide some inspectability for SparseSets. 

## Solution

- `Tables` has these three methods, len, is_empty and iter too. Add these methods to `SparseSets`, so user can print the shape of storage.

---

## Changelog

> This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section.

- Add `len`, `is_empty`, `iter` methods on SparseSets.
- Rename `clear` to `clear_entities` to clarify its purpose.
- Add `new_for_test` on `ComponentInfo` to make test code easy.
- Add test case covering new methods.

## Migration Guide

> This section is optional. If there are no breaking changes, you can delete this section.

- Simply adding new functionality is not a breaking change.
This commit is contained in:
shuo 2023-02-15 23:52:02 +00:00
parent e392e99f7e
commit 1dc713b605
4 changed files with 83 additions and 10 deletions

View file

@ -239,7 +239,8 @@ impl ComponentInfo {
self.descriptor.is_send_and_sync
}
fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {
/// Create a new [`ComponentInfo`].
pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {
ComponentInfo { id, descriptor }
}
}

View file

@ -497,7 +497,35 @@ pub struct SparseSets {
}
impl SparseSets {
pub fn get_or_insert(&mut self, component_info: &ComponentInfo) -> &mut ComponentSparseSet {
/// Returns the number of [`ComponentSparseSet`]s this collection contains.
#[inline]
pub fn len(&self) -> usize {
self.sets.len()
}
/// Returns true if this collection contains no [`ComponentSparseSet`]s.
#[inline]
pub fn is_empty(&self) -> bool {
self.sets.is_empty()
}
/// An Iterator visiting all ([`ComponentId`], [`ComponentSparseSet`]) pairs.
/// NOTE: Order is not guaranteed.
pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ComponentSparseSet)> {
self.sets.iter().map(|(id, data)| (*id, data))
}
/// Gets a reference to the [`ComponentSparseSet`] of a [`ComponentId`].
pub fn get(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {
self.sets.get(component_id)
}
/// Gets a mutable reference of [`ComponentSparseSet`] of a [`ComponentInfo`].
/// Create a new [`ComponentSparseSet`] if not exists.
pub(crate) fn get_or_insert(
&mut self,
component_info: &ComponentInfo,
) -> &mut ComponentSparseSet {
if !self.sets.contains(component_info.id()) {
self.sets.insert(
component_info.id(),
@ -508,15 +536,13 @@ impl SparseSets {
self.sets.get_mut(component_info.id()).unwrap()
}
pub fn get(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {
self.sets.get(component_id)
}
pub fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ComponentSparseSet> {
/// Gets a mutable reference to the [`ComponentSparseSet`] of a [`ComponentId`].
pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ComponentSparseSet> {
self.sets.get_mut(component_id)
}
pub fn clear(&mut self) {
/// Clear entities stored in each [`ComponentSparseSet`]
pub(crate) fn clear_entities(&mut self) {
for set in self.sets.values_mut() {
set.clear();
}
@ -531,7 +557,13 @@ impl SparseSets {
#[cfg(test)]
mod tests {
use crate::{entity::Entity, storage::SparseSet};
use super::SparseSets;
use crate::{
self as bevy_ecs,
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo},
entity::Entity,
storage::SparseSet,
};
#[derive(Debug, Eq, PartialEq)]
struct Foo(usize);
@ -584,4 +616,42 @@ mod tests {
*set.get_mut(e1).unwrap() = Foo(11);
assert_eq!(set.get(e1), Some(&Foo(11)));
}
#[test]
fn sparse_sets() {
let mut sets = SparseSets::default();
#[derive(Component, Default, Debug)]
struct TestComponent1;
#[derive(Component, Default, Debug)]
struct TestComponent2;
assert_eq!(sets.len(), 0);
assert!(sets.is_empty());
init_component::<TestComponent1>(&mut sets, 1);
assert_eq!(sets.len(), 1);
init_component::<TestComponent2>(&mut sets, 2);
assert_eq!(sets.len(), 2);
// check its shape by iter
let mut collected_sets = sets
.iter()
.map(|(id, set)| (id, set.len()))
.collect::<Vec<_>>();
collected_sets.sort();
assert_eq!(
collected_sets,
vec![(ComponentId::new(1), 0), (ComponentId::new(2), 0),]
);
fn init_component<T: Component>(sets: &mut SparseSets, id: usize) {
let descriptor = ComponentDescriptor::new::<TestComponent1>();
let id = ComponentId::new(id);
let info = ComponentInfo::new(id, descriptor);
sets.get_or_insert(&info);
}
}
}

View file

@ -654,11 +654,13 @@ pub(crate) struct TableMoveResult {
}
impl Tables {
/// Returns the number of [`Table`]s this collection contains
#[inline]
pub fn len(&self) -> usize {
self.tables.len()
}
/// Returns true if this collection contains no [`Table`]s
#[inline]
pub fn is_empty(&self) -> bool {
self.tables.is_empty()

View file

@ -1538,7 +1538,7 @@ impl World {
/// Despawns all entities in this [`World`].
pub fn clear_entities(&mut self) {
self.storages.tables.clear();
self.storages.sparse_sets.clear();
self.storages.sparse_sets.clear_entities();
self.archetypes.clear_entities();
self.entities.clear();
}