Merge pull request #2714 from Amanieu/more_entitylist
EntityList improvments
This commit is contained in:
@@ -307,6 +307,24 @@ impl<T: EntityRef + ReservedValue> EntityList<T> {
|
|||||||
self.as_mut_slice(pool).get_mut(index)
|
self.as_mut_slice(pool).get_mut(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a deep clone of the list, which does not alias the original list.
|
||||||
|
pub fn deep_clone(&self, pool: &mut ListPool<T>) -> Self {
|
||||||
|
match pool.len_of(self) {
|
||||||
|
None => return Self::new(),
|
||||||
|
Some(len) => {
|
||||||
|
let src = self.index as usize;
|
||||||
|
let block = pool.alloc(sclass_for_length(len));
|
||||||
|
pool.data[block] = T::new(len);
|
||||||
|
pool.data.copy_within(src..src + len, block + 1);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
index: (block + 1) as u32,
|
||||||
|
unused: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes all elements from the list.
|
/// Removes all elements from the list.
|
||||||
///
|
///
|
||||||
/// The memory used by the list is put back in the pool.
|
/// The memory used by the list is put back in the pool.
|
||||||
@@ -445,20 +463,8 @@ impl<T: EntityRef + ReservedValue> EntityList<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the element at position `index` from the list. Potentially linear complexity.
|
/// Removes the last element from the list.
|
||||||
pub fn remove(&mut self, index: usize, pool: &mut ListPool<T>) {
|
fn remove_last(&mut self, len: usize, pool: &mut ListPool<T>) {
|
||||||
let len;
|
|
||||||
{
|
|
||||||
let seq = self.as_mut_slice(pool);
|
|
||||||
len = seq.len();
|
|
||||||
debug_assert!(index < len);
|
|
||||||
|
|
||||||
// Copy elements down.
|
|
||||||
for i in index..len - 1 {
|
|
||||||
seq[i] = seq[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we deleted the last element.
|
// Check if we deleted the last element.
|
||||||
if len == 1 {
|
if len == 1 {
|
||||||
self.clear(pool);
|
self.clear(pool);
|
||||||
@@ -477,19 +483,64 @@ impl<T: EntityRef + ReservedValue> EntityList<T> {
|
|||||||
pool.data[block] = T::new(len - 1);
|
pool.data[block] = T::new(len - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes the element at position `index` from the list. Potentially linear complexity.
|
||||||
|
pub fn remove(&mut self, index: usize, pool: &mut ListPool<T>) {
|
||||||
|
let len;
|
||||||
|
{
|
||||||
|
let seq = self.as_mut_slice(pool);
|
||||||
|
len = seq.len();
|
||||||
|
debug_assert!(index < len);
|
||||||
|
|
||||||
|
// Copy elements down.
|
||||||
|
for i in index..len - 1 {
|
||||||
|
seq[i] = seq[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_last(len, pool);
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes the element at `index` in constant time by switching it with the last element of
|
/// Removes the element at `index` in constant time by switching it with the last element of
|
||||||
/// the list.
|
/// the list.
|
||||||
pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool<T>) {
|
pub fn swap_remove(&mut self, index: usize, pool: &mut ListPool<T>) {
|
||||||
let len = self.len(pool);
|
let seq = self.as_mut_slice(pool);
|
||||||
|
let len = seq.len();
|
||||||
debug_assert!(index < len);
|
debug_assert!(index < len);
|
||||||
if index == len - 1 {
|
if index != len - 1 {
|
||||||
self.remove(index, pool);
|
seq.swap(index, len - 1);
|
||||||
} else {
|
}
|
||||||
{
|
|
||||||
let seq = self.as_mut_slice(pool);
|
self.remove_last(len, pool);
|
||||||
seq.swap(index, len - 1);
|
}
|
||||||
|
|
||||||
|
/// Shortens the list down to `len` elements.
|
||||||
|
///
|
||||||
|
/// Does nothing if the list is already shorter than `len`.
|
||||||
|
pub fn truncate(&mut self, new_len: usize, pool: &mut ListPool<T>) {
|
||||||
|
if new_len == 0 {
|
||||||
|
self.clear(pool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match pool.len_of(self) {
|
||||||
|
None => return,
|
||||||
|
Some(len) => {
|
||||||
|
if len <= new_len {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block;
|
||||||
|
let idx = self.index as usize;
|
||||||
|
let sclass = sclass_for_length(len);
|
||||||
|
let new_sclass = sclass_for_length(new_len);
|
||||||
|
if sclass != new_sclass {
|
||||||
|
block = pool.realloc(idx - 1, sclass, new_sclass, new_len + 1);
|
||||||
|
self.index = (block + 1) as u32;
|
||||||
|
} else {
|
||||||
|
block = idx - 1;
|
||||||
|
}
|
||||||
|
pool.data[block] = T::new(new_len);
|
||||||
}
|
}
|
||||||
self.remove(len - 1, pool);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,4 +787,44 @@ mod tests {
|
|||||||
list.as_mut_slice(pool)[3] = i4;
|
list.as_mut_slice(pool)[3] = i4;
|
||||||
assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]);
|
assert_eq!(list.as_slice(pool), &[i2, i1, i3, i4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deep_clone() {
|
||||||
|
let pool = &mut ListPool::<Inst>::new();
|
||||||
|
|
||||||
|
let i1 = Inst::new(1);
|
||||||
|
let i2 = Inst::new(2);
|
||||||
|
let i3 = Inst::new(3);
|
||||||
|
let i4 = Inst::new(4);
|
||||||
|
|
||||||
|
let mut list1 = EntityList::from_slice(&[i1, i2, i3], pool);
|
||||||
|
let list2 = list1.deep_clone(pool);
|
||||||
|
assert_eq!(list1.as_slice(pool), &[i1, i2, i3]);
|
||||||
|
assert_eq!(list2.as_slice(pool), &[i1, i2, i3]);
|
||||||
|
|
||||||
|
list1.as_mut_slice(pool)[0] = i4;
|
||||||
|
assert_eq!(list1.as_slice(pool), &[i4, i2, i3]);
|
||||||
|
assert_eq!(list2.as_slice(pool), &[i1, i2, i3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn truncate() {
|
||||||
|
let pool = &mut ListPool::<Inst>::new();
|
||||||
|
|
||||||
|
let i1 = Inst::new(1);
|
||||||
|
let i2 = Inst::new(2);
|
||||||
|
let i3 = Inst::new(3);
|
||||||
|
let i4 = Inst::new(4);
|
||||||
|
|
||||||
|
let mut list = EntityList::from_slice(&[i1, i2, i3, i4, i1, i2, i3, i4], pool);
|
||||||
|
assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2, i3, i4]);
|
||||||
|
list.truncate(6, pool);
|
||||||
|
assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]);
|
||||||
|
list.truncate(9, pool);
|
||||||
|
assert_eq!(list.as_slice(pool), &[i1, i2, i3, i4, i1, i2]);
|
||||||
|
list.truncate(2, pool);
|
||||||
|
assert_eq!(list.as_slice(pool), &[i1, i2]);
|
||||||
|
list.truncate(0, pool);
|
||||||
|
assert!(list.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user