feat(ecs): limited the creation of archetypes to three unique components to lower the creation to polynomial complexity

This commit is contained in:
lisk77 2025-07-26 01:13:23 +02:00
parent 0da5200916
commit d04c706a94
5 changed files with 409 additions and 421 deletions

View file

@ -1,7 +1,5 @@
use comet_colors::{Color as ColorTrait, LinearRgba}; use comet_colors::{Color as ColorTrait, LinearRgba};
use comet_ecs::{ use comet_ecs::{Camera2D, Component, Entity, Render2D, Scene, Text, Transform2D, Transform3D};
Camera2D, Color, Component, Entity, Render2D, Scene, Text, Transform2D, Transform3D,
};
use comet_input::keyboard::Key; use comet_input::keyboard::Key;
use comet_log::*; use comet_log::*;
use comet_renderer::renderer::Renderer; use comet_renderer::renderer::Renderer;

View file

@ -215,16 +215,14 @@ impl Scene {
self.create_archetype(new_component_set.clone()); self.create_archetype(new_component_set.clone());
} }
let powerset = ComponentSet::powerset(new_component_set.to_vec()); let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
for subset in powerset { for subset in subsets {
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect()); if !self.archetypes.contains_archetype(&subset) {
self.create_archetype(subset.clone());
if !self.archetypes.contains_archetype(&component_set) {
self.create_archetype(component_set.clone());
} }
self.add_entity_to_archetype(entity_id as u32, component_set); self.add_entity_to_archetype(entity_id as u32, subset);
} }
info!( info!(
@ -256,16 +254,14 @@ impl Scene {
self.create_archetype(new_component_set.clone()); self.create_archetype(new_component_set.clone());
} }
let powerset = ComponentSet::powerset(new_component_set.to_vec()); let subsets = ComponentSet::compute_subsets_up_to_size_3(new_component_set.to_vec());
for subset in powerset { for subset in subsets {
let component_set = ComponentSet::from_ids(subset.iter().cloned().collect()); if !self.archetypes.contains_archetype(&subset) {
self.create_archetype(subset.clone());
if !self.archetypes.contains_archetype(&component_set) {
self.create_archetype(component_set.clone());
} }
self.add_entity_to_archetype(entity_id as u32, component_set); self.add_entity_to_archetype(entity_id as u32, subset);
} }
} }
@ -295,6 +291,10 @@ impl Scene {
/// Returns a list of entities that have the given components. /// Returns a list of entities that have the given components.
pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> { pub fn get_entities_with(&self, components: Vec<TypeId>) -> Vec<usize> {
let component_set = ComponentSet::from_ids(components); let component_set = ComponentSet::from_ids(components);
if component_set.size() > 3 {
error!("An entity query should only contain at most 3 different components!");
return Vec::new();
}
if self.archetypes.contains_archetype(&component_set) { if self.archetypes.contains_archetype(&component_set) {
return self return self
.archetypes .archetypes
@ -316,7 +316,7 @@ impl Scene {
} }
} }
/// Iterates over all entities that have the given components and calls the given function. /// Iterates over all entities that have the two given components and calls the given function.
pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) { pub fn foreach<C: Component, K: Component>(&mut self, func: fn(&mut C, &mut K)) {
let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]); let entities = self.get_entities_with(vec![C::type_id(), K::type_id()]);
for entity in entities { for entity in entities {

View file

@ -1,299 +1,293 @@
use std::{
alloc::{
handle_alloc_error,
Layout
},
any::TypeId,
hash::{
Hash,
Hasher
},
mem::MaybeUninit,
ptr::NonNull
};
use std::ptr; use std::ptr;
use std::{
alloc::{handle_alloc_error, Layout},
any::TypeId,
mem::MaybeUninit,
ptr::NonNull,
};
// The following two structs are just blatantly stolen from Bevy - another Rust game engine. // The following two structs are just blatantly stolen from Bevy - another Rust game engine.
// I just need them for the ComponentStorage system, and I was too lazy to write them myself. // I just need them for the ComponentStorage system, and I was too lazy to write them myself.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct BlobVec { pub struct BlobVec {
item_layout: Layout, item_layout: Layout,
capacity: usize, capacity: usize,
len: usize, len: usize,
data: NonNull<u8>, data: NonNull<u8>,
swap_scratch: NonNull<u8>, swap_scratch: NonNull<u8>,
drop: unsafe fn(*mut u8) drop: unsafe fn(*mut u8),
} }
impl BlobVec { impl BlobVec {
pub fn new(item_layout: Layout, drop: unsafe fn(*mut u8), capacity: usize) -> Self { pub fn new(item_layout: Layout, drop: unsafe fn(*mut u8), capacity: usize) -> Self {
if item_layout.size() == 0 { if item_layout.size() == 0 {
BlobVec { BlobVec {
swap_scratch: NonNull::dangling(), swap_scratch: NonNull::dangling(),
data: NonNull::dangling(), data: NonNull::dangling(),
capacity: usize:: MAX, capacity: usize::MAX,
len: 0, len: 0,
item_layout, item_layout,
drop, drop,
} }
} } else {
else { let swap_scratch = NonNull::new(unsafe { std::alloc::alloc(item_layout) })
let swap_scratch = NonNull::new(unsafe { std::alloc::alloc(item_layout) }) .unwrap_or_else(|| handle_alloc_error(item_layout));
.unwrap_or_else(|| handle_alloc_error(item_layout));
let mut blob_vec = BlobVec { let mut blob_vec = BlobVec {
swap_scratch, swap_scratch,
data: NonNull::dangling(), data: NonNull::dangling(),
capacity: 0, capacity: 0,
len: 0, len: 0,
item_layout, item_layout,
drop, drop,
}; };
blob_vec.reserve_exact(capacity); blob_vec.reserve_exact(capacity);
blob_vec blob_vec
} }
} }
pub fn reserve_exact(&mut self, additional: usize) { pub fn reserve_exact(&mut self, additional: usize) {
let available_space = self.capacity - self.len; let available_space = self.capacity - self.len;
if available_space < additional { if available_space < additional {
self.grow_exact(additional - available_space); self.grow_exact(additional - available_space);
} }
} }
fn grow_exact(&mut self, increment: usize) { fn grow_exact(&mut self, increment: usize) {
debug_assert!(self.item_layout.size() != 0); debug_assert!(self.item_layout.size() != 0);
let new_capacity = self.capacity + increment; let new_capacity = self.capacity + increment;
let new_layout = let new_layout =
array_layout(&self.item_layout, new_capacity).expect("array layout should be valid"); array_layout(&self.item_layout, new_capacity).expect("array layout should be valid");
unsafe { unsafe {
let new_data = if self.capacity == 0 { let new_data = if self.capacity == 0 {
std::alloc::alloc(new_layout) std::alloc::alloc(new_layout)
} else { } else {
std::alloc::realloc( std::alloc::realloc(
self.get_ptr().as_ptr(), self.get_ptr().as_ptr(),
array_layout(&self.item_layout, self.capacity) array_layout(&self.item_layout, self.capacity)
.expect("array layout should be valid"), .expect("array layout should be valid"),
new_layout.size(), new_layout.size(),
) )
}; };
self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout)); self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout));
} }
self.capacity = new_capacity; self.capacity = new_capacity;
} }
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.len self.len
} }
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len == 0 self.len == 0
} }
#[inline] #[inline]
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
self.capacity self.capacity
} }
#[inline]
pub unsafe fn get_ptr(&self) -> NonNull<u8> {
self.data
}
#[inline] #[inline]
pub unsafe fn get_ptr(&self) -> NonNull<u8> { pub unsafe fn push_uninit(&mut self) -> usize {
self.data self.reserve_exact(1);
} let index = self.len;
self.len += 1;
index
}
#[inline] #[inline]
pub unsafe fn push_uninit(&mut self) -> usize { pub unsafe fn get_unchecked(&self, index: usize) -> *mut u8 {
self.reserve_exact(1); debug_assert!(index < self.len());
let index = self.len; self.get_ptr().as_ptr().add(index * self.item_layout.size())
self.len += 1; }
index
}
#[inline] #[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> *mut u8 { pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> *mut u8 {
debug_assert!(index < self.len()); debug_assert!(index < self.len());
self.get_ptr().as_ptr().add(index * self.item_layout.size()) self.get_ptr().as_ptr().add(index * self.item_layout.size())
} }
#[inline] pub unsafe fn push_element<T>(&mut self, element: T) {
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> *mut u8 { let index = self.push_uninit();
debug_assert!(index < self.len()); let ptr = self.get_unchecked(index) as *mut T;
self.get_ptr().as_ptr().add(index * self.item_layout.size()) ptr::write(ptr, element);
} }
pub unsafe fn push_element<T>(&mut self, element: T) { pub fn clear(&mut self) {
let index = self.push_uninit(); let len = self.len;
let ptr = self.get_unchecked(index) as *mut T; // We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't
ptr::write(ptr,element); // accidentally drop elements twice in the event of a drop impl panicking.
} self.len = 0;
for i in 0..len {
unsafe {
// NOTE: this doesn't use self.get_unchecked(i) because the debug_assert on index
// will panic here due to self.len being set to 0
let ptr = self.get_ptr().as_ptr().add(i * self.item_layout.size());
(self.drop)(ptr);
}
}
}
pub fn clear(&mut self) { #[inline]
let len = self.len; pub unsafe fn swap_remove_and_forget_unchecked(&mut self, index: usize) -> *mut u8 {
// We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't debug_assert!(index < self.len());
// accidentally drop elements twice in the event of a drop impl panicking. let last = self.len - 1;
self.len = 0; let swap_scratch = self.swap_scratch.as_ptr();
for i in 0..len { ptr::copy_nonoverlapping(
unsafe { self.get_unchecked(index),
// NOTE: this doesn't use self.get_unchecked(i) because the debug_assert on index swap_scratch,
// will panic here due to self.len being set to 0 self.item_layout.size(),
let ptr = self.get_ptr().as_ptr().add(i * self.item_layout.size()); );
(self.drop)(ptr); ptr::copy(
} self.get_unchecked(last),
} self.get_unchecked(index),
} self.item_layout.size(),
);
self.len -= 1;
swap_scratch
}
#[inline] #[inline]
pub unsafe fn swap_remove_and_forget_unchecked(&mut self, index: usize) -> *mut u8 { pub unsafe fn initialize_unchecked(&mut self, index: usize, value: *mut u8) {
debug_assert!(index < self.len()); debug_assert!(index < self.len());
let last = self.len - 1; let ptr = self.get_unchecked(index);
let swap_scratch = self.swap_scratch.as_ptr(); ptr::copy_nonoverlapping(value, ptr, self.item_layout.size());
ptr::copy_nonoverlapping( }
self.get_unchecked(index),
swap_scratch,
self.item_layout.size(),
);
ptr::copy(
self.get_unchecked(last),
self.get_unchecked(index),
self.item_layout.size(),
);
self.len -= 1;
swap_scratch
}
#[inline]
pub unsafe fn initialize_unchecked(&mut self, index: usize, value: *mut u8) {
debug_assert!(index < self.len());
let ptr = self.get_unchecked(index);
ptr::copy_nonoverlapping(value, ptr, self.item_layout.size());
}
} }
impl Drop for BlobVec { impl Drop for BlobVec {
fn drop(&mut self) { fn drop(&mut self) {
self.clear(); self.clear();
let array_layout = let array_layout =
array_layout(&self.item_layout, self.capacity).expect("array layout should be valid"); array_layout(&self.item_layout, self.capacity).expect("array layout should be valid");
if array_layout.size() > 0 { if array_layout.size() > 0 {
unsafe { unsafe {
std::alloc::dealloc(self.get_ptr().as_ptr(), array_layout); std::alloc::dealloc(self.get_ptr().as_ptr(), array_layout);
std::alloc::dealloc(self.swap_scratch.as_ptr(), self.item_layout); std::alloc::dealloc(self.swap_scratch.as_ptr(), self.item_layout);
} }
} }
} }
} }
unsafe impl Send for BlobVec {} unsafe impl Send for BlobVec {}
unsafe impl Sync for BlobVec {} unsafe impl Sync for BlobVec {}
fn array_layout(layout: &Layout, n: usize) -> Option<Layout> { fn array_layout(layout: &Layout, n: usize) -> Option<Layout> {
let (array_layout, offset) = repeat_layout(layout, n)?; let (array_layout, offset) = repeat_layout(layout, n)?;
debug_assert_eq!(layout.size(), offset); debug_assert_eq!(layout.size(), offset);
Some(array_layout) Some(array_layout)
} }
fn repeat_layout(layout: &Layout, n: usize) -> Option<(Layout, usize)> { fn repeat_layout(layout: &Layout, n: usize) -> Option<(Layout, usize)> {
let padded_size = layout.size() + padding_needed_for(layout, layout.align()); let padded_size = layout.size() + padding_needed_for(layout, layout.align());
let alloc_size = padded_size.checked_mul(n)?; let alloc_size = padded_size.checked_mul(n)?;
unsafe { unsafe {
Some(( Some((
Layout::from_size_align_unchecked(alloc_size, layout.align()), Layout::from_size_align_unchecked(alloc_size, layout.align()),
padded_size, padded_size,
)) ))
} }
} }
const fn padding_needed_for(layout: &Layout, align: usize) -> usize { const fn padding_needed_for(layout: &Layout, align: usize) -> usize {
let len = layout.size(); let len = layout.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len) len_rounded_up.wrapping_sub(len)
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Column { pub struct Column {
pub data: BlobVec pub data: BlobVec,
} }
impl Column { impl Column {
pub fn new<T: 'static>(capacity: usize) -> Self { pub fn new<T: 'static>(capacity: usize) -> Self {
let layout = Layout::new::<T>(); let layout = Layout::new::<T>();
let drop_fn = |ptr: *mut u8| unsafe { let drop_fn = |ptr: *mut u8| unsafe {
ptr::drop_in_place(ptr as *mut T); ptr::drop_in_place(ptr as *mut T);
}; };
Self { Self {
data: BlobVec::new(layout, drop_fn, capacity), data: BlobVec::new(layout, drop_fn, capacity),
} }
} }
pub fn data(&self) -> BlobVec { pub fn data(&self) -> BlobVec {
self.data.clone() self.data.clone()
} }
pub fn push<T: 'static>(&mut self, item: T) { pub fn push<T: 'static>(&mut self, item: T) {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch"); assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
unsafe { unsafe {
let index = self.data.push_uninit(); let index = self.data.push_uninit();
let ptr = self.data.get_unchecked(index); let ptr = self.data.get_unchecked(index);
ptr::write(ptr as *mut T, item); ptr::write(ptr as *mut T, item);
} }
} }
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> { pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch"); assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
if index >= self.data.len() { if index >= self.data.len() {
return None; return None;
} }
unsafe { unsafe {
let ptr = self.data.get_unchecked(index); let ptr = self.data.get_unchecked(index);
Some(&*(ptr as *const T)) Some(&*(ptr as *const T))
} }
} }
pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> { pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch"); assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
if index >= self.data.len() { if index >= self.data.len() {
return None; return None;
} }
// Access the element at the given index // Access the element at the given index
unsafe { unsafe {
let ptr = self.data.get_unchecked(index); let ptr = self.data.get_unchecked(index);
// Convert the pointer to a mutable reference and return it // Convert the pointer to a mutable reference and return it
Some(&mut *(ptr as *mut T)) Some(&mut *(ptr as *mut T))
} }
} }
pub fn remove<T: 'static>(&mut self, index: usize) -> Option<T> { pub fn remove<T: 'static>(&mut self, index: usize) -> Option<T> {
assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch"); assert_eq!(TypeId::of::<T>(), TypeId::of::<T>(), "Type mismatch");
if index >= self.data.len() { if index >= self.data.len() {
return None; return None;
} }
unsafe { unsafe {
let ptr = self.data.swap_remove_and_forget_unchecked(index); let ptr = self.data.swap_remove_and_forget_unchecked(index);
Some(ptr::read(ptr as *const T)) Some(ptr::read(ptr as *const T))
} }
} }
pub fn swap(&mut self, index1: usize, index2: usize) { pub fn swap(&mut self, index1: usize, index2: usize) {
assert!(index1 < self.data.len() && index2 < self.data.len(), "Index out of bounds"); assert!(
index1 < self.data.len() && index2 < self.data.len(),
"Index out of bounds"
);
unsafe { unsafe {
let ptr1 = self.data.get_unchecked(index1); let ptr1 = self.data.get_unchecked(index1);
let ptr2 = self.data.get_unchecked(index2); let ptr2 = self.data.get_unchecked(index2);
let mut temp = MaybeUninit::<u8>::uninit(); let mut temp = MaybeUninit::<u8>::uninit();
// Swap the elements at index1 and index2 // Swap the elements at index1 and index2
ptr::copy_nonoverlapping(ptr1, temp.as_mut_ptr(), self.data.item_layout.size()); ptr::copy_nonoverlapping(ptr1, temp.as_mut_ptr(), self.data.item_layout.size());
ptr::copy_nonoverlapping(ptr2, ptr1, self.data.item_layout.size()); ptr::copy_nonoverlapping(ptr2, ptr1, self.data.item_layout.size());
ptr::copy_nonoverlapping(temp.as_ptr(), ptr2, self.data.item_layout.size()); ptr::copy_nonoverlapping(temp.as_ptr(), ptr2, self.data.item_layout.size());
} }
} }
} }

View file

@ -4,53 +4,82 @@ use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct ComponentSet { pub struct ComponentSet {
set: HashSet<TypeId> set: HashSet<TypeId>,
} }
impl ComponentSet { impl ComponentSet {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
set: HashSet::new() set: HashSet::new(),
} }
} }
pub fn from_ids(ids: Vec<TypeId>) -> Self { pub fn from_ids(ids: Vec<TypeId>) -> Self {
Self { Self {
set: ids.into_iter().collect() set: ids.into_iter().collect(),
} }
} }
pub fn powerset(ids: Vec<TypeId>) -> Vec<HashSet<TypeId>> { pub fn compute_subsets_up_to_size_3(ids: Vec<TypeId>) -> Vec<ComponentSet> {
let n = ids.len(); let mut result = Vec::new();
let mut subsets: Vec<HashSet<TypeId>> = Vec::with_capacity(1 << n); let n = ids.len();
for mask in 0..(1 << n) {
let mut subset = HashSet::new();
for i in 0..n {
if (mask & (1 << i)) != 0 {
subset.insert(ids[i].clone());
}
}
subsets.push(subset);
}
subsets.remove(0);
subsets for i in 0..n {
} result.push(ComponentSet::from_ids(vec![ids[i]]));
}
pub fn is_subset(&self, other: &ComponentSet) -> bool { for i in 0..n {
self.set.is_subset(&other.set) for j in (i + 1)..n {
} result.push(ComponentSet::from_ids(vec![ids[i], ids[j]]));
}
}
pub fn to_vec(&self) -> Vec<TypeId> { for i in 0..n {
self.set.iter().cloned().collect() for j in (i + 1)..n {
} for k in (j + 1)..n {
result.push(ComponentSet::from_ids(vec![ids[i], ids[j], ids[k]]));
}
}
}
result
}
pub fn powerset(ids: Vec<TypeId>) -> Vec<HashSet<TypeId>> {
let n = ids.len();
let mut subsets: Vec<HashSet<TypeId>> = Vec::with_capacity(1 << n);
for mask in 0..(1 << n) {
let mut subset = HashSet::new();
for i in 0..n {
if (mask & (1 << i)) != 0 {
subset.insert(ids[i].clone());
}
}
subsets.push(subset);
}
subsets.remove(0);
subsets
}
pub fn is_subset(&self, other: &ComponentSet) -> bool {
self.set.is_subset(&other.set)
}
pub fn to_vec(&self) -> Vec<TypeId> {
self.set.iter().cloned().collect()
}
pub fn size(&self) -> usize {
self.set.len()
}
} }
impl Hash for ComponentSet { impl Hash for ComponentSet {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
let mut types: Vec<TypeId> = self.set.iter().cloned().collect(); let mut types: Vec<TypeId> = self.set.iter().cloned().collect();
types.sort(); types.sort();
types.hash(state); types.hash(state);
} }
} }

View file

@ -1,142 +1,109 @@
use crate::Column; use crate::Column;
use std::hash::{
Hash,
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SparseSet { pub struct SparseSet {
sparse: Vec<Option<Vec<Option<usize>>>>, sparse: Vec<Option<Vec<Option<usize>>>>,
dense: Column, dense: Column,
page_size: usize page_size: usize,
} }
impl SparseSet { impl SparseSet {
pub fn new<T: 'static>(capacity: usize, page_size: usize) -> Self { pub fn new<T: 'static>(capacity: usize, page_size: usize) -> Self {
Self { Self {
sparse: Vec::new(), sparse: Vec::new(),
dense: Column::new::<T>(capacity), dense: Column::new::<T>(capacity),
page_size page_size,
} }
} }
pub fn insert<T: 'static>(&mut self, index: usize, value: T) { pub fn insert<T: 'static>(&mut self, index: usize, value: T) {
let page = index / self.page_size; let page = index / self.page_size;
if page >= self.sparse.len() { if page >= self.sparse.len() {
self.sparse.resize(page + 1, None); self.sparse.resize(page + 1, None);
} }
if self.sparse[page].is_none() { if self.sparse[page].is_none() {
self.sparse[page] = Some(vec![None; self.page_size]); self.sparse[page] = Some(vec![None; self.page_size]);
} }
if let Some(page_vec) = &mut self.sparse[page] { if let Some(page_vec) = &mut self.sparse[page] {
page_vec[index % self.page_size] = Some(self.dense.data.len()); page_vec[index % self.page_size] = Some(self.dense.data.len());
} }
self.dense.push(value); self.dense.push(value);
} }
pub fn remove<T: 'static>(&mut self, index: usize) -> Option<T> { pub fn remove<T: 'static>(&mut self, index: usize) -> Option<T> {
if let Some(page_vec) = self.sparse.get(index / self.page_size).and_then(|x| x.as_ref()) { if let Some(page_vec) = self
if let Some(sparse_index) = page_vec.get(index % self.page_size).and_then(|x| x.as_ref()) { .sparse
let dense_index = *sparse_index; .get(index / self.page_size)
let last_index = self.dense.data.len() - 1; .and_then(|x| x.as_ref())
if dense_index != last_index { {
self.dense.swap(dense_index, last_index); if let Some(sparse_index) = page_vec
if let Some(page_vec) = self.sparse.get_mut(last_index / self.page_size).and_then(|x| x.as_mut()) { .get(index % self.page_size)
page_vec[last_index % self.page_size] = Some(dense_index); .and_then(|x| x.as_ref())
} {
} let dense_index = *sparse_index;
if let Some(page_vec) = self.sparse.get_mut(index / self.page_size).and_then(|x| x.as_mut()) { let last_index = self.dense.data.len() - 1;
page_vec[index % self.page_size] = None; if dense_index != last_index {
} self.dense.swap(dense_index, last_index);
return self.dense.remove::<T>(last_index); if let Some(page_vec) = self
} .sparse
} .get_mut(last_index / self.page_size)
None .and_then(|x| x.as_mut())
} {
page_vec[last_index % self.page_size] = Some(dense_index);
}
}
if let Some(page_vec) = self
.sparse
.get_mut(index / self.page_size)
.and_then(|x| x.as_mut())
{
page_vec[index % self.page_size] = None;
}
return self.dense.remove::<T>(last_index);
}
}
None
}
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> { pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
if let Some(page_vec) = self.sparse.get(index / self.page_size).and_then(|x| x.as_ref()) { if let Some(page_vec) = self
if let Some(sparse_index) = page_vec.get(index % self.page_size).and_then(|x| x.as_ref()) { .sparse
self.dense.get::<T>(*sparse_index) .get(index / self.page_size)
} .and_then(|x| x.as_ref())
else { {
None if let Some(sparse_index) = page_vec
} .get(index % self.page_size)
} .and_then(|x| x.as_ref())
else { {
None self.dense.get::<T>(*sparse_index)
} } else {
} None
}
} else {
None
}
}
pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> { pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> {
if let Some(page_vec) = self.sparse.get(index / self.page_size).and_then(|x| x.as_ref()) { if let Some(page_vec) = self
if let Some(sparse_index) = page_vec.get(index % self.page_size).and_then(|x| x.as_ref()) { .sparse
self.dense.get_mut::<T>(*sparse_index) .get(index / self.page_size)
} .and_then(|x| x.as_ref())
else { {
None if let Some(sparse_index) = page_vec
} .get(index % self.page_size)
} .and_then(|x| x.as_ref())
else { {
None self.dense.get_mut::<T>(*sparse_index)
} } else {
} None
}
} else {
None
}
}
} }
/*#[derive(Debug, Clone)]
pub struct SparseSet {
sparse: Vec<Option<usize>>,
dense: Column,
}
impl SparseSet {
pub fn new<T: 'static>(capacity: usize) -> Self {
Self {
sparse: Vec::new(),
dense: Column::new::<T>(capacity),
}
}
pub fn insert<T: 'static>(&mut self, index: usize, value: T) {
if index >= self.sparse.len() {
self.sparse.resize(index + 1, None);
}
self.sparse[index] = Some(self.dense.data.len());
self.dense.push(value);
}
pub fn remove<T: 'static>(&mut self, index: usize) -> Option<T>{
if let Some(sparse_index) = self.sparse.get(index).and_then(|x| x.as_ref()) {
let dense_index = *sparse_index;
let last_index = self.dense.data.len() - 1;
if dense_index != last_index {
self.dense.swap(dense_index, last_index);
if let Some(sparse) = self.sparse.get_mut(last_index) {
*sparse = Some(dense_index);
}
}
self.sparse[index] = None;
self.dense.remove::<T>(last_index)
}
else {
None
}
}
pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
match self.sparse.get(index).and_then(|x| x.as_ref()) {
Some(sparse_index) => self.dense.get::<T>(*sparse_index),
None => None,
}
}
pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> {
match self.sparse.get(index).and_then(|x| x.as_ref()) {
Some(sparse_index) => self.dense.get_mut::<T>(*sparse_index),
None => None,
}
}
}*/