extern crate alloc;
use crate::{Cursor, CursorMut, ElemPool, Index, IndexError, IndexMap,
PieView, PieViewMut};
use crate::slot::Slot;
use core::{cmp, iter::FusedIterator, marker::PhantomData};
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = ""))]
#[must_use]
pub struct PieList<T> {
pub(crate) sentinel: Index<T>,
pub(crate) len: usize,
#[cfg(debug_assertions)]
check_leak: bool,
}
impl<T> PieList<T> {
#[inline]
pub(crate) fn shallow_copy(&self) -> Self {
PieList {
sentinel: self.sentinel,
len: self.len,
#[cfg(debug_assertions)]
check_leak: false, }
}
}
#[cfg(debug_assertions)]
impl<T> Drop for PieList<T> {
fn drop(&mut self) {
#[cfg(feature = "std")]
if std::thread::panicking() {
return;
}
if self.check_leak {
debug_assert!(
self.is_empty(),
"PieList dropped while not empty, causing a memory leak. You must call \
.clear() or .drain() before the list goes out of scope."
);
}
}
}
impl<T> PieList<T> {
pub fn new(pool: &mut ElemPool<T>) -> Self {
let sentinel = pool
.index_new()
.expect("Pool failed to allocate sentinel for new list");
let sentinel = pool
.index_make_sentinel(sentinel)
.expect("Failed to convert element to sentinel");
#[cfg(debug_assertions)]
{ Self { sentinel, len: 0, check_leak: true } }
#[cfg(not(debug_assertions))]
Self { sentinel, len: 0 }
}
#[allow(unused_mut)]
pub fn without_leak_check(mut self) -> Self {
#[cfg(debug_assertions)]
{ self.check_leak = false; }
self
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn front<'a>(&self, pool: &'a ElemPool<T>) -> Option<&'a T> {
if self.is_empty() {
return None;
}
let front_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
pool.data_at(front_slot)
}
#[inline]
pub fn front_mut<'a>(&mut self, pool: &'a mut ElemPool<T>) -> Option<&'a mut T> {
if self.is_empty() {
return None;
}
let front_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
pool.data_at_mut(front_slot)
}
#[inline]
pub fn back<'a>(&self, pool: &'a ElemPool<T>) -> Option<&'a T> {
if self.is_empty() {
return None;
}
let back_slot = pool.prev_slot(self.sentinel.slot as usize).unwrap();
pool.data_at(back_slot)
}
#[inline]
pub fn back_mut<'a>(&mut self, pool: &'a mut ElemPool<T>) -> Option<&'a mut T> {
if self.is_empty() {
return None;
}
let back_slot = pool.prev_slot(self.sentinel.slot as usize).unwrap();
pool.data_at_mut(back_slot)
}
#[inline]
pub fn push_front(&mut self, data: T, pool: &mut ElemPool<T>) -> Result<Index<T>, IndexError> {
let new_idx = pool.index_new_with_data(data)?;
pool.index_link_after(new_idx, self.sentinel)?;
self.len += 1;
Ok(new_idx)
}
#[inline]
pub fn push_back(&mut self, data: T, pool: &mut ElemPool<T>) -> Result<Index<T>, IndexError> {
let new_idx = pool.index_new_with_data(data)?;
pool.index_link_before(new_idx, self.sentinel)?;
self.len += 1;
Ok(new_idx)
}
#[inline]
pub fn pop_front(&mut self, pool: &mut ElemPool<T>) -> Option<T> {
if self.is_empty() {
return None;
}
let front_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
let front_idx = pool.index_from_slot(front_slot);
pool.index_linkout(front_idx).ok()?;
self.len -= 1;
let data = pool.data_swap(front_idx, None);
pool.index_del(front_idx).ok()?;
data
}
#[inline]
pub fn pop_back(&mut self, pool: &mut ElemPool<T>) -> Option<T> {
if self.is_empty() {
return None;
}
let back_slot = pool.prev_slot(self.sentinel.slot as usize).unwrap();
let back_idx = pool.index_from_slot(back_slot);
pool.index_linkout(back_idx).ok()?;
self.len -= 1;
let data = pool.data_swap(back_idx, None);
pool.index_del(back_idx).ok()?;
data
}
pub fn retain<F>(&mut self, pool: &mut ElemPool<T>, mut f: F)
where
F: FnMut(&T) -> bool,
{
let sentinel_slot = self.sentinel.slot as usize;
let mut current_slot = pool.next_slot(sentinel_slot).unwrap();
while current_slot != sentinel_slot {
let next_slot = pool.next_slot(current_slot).unwrap();
let keep = pool.data_at(current_slot)
.is_some_and(&mut f);
if !keep {
let idx = pool.index_from_slot(current_slot);
pool.index_linkout(idx).expect("retain: linkout of valid element failed");
self.len -= 1;
pool.data_swap(idx, None);
pool.index_del(idx).expect("retain: index_del of valid element failed");
}
current_slot = next_slot;
}
}
pub fn set_leak_check(&mut self, _leak_check: bool) {
#[cfg(debug_assertions)]
{ self.check_leak = _leak_check; }
}
pub fn clear(&mut self, pool: &mut ElemPool<T>) {
if self.is_empty() {
return;
}
let sentinel_slot = self.sentinel.slot as usize;
let mut current_slot = pool.next_slot(sentinel_slot).unwrap();
while current_slot != sentinel_slot {
let next_slot = pool.next_slot(current_slot).unwrap();
let current_idx = pool.index_from_slot(current_slot);
pool.data_swap(current_idx, None);
pool.index_del(current_idx).expect("valid node for deletion");
current_slot = next_slot;
}
let sentinel_slot_val = Slot::new(self.sentinel.slot);
pool.elem_mut(sentinel_slot).set_links(sentinel_slot_val, sentinel_slot_val);
self.len = 0;
}
pub fn drain<'a>(&'a mut self, pool: &'a mut ElemPool<T>) -> Drain<'a, T> {
let sentinel_slot = self.sentinel.slot as usize;
let front_slot = pool.next_slot(sentinel_slot).unwrap();
let back_slot = pool.prev_slot(sentinel_slot).unwrap();
let len = self.len;
let sentinel_slot_val = Slot::new(self.sentinel.slot);
pool.elem_mut(sentinel_slot).set_links(sentinel_slot_val, sentinel_slot_val);
self.len = 0;
Drain {
pool,
front_slot,
back_slot,
len,
_phantom: PhantomData,
}
}
pub fn sort<F>(&mut self, pool: &mut ElemPool<T>, mut compare: F)
where
F: FnMut(&T, &T) -> cmp::Ordering,
{
if self.len() < 2 {
return;
}
const MAX_STACK_SIZE: usize = 64;
let mut stack: [Option<PieList<T>>; MAX_STACK_SIZE] = core::array::from_fn(|_| None);
let needed_sentinels = (usize::BITS - self.len().leading_zeros()) as usize;
let mut sentinel_pool = [Index::<T>::NONE; MAX_STACK_SIZE];
let mut pool_top: usize = 0;
for _ in 0..needed_sentinels {
let sentinel = pool.index_new().expect("Pool failed to allocate temp sentinel");
let sentinel = pool.index_make_sentinel(sentinel).expect("Failed to make sentinel");
sentinel_pool[pool_top] = sentinel;
pool_top += 1;
}
while !self.is_empty() {
let front_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
let front_node = pool.index_from_slot(front_slot);
pool.index_linkout(front_node).expect("node is linked in list");
self.len -= 1;
let run_sentinel = if pool_top > 0 {
pool_top -= 1;
sentinel_pool[pool_top]
} else {
let s = pool.index_new().expect("Pool failed to allocate sentinel");
pool.index_make_sentinel(s).expect("Failed to make sentinel")
};
pool.index_link_after(front_node, run_sentinel).expect("valid list insertion point");
let mut run = PieList {
sentinel: run_sentinel,
len: 1,
#[cfg(debug_assertions)]
check_leak: false,
};
let mut slot = 0;
while slot < MAX_STACK_SIZE {
match stack[slot].take() {
None => {
stack[slot] = Some(run);
break;
}
Some(mut existing) => {
let old_sentinel = run.sentinel;
existing.merge(run, pool, &mut compare);
run = existing;
let old_slot = Slot::new(old_sentinel.slot);
let _ = pool.get_elem_mut(old_sentinel).map(|e| e.set_links(old_slot, old_slot));
sentinel_pool[pool_top] = old_sentinel;
pool_top += 1;
slot += 1;
}
}
}
}
let mut result: Option<PieList<T>> = None;
for slot in (0..MAX_STACK_SIZE).rev() {
if let Some(run) = stack[slot].take() {
match result.take() {
None => result = Some(run),
Some(mut existing) => {
let old_sentinel = run.sentinel;
existing.merge(run, pool, &mut compare);
let old_slot = Slot::new(old_sentinel.slot);
let _ = pool.get_elem_mut(old_sentinel).map(|e| e.set_links(old_slot, old_slot));
sentinel_pool[pool_top] = old_sentinel;
pool_top += 1;
result = Some(existing);
}
}
}
}
if let Some(sorted) = result {
let old_sentinel = self.sentinel;
self.sentinel = sorted.sentinel;
self.len = sorted.len;
let _ = pool.data_swap(old_sentinel, None);
let _ = pool.index_del(old_sentinel);
}
for sentinel in sentinel_pool.iter().take(pool_top) {
if *sentinel != self.sentinel {
let _ = pool.data_swap(*sentinel, None);
let _ = pool.index_del(*sentinel);
}
}
#[cfg(debug_assertions)]
{ self.check_leak = true; }
}
fn merge<F>(&mut self, mut other: PieList<T>, pool: &mut ElemPool<T>, compare: &mut F)
where
F: FnMut(&T, &T) -> cmp::Ordering,
{
if other.is_empty() {
return;
}
if self.is_empty() {
self.splice(self.sentinel, &mut other, pool).expect("valid splice position");
return;
}
let mut current_self_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
while !other.is_empty() && current_self_slot != self.sentinel.slot as usize {
let self_data = pool.data_at(current_self_slot).expect("slot contains valid data");
let other_data = other.front(pool).expect("non-empty list has front");
if compare(other_data, self_data) == cmp::Ordering::Less {
let node_to_move_slot = pool.next_slot(other.sentinel.slot as usize).unwrap();
let node_to_move = pool.index_from_slot(node_to_move_slot);
pool.index_linkout(node_to_move).expect("node is linked in list");
other.len -= 1;
let current_self_node = pool.index_from_slot(current_self_slot);
pool.index_link_before(node_to_move, current_self_node)
.expect("valid list insertion point");
self.len += 1;
} else {
current_self_slot = pool.next_slot(current_self_slot).unwrap();
}
}
if !other.is_empty() {
self.splice(self.sentinel, &mut other, pool).expect("valid splice position");
}
}
pub(crate) fn split_off(
&mut self,
split_node: Index<T>,
split_len: usize, pool: &mut ElemPool<T>,
) -> Result<PieList<T>, IndexError> {
let original_len = self.len();
if split_len == 0 {
return Ok(PieList::new(pool));
}
let mut new_list = PieList::new(pool);
let self_sentinel_slot = self.sentinel.slot as usize;
let new_sentinel_slot = new_list.sentinel.slot as usize;
let split_slot = split_node.slot as usize;
let original_front_slot = pool.next_slot(self_sentinel_slot).unwrap();
let before_split_slot = pool.prev_slot(split_slot).unwrap();
pool.elem_mut(new_sentinel_slot).set_links(
Slot::new(before_split_slot as u32),
Slot::new(original_front_slot as u32)
);
pool.elem_mut(original_front_slot).prev = Slot::new(new_sentinel_slot as u32);
pool.elem_mut(before_split_slot).next = Slot::new(new_sentinel_slot as u32);
pool.elem_mut(self_sentinel_slot).next = Slot::new(split_slot as u32);
pool.elem_mut(split_slot).prev = Slot::new(self_sentinel_slot as u32);
self.len = original_len - split_len;
new_list.len = split_len;
Ok(new_list)
}
pub(crate) fn splice(
&mut self,
insertion_node: Index<T>,
other: &mut PieList<T>,
pool: &mut ElemPool<T>,
) -> Result<(), IndexError> {
let other_len = other.len;
if other_len == 0 {
return Ok(());
}
let insertion_slot = insertion_node.slot as usize;
let other_sentinel_slot = other.sentinel.slot as usize;
let before_slot = pool.prev_slot(insertion_slot).unwrap();
let other_first_slot = pool.next_slot(other_sentinel_slot).unwrap();
let other_last_slot = pool.prev_slot(other_sentinel_slot).unwrap();
pool.elem_mut(before_slot).next = Slot::new(other_first_slot as u32);
pool.elem_mut(other_first_slot).prev = Slot::new(before_slot as u32);
pool.elem_mut(other_last_slot).next = Slot::new(insertion_slot as u32);
pool.elem_mut(insertion_slot).prev = Slot::new(other_last_slot as u32);
let other_sentinel_slot_val = Slot::new(other_sentinel_slot as u32);
pool.elem_mut(other_sentinel_slot).set_links(other_sentinel_slot_val, other_sentinel_slot_val);
self.len += other_len;
other.len = 0;
Ok(())
}
pub fn append(
&mut self,
other: &mut PieList<T>,
pool: &mut ElemPool<T>,
) -> Result<(), IndexError> {
self.splice(self.sentinel, other, pool)
}
pub fn prepend(
&mut self,
other: &mut PieList<T>,
pool: &mut ElemPool<T>,
) -> Result<(), IndexError> {
let sentinel_slot = self.sentinel.slot as usize;
let first_slot = pool.next_slot(sentinel_slot).unwrap();
self.splice(pool.index_from_slot(first_slot), other, pool)
}
pub fn iter<'a>(&self, pool: &'a ElemPool<T>) -> Iter<'a, T> {
let sentinel_slot = self.sentinel.slot as usize;
Iter {
pool,
front_slot: pool.next_slot(sentinel_slot).unwrap(),
back_slot: pool.prev_slot(sentinel_slot).unwrap(),
len: self.len,
_phantom: PhantomData,
}
}
pub fn iter_mut<'a>(&mut self, pool: &'a mut ElemPool<T>) -> IterMut<'a, T> {
let sentinel_slot = self.sentinel.slot as usize;
let front_slot = pool.next_slot(sentinel_slot).unwrap();
let back_slot = pool.prev_slot(sentinel_slot).unwrap();
IterMut {
pool,
front_slot,
back_slot,
len: self.len,
_phantom: PhantomData,
}
}
pub fn view<'a>(&'a self, pool: &'a ElemPool<T>) -> PieView<'a, T> {
PieView::new(self, pool)
}
pub fn view_mut<'a>(&'a mut self, pool: &'a mut ElemPool<T>) -> PieViewMut<'a, T> {
PieViewMut::new(self, pool)
}
pub fn cursor<'a>(&'a self, pool: &'a ElemPool<T>) -> Cursor<'a, T> {
let first_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
let first_elem = pool.index_from_slot(first_slot);
Cursor::new(self, first_elem, 0)
}
pub fn cursor_at<'a>(
&'a self,
index: usize,
pool: &'a ElemPool<T>,
) -> Result<Cursor<'a, T>, IndexError> {
if index >= self.len {
return Err(IndexError::IndexOutOfBounds);
}
let mut current_slot = self.sentinel.slot as usize;
if index < self.len / 2 {
for _ in 0..=index {
current_slot = pool.next_slot(current_slot).unwrap();
}
} else {
for _ in 0..(self.len - index) {
current_slot = pool.prev_slot(current_slot).unwrap();
}
}
let current_idx = pool.index_from_slot(current_slot);
Ok(Cursor::new(self, current_idx, index))
}
pub fn cursor_mut<'a>(&'a mut self, pool: &mut ElemPool<T>) -> CursorMut<'a, T> {
let first_slot = pool.next_slot(self.sentinel.slot as usize).unwrap();
let first_elem = pool.index_from_slot(first_slot);
CursorMut::new(self, first_elem, 0)
}
pub fn cursor_mut_at<'a>(
&'a mut self,
index: usize,
pool: &mut ElemPool<T>,
) -> Result<CursorMut<'a, T>, IndexError> {
if index >= self.len {
return Err(IndexError::IndexOutOfBounds);
}
let mut current_slot = self.sentinel.slot as usize;
if index < self.len / 2 {
for _ in 0..=index {
current_slot = pool.next_slot(current_slot).unwrap();
}
} else {
for _ in 0..(self.len - index) {
current_slot = pool.prev_slot(current_slot).unwrap();
}
}
let current_idx = pool.index_from_slot(current_slot);
Ok(CursorMut::new(self, current_idx, index))
}
pub fn remap(&mut self, map: &IndexMap<Index<T>, Index<T>>) {
if let Some(&new_index) = map.get(&self.sentinel) {
self.sentinel = new_index;
}
}
}
pub struct Iter<'a, T: 'a> {
pool: &'a ElemPool<T>,
front_slot: usize,
back_slot: usize,
len: usize,
_phantom: PhantomData<&'a T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.front_slot;
self.front_slot = self.pool.next_slot(current_slot).unwrap();
self.len -= 1;
self.pool.data_at(current_slot)
}
}
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.back_slot;
self.back_slot = self.pool.prev_slot(current_slot).unwrap();
self.len -= 1;
self.pool.data_at(current_slot)
}
}
impl<'a, T> ExactSizeIterator for Iter<'a, T> {
fn len(&self) -> usize {
self.len
}
}
impl<'a, T> FusedIterator for Iter<'a, T> {}
pub struct IterMut<'a, T: 'a> {
pool: &'a mut ElemPool<T>,
front_slot: usize,
back_slot: usize,
len: usize,
_phantom: PhantomData<&'a mut T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
#[inline]
#[allow(unsafe_code)]
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.front_slot;
self.front_slot = self.pool.next_slot(current_slot).unwrap();
self.len -= 1;
let pool_ptr = self.pool as *mut ElemPool<T>;
unsafe { (*pool_ptr).data_at_mut(current_slot) }
}
}
impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
#[inline]
#[allow(unsafe_code)]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.back_slot;
self.back_slot = self.pool.prev_slot(current_slot).unwrap();
self.len -= 1;
let pool_ptr = self.pool as *mut ElemPool<T>;
unsafe { (*pool_ptr).data_at_mut(current_slot) }
}
}
impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
fn len(&self) -> usize {
self.len
}
}
impl<'a, T> FusedIterator for IterMut<'a, T> {}
pub struct Drain<'a, T: 'a> {
pool: &'a mut ElemPool<T>,
front_slot: usize,
back_slot: usize,
len: usize,
_phantom: PhantomData<T>,
}
impl<'a, T> Iterator for Drain<'a, T> {
type Item = T;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.front_slot;
self.front_slot = self.pool.next_slot(current_slot).unwrap();
self.len -= 1;
let current_idx = self.pool.index_from_slot(current_slot);
let data = self.pool.data_swap(current_idx, None);
self.pool.index_del(current_idx).expect("valid node for deletion");
data
}
}
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if self.len == 0 {
return None;
}
let current_slot = self.back_slot;
self.back_slot = self.pool.prev_slot(current_slot).unwrap();
self.len -= 1;
let current_idx = self.pool.index_from_slot(current_slot);
let data = self.pool.data_swap(current_idx, None);
self.pool.index_del(current_idx).expect("valid node for deletion");
data
}
}
impl<'a, T> ExactSizeIterator for Drain<'a, T> {
fn len(&self) -> usize {
self.len
}
}
impl<'a, T> FusedIterator for Drain<'a, T> {}
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in self {}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pool::ElemPool;
#[test]
fn test_new_list() {
let mut pool = ElemPool::<i32>::new();
let list = PieList::new(&mut pool);
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert_eq!(pool.len(), 0);
assert_eq!(pool.capacity(), 1);
}
#[test]
fn test_push_and_pop() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back("A", &mut pool).unwrap();
list.push_front("B", &mut pool).unwrap(); list.push_back("C", &mut pool).unwrap();
assert_eq!(list.len(), 3);
assert_eq!(*list.front(&pool).unwrap(), "B");
assert_eq!(*list.back(&pool).unwrap(), "C");
assert_eq!(list.pop_front(&mut pool), Some("B")); assert_eq!(list.len(), 2);
assert_eq!(*list.front(&pool).unwrap(), "A");
assert_eq!(list.pop_back(&mut pool), Some("C")); assert_eq!(list.len(), 1);
assert_eq!(*list.front(&pool).unwrap(), "A");
assert_eq!(*list.back(&pool).unwrap(), "A");
assert_eq!(list.pop_front(&mut pool), Some("A"));
assert!(list.is_empty());
assert_eq!(list.pop_front(&mut pool), None);
assert_eq!(list.pop_back(&mut pool), None);
}
#[test]
fn test_clear() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(1, &mut pool).unwrap();
list.push_back(2, &mut pool).unwrap();
assert_eq!(list.len(), 2);
assert_eq!(pool.len(), 2);
list.clear(&mut pool);
assert!(list.is_empty());
assert_eq!(pool.len(), 0); }
#[test]
fn test_clear_debug() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(1, &mut pool).unwrap();
list.push_back(2, &mut pool).unwrap();
assert_eq!(list.len(), 2);
list.clear(&mut pool);
assert!(list.is_empty());
}
#[test]
fn test_front_back_mut() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(10, &mut pool).unwrap();
list.push_back(20, &mut pool).unwrap();
*list.front_mut(&mut pool).unwrap() = 15;
*list.back_mut(&mut pool).unwrap() = 25;
assert_eq!(list.pop_front(&mut pool), Some(15));
assert_eq!(list.pop_front(&mut pool), Some(25));
assert!(list.is_empty());
}
#[test]
fn test_iter() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(1, &mut pool).unwrap();
list.push_back(2, &mut pool).unwrap();
list.push_back(3, &mut pool).unwrap();
let mut iter = list.iter(&pool);
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next_back(), Some(&3));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
let vec: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(vec, vec![1, 2, 3]);
list.clear(&mut pool);
}
#[test]
fn test_iter_mut() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(10, &mut pool).unwrap();
list.push_back(20, &mut pool).unwrap();
for item in list.iter_mut(&mut pool) {
*item *= 2;
}
let vec: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(vec, vec![20, 40]);
list.clear(&mut pool);
}
#[test]
fn test_drain() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(1, &mut pool).unwrap();
list.push_back(2, &mut pool).unwrap();
list.push_back(3, &mut pool).unwrap();
assert_eq!(list.len(), 3);
assert_eq!(pool.len(), 3);
{
let mut drain = list.drain(&mut pool);
assert_eq!(drain.next(), Some(1));
assert_eq!(drain.next_back(), Some(3));
assert_eq!(drain.next(), Some(2));
assert_eq!(drain.next(), None);
assert_eq!(drain.next_back(), None);
}
assert!(list.is_empty());
assert_eq!(pool.len(), 0); }
#[test]
fn test_drain_drop() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(10, &mut pool).unwrap();
list.push_back(20, &mut pool).unwrap();
list.push_back(30, &mut pool).unwrap();
list.push_back(40, &mut pool).unwrap();
{
let mut drain = list.drain(&mut pool);
assert_eq!(drain.next(), Some(10));
}
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert_eq!(pool.len(), 0);
}
#[test]
fn test_multiple_lists_in_one_pool() {
let mut pool = ElemPool::new();
let mut list1 = PieList::new(&mut pool);
let mut list2 = PieList::new(&mut pool);
list1.push_back("a", &mut pool).unwrap();
list1.push_back("b", &mut pool).unwrap();
list2.push_back("x", &mut pool).unwrap();
list2.push_back("y", &mut pool).unwrap();
list2.push_back("z", &mut pool).unwrap();
assert_eq!(list1.len(), 2);
assert_eq!(list2.len(), 3);
assert_eq!(pool.len(), 5);
assert_eq!(list1.pop_front(&mut pool), Some("a"));
assert_eq!(list2.pop_front(&mut pool), Some("x"));
assert_eq!(pool.len(), 3);
list2.clear(&mut pool);
assert!(list2.is_empty());
assert_eq!(list1.len(), 1);
assert_eq!(pool.len(), 1);
list2.push_back("new", &mut pool).unwrap();
assert_eq!(list2.len(), 1);
assert_eq!(pool.len(), 2);
list1.clear(&mut pool);
list2.clear(&mut pool);
}
#[test]
fn test_sort() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.sort(&mut pool, |a: &i32, b| a.cmp(b));
assert!(list.is_empty());
list.push_back(10, &mut pool).unwrap();
list.sort(&mut pool, |a, b| a.cmp(b));
assert_eq!(*list.front(&pool).unwrap(), 10);
list.clear(&mut pool);
list.push_back(5, &mut pool).unwrap();
list.push_back(2, &mut pool).unwrap();
list.push_back(8, &mut pool).unwrap();
list.push_back(1, &mut pool).unwrap();
list.sort(&mut pool, |a, b| a.cmp(b));
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted, vec![1, 2, 5, 8]);
list.sort(&mut pool, |a, b| a.cmp(b));
let sorted2: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted2, vec![1, 2, 5, 8]);
list.sort(&mut pool, |a, b| b.cmp(a));
let sorted3: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted3, vec![8, 5, 2, 1]);
list.clear(&mut pool);
}
#[test]
fn test_sort_stability() {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct Item {
key: i32,
val: char,
}
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(Item { key: 2, val: 'a' }, &mut pool).unwrap();
list.push_back(Item { key: 1, val: 'b' }, &mut pool).unwrap();
list.push_back(Item { key: 2, val: 'c' }, &mut pool).unwrap();
list.push_back(Item { key: 0, val: 'd' }, &mut pool).unwrap();
list.push_back(Item { key: 1, val: 'e' }, &mut pool).unwrap();
list.sort(&mut pool, |a, b| a.key.cmp(&b.key));
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(
sorted,
vec![
Item { key: 0, val: 'd' },
Item { key: 1, val: 'b' },
Item { key: 1, val: 'e' }, Item { key: 2, val: 'a' },
Item { key: 2, val: 'c' }, ]
);
list.clear(&mut pool);
}
#[test]
fn test_sort_all_equal() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for _ in 0..8 {
list.push_back(42, &mut pool).unwrap();
}
list.sort(&mut pool, |a: &i32, b| a.cmp(b));
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted, vec![42; 8]);
assert_eq!(list.len(), 8);
list.clear(&mut pool);
}
#[test]
fn test_sort_large_list() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
let mut values: Vec<i32> = (0..200).rev().collect();
for &v in &values {
list.push_back(v, &mut pool).unwrap();
}
list.sort(&mut pool, |a, b| a.cmp(b));
values.sort();
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted, values);
assert_eq!(list.len(), 200);
list.clear(&mut pool);
}
#[test]
fn test_sort_no_pool_leak() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..150 {
list.push_back(v, &mut pool).unwrap();
}
let lists_before = pool.list_count();
let used_before = pool.len();
assert_eq!(lists_before, 1);
assert_eq!(used_before, 150);
list.sort(&mut pool, |a: &i32, b| b.cmp(a));
assert_eq!(pool.list_count(), 1, "sentinel leak: extra lists remain after sort");
assert_eq!(pool.len(), 150, "data element count changed after sort");
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted, (0..150).rev().collect::<Vec<_>>());
list.clear(&mut pool);
assert_eq!(pool.len(), 0);
assert_eq!(pool.list_count(), 1);
}
#[test]
fn test_sort_large_all_equal() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for _ in 0..128 {
list.push_back(7, &mut pool).unwrap();
}
list.sort(&mut pool, |a: &i32, b| a.cmp(b));
let sorted: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(sorted, vec![7; 128]);
assert_eq!(list.len(), 128);
assert_eq!(pool.list_count(), 1, "sentinel leak after equal-key sort");
list.clear(&mut pool);
}
#[test]
fn test_clear_large_list() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for i in 0..500 {
list.push_back(i, &mut pool).unwrap();
}
assert_eq!(pool.len(), 500);
assert_eq!(pool.list_count(), 1);
list.clear(&mut pool);
assert_eq!(pool.len(), 0);
assert_eq!(pool.free_len(), 500);
assert_eq!(pool.list_count(), 1);
for i in 0..500 {
list.push_back(i, &mut pool).unwrap();
}
let collected: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(collected, (0..500).collect::<Vec<_>>());
list.clear(&mut pool);
}
#[test]
fn test_sort_concurrent_lists_shared_pool() {
let mut pool = ElemPool::new();
let mut list_a = PieList::new(&mut pool);
let mut list_b = PieList::new(&mut pool);
for i in (0..100).rev() {
list_a.push_back(i, &mut pool).unwrap();
}
for i in (0..80).rev() {
list_b.push_back(i * 3, &mut pool).unwrap();
}
assert_eq!(pool.list_count(), 2);
assert_eq!(pool.len(), 180);
list_a.sort(&mut pool, |a, b| a.cmp(b));
assert_eq!(pool.list_count(), 2, "sentinel leak after sorting list_a");
assert_eq!(pool.len(), 180);
list_b.sort(&mut pool, |a, b| a.cmp(b));
assert_eq!(pool.list_count(), 2, "sentinel leak after sorting list_b");
assert_eq!(pool.len(), 180);
let a_sorted: Vec<_> = list_a.iter(&pool).copied().collect();
let b_sorted: Vec<_> = list_b.iter(&pool).copied().collect();
assert_eq!(a_sorted, (0..100).collect::<Vec<_>>());
let mut expected_b: Vec<i32> = (0..80).map(|i| i * 3).collect();
expected_b.sort();
assert_eq!(b_sorted, expected_b);
list_a.clear(&mut pool);
list_b.clear(&mut pool);
}
#[test]
fn test_sort_repeated_no_leak() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in (0..64).rev() {
list.push_back(v, &mut pool).unwrap();
}
for _ in 0..10 {
list.sort(&mut pool, |a: &i32, b| a.cmp(b));
assert_eq!(pool.list_count(), 1, "sentinel leak on repeated sort");
assert_eq!(pool.len(), 64);
list.sort(&mut pool, |a: &i32, b| b.cmp(a));
assert_eq!(pool.list_count(), 1);
}
list.clear(&mut pool);
}
#[test]
fn test_append() {
let mut pool = ElemPool::new();
let mut a = PieList::new(&mut pool);
let mut b = PieList::new(&mut pool);
for v in 0..5 {
a.push_back(v, &mut pool).unwrap();
}
for v in 5..10 {
b.push_back(v, &mut pool).unwrap();
}
a.append(&mut b, &mut pool).unwrap();
assert_eq!(a.len(), 10);
assert!(b.is_empty());
let items: Vec<_> = a.iter(&pool).copied().collect();
assert_eq!(items, (0..10).collect::<Vec<_>>());
a.append(&mut b, &mut pool).unwrap();
assert_eq!(a.len(), 10);
let mut c = PieList::new(&mut pool);
c.append(&mut a, &mut pool).unwrap();
assert_eq!(c.len(), 10);
assert!(a.is_empty());
a.clear(&mut pool);
b.clear(&mut pool);
c.clear(&mut pool);
}
#[test]
fn test_prepend() {
let mut pool = ElemPool::new();
let mut a = PieList::new(&mut pool);
let mut b = PieList::new(&mut pool);
for v in 5..10 {
a.push_back(v, &mut pool).unwrap();
}
for v in 0..5 {
b.push_back(v, &mut pool).unwrap();
}
a.prepend(&mut b, &mut pool).unwrap();
assert_eq!(a.len(), 10);
assert!(b.is_empty());
let items: Vec<_> = a.iter(&pool).copied().collect();
assert_eq!(items, (0..10).collect::<Vec<_>>());
a.prepend(&mut b, &mut pool).unwrap();
assert_eq!(a.len(), 10);
a.clear(&mut pool);
b.clear(&mut pool);
}
#[test]
fn test_retain_keep_even() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..10 {
list.push_back(v, &mut pool).unwrap();
}
list.retain(&mut pool, |x| x % 2 == 0);
let items: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(items, vec![0, 2, 4, 6, 8]);
assert_eq!(list.len(), 5);
assert_eq!(pool.len(), 5);
list.clear(&mut pool);
}
#[test]
fn test_retain_remove_all() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..5 {
list.push_back(v, &mut pool).unwrap();
}
list.retain(&mut pool, |_| false);
assert!(list.is_empty());
assert_eq!(pool.len(), 0);
list.clear(&mut pool);
}
#[test]
fn test_retain_keep_all() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..5 {
list.push_back(v, &mut pool).unwrap();
}
list.retain(&mut pool, |_| true);
assert_eq!(list.len(), 5);
let items: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(items, vec![0, 1, 2, 3, 4]);
list.clear(&mut pool);
}
#[test]
fn test_retain_empty_list() {
let mut pool = ElemPool::<i32>::new();
let mut list = PieList::new(&mut pool);
list.retain(&mut pool, |_| true);
assert!(list.is_empty());
list.clear(&mut pool);
}
#[test]
fn test_cursor_at_out_of_bounds() {
let mut pool = ElemPool::<i32>::new();
let mut list = PieList::new(&mut pool);
assert!(matches!(list.cursor_at(0, &pool), Err(crate::IndexError::IndexOutOfBounds)));
list.clear(&mut pool);
}
#[test]
fn test_cursor_at_out_of_bounds_nonempty() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(10, &mut pool).unwrap();
list.push_back(20, &mut pool).unwrap();
assert!(matches!(list.cursor_at(2, &pool), Err(crate::IndexError::IndexOutOfBounds)));
assert!(matches!(list.cursor_at(100, &pool), Err(crate::IndexError::IndexOutOfBounds)));
assert!(list.cursor_at(0, &pool).is_ok());
assert!(list.cursor_at(1, &pool).is_ok());
list.clear(&mut pool);
}
#[test]
fn test_cursor_mut_at_out_of_bounds() {
let mut pool = ElemPool::<i32>::new();
let mut list = PieList::new(&mut pool);
assert!(matches!(list.cursor_mut_at(0, &mut pool), Err(crate::IndexError::IndexOutOfBounds)));
list.clear(&mut pool);
}
#[test]
fn test_cursor_mut_at_out_of_bounds_nonempty() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..5 {
list.push_back(v, &mut pool).unwrap();
}
assert!(matches!(list.cursor_mut_at(5, &mut pool), Err(crate::IndexError::IndexOutOfBounds)));
assert!(matches!(list.cursor_mut_at(999, &mut pool), Err(crate::IndexError::IndexOutOfBounds)));
assert!(list.cursor_mut_at(0, &mut pool).is_ok());
assert!(list.cursor_mut_at(4, &mut pool).is_ok());
list.clear(&mut pool);
}
#[test]
fn test_iter_size_hint() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..5 {
list.push_back(v, &mut pool).unwrap();
}
let mut iter = list.iter(&pool);
assert_eq!(iter.size_hint(), (5, Some(5)));
assert_eq!(iter.len(), 5);
iter.next();
assert_eq!(iter.size_hint(), (4, Some(4)));
iter.next_back();
assert_eq!(iter.size_hint(), (3, Some(3)));
for _ in &mut iter {}
assert_eq!(iter.size_hint(), (0, Some(0)));
list.clear(&mut pool);
}
#[test]
fn test_iter_mut_size_hint() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..4 {
list.push_back(v, &mut pool).unwrap();
}
let mut iter = list.iter_mut(&mut pool);
assert_eq!(iter.size_hint(), (4, Some(4)));
iter.next();
assert_eq!(iter.size_hint(), (3, Some(3)));
iter.next_back();
assert_eq!(iter.size_hint(), (2, Some(2)));
list.clear(&mut pool);
}
#[test]
fn test_iter_double_ended() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 1..=6 {
list.push_back(v, &mut pool).unwrap();
}
let mut iter = list.iter(&pool);
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next_back(), Some(&6));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next_back(), Some(&5));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next_back(), Some(&4));
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
list.clear(&mut pool);
}
#[test]
fn test_iter_mut_double_ended() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 1..=4 {
list.push_back(v, &mut pool).unwrap();
}
{
let mut iter = list.iter_mut(&mut pool);
*iter.next().unwrap() = 10;
*iter.next_back().unwrap() = 40;
*iter.next().unwrap() = 20;
*iter.next_back().unwrap() = 30;
assert_eq!(iter.next(), None);
}
let items: Vec<_> = list.iter(&pool).copied().collect();
assert_eq!(items, vec![10, 20, 30, 40]);
list.clear(&mut pool);
}
#[test]
fn test_drain_size_hint() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 0..5 {
list.push_back(v, &mut pool).unwrap();
}
let mut drain = list.drain(&mut pool);
assert_eq!(drain.size_hint(), (5, Some(5)));
assert_eq!(drain.len(), 5);
drain.next();
assert_eq!(drain.size_hint(), (4, Some(4)));
drain.next_back();
assert_eq!(drain.size_hint(), (3, Some(3)));
}
#[test]
fn test_drain_double_ended() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
for v in 1..=4 {
list.push_back(v, &mut pool).unwrap();
}
let mut drain = list.drain(&mut pool);
assert_eq!(drain.next(), Some(1));
assert_eq!(drain.next_back(), Some(4));
assert_eq!(drain.next(), Some(2));
assert_eq!(drain.next_back(), Some(3));
assert_eq!(drain.next(), None);
assert_eq!(drain.next_back(), None);
}
#[test]
fn test_iter_fused() {
let mut pool = ElemPool::new();
let mut list = PieList::new(&mut pool);
list.push_back(1, &mut pool).unwrap();
let mut iter = list.iter(&pool);
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), None);
assert_eq!(iter.next(), None); list.clear(&mut pool);
}
}