use crate::CACHE_LINE_SIZE;
use alloc::alloc::{alloc, dealloc, handle_alloc_error};
use core::alloc::Layout;
use core::mem::{MaybeUninit, align_of, needs_drop, size_of};
use core::ptr::{NonNull, null_mut};
pub struct SegList<T> {
tail: NonNull<SegHeader<T>>,
count: usize,
}
unsafe impl<T: Send> Send for SegList<T> {}
unsafe impl<T: Send> Sync for SegList<T> {}
impl<T> SegList<T> {
pub fn new() -> Self {
let mut seg = unsafe { Segment::<T>::alloc(null_mut(), null_mut(), true) };
let header_ptr = seg.header.as_ptr();
let header = seg.get_header_mut();
header.next = header_ptr;
Self { tail: seg.header, count: 0 }
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.count == 0
}
#[inline(always)]
pub const fn segment_cap() -> usize {
Segment::<T>::base_cap()
}
#[inline(always)]
pub fn len(&self) -> usize {
self.count
}
#[inline]
pub fn push(&mut self, item: T) {
unsafe {
let mut tail_seg = Segment::from_raw(self.tail);
if tail_seg.is_full() {
let tail_ptr = tail_seg.header.as_ptr();
let cur = tail_seg.get_header_mut();
let new_seg = Segment::alloc(tail_ptr, cur.next, false);
cur.next = new_seg.header.as_ptr();
self.tail = new_seg.header;
tail_seg = new_seg;
}
tail_seg.push(item);
}
self.count += 1;
}
#[inline]
pub fn pop(&mut self) -> Option<T> {
if self.count == 0 {
return None;
}
unsafe {
let mut tail_seg = Segment::from_raw(self.tail);
let (item, is_empty) = tail_seg.pop();
if is_empty {
let cur = tail_seg.get_header_mut();
let first_ptr = cur.next;
let cur_prev = cur.prev;
if self.tail.as_ptr() != first_ptr && !cur_prev.is_null() {
self.tail = NonNull::new_unchecked(cur_prev);
(*self.tail.as_ptr()).next = first_ptr;
tail_seg.dealloc();
}
}
self.count -= 1;
Some(item)
}
}
#[inline(always)]
fn break_first_node(&mut self) -> Segment<T> {
let tail_header = unsafe { self.tail.as_mut() };
let first = tail_header.next;
tail_header.next = null_mut();
unsafe { Segment::from_raw(NonNull::new_unchecked(first)) }
}
#[inline(always)]
fn first_ptr(&self) -> NonNull<SegHeader<T>> {
unsafe {
let tail_header = self.tail.as_ref();
let first = tail_header.next;
NonNull::new_unchecked(first)
}
}
#[inline]
pub fn iter(&self) -> SegListIter<'_, T> {
let first_seg = unsafe { Segment::from_raw(self.first_ptr()) };
SegListIter {
base: IterBase { cur: first_seg, cur_idx: 0, remaining: self.count, forward: true },
_marker: core::marker::PhantomData,
}
}
#[inline]
pub fn iter_rev(&self) -> SegListIter<'_, T> {
let tail_seg = unsafe { Segment::from_raw(self.tail) };
let tail_header = tail_seg.get_header();
let start_idx = if tail_header.count > 0 { tail_header.count as usize - 1 } else { 0 };
SegListIter {
base: IterBase {
cur: tail_seg,
cur_idx: start_idx,
remaining: self.count,
forward: false,
},
_marker: core::marker::PhantomData,
}
}
#[inline]
pub fn iter_mut(&mut self) -> SegListIterMut<'_, T> {
let first_seg = unsafe { Segment::from_raw(self.first_ptr()) };
SegListIterMut {
base: IterBase { cur: first_seg, cur_idx: 0, remaining: self.count, forward: true },
_marker: core::marker::PhantomData,
}
}
#[inline]
pub fn iter_mut_rev(&mut self) -> SegListIterMut<'_, T> {
let tail_seg = unsafe { Segment::from_raw(self.tail) };
let tail_header = tail_seg.get_header();
let start_idx = if tail_header.count > 0 { tail_header.count as usize - 1 } else { 0 };
SegListIterMut {
base: IterBase {
cur: tail_seg,
cur_idx: start_idx,
remaining: self.count,
forward: false,
},
_marker: core::marker::PhantomData,
}
}
pub fn drain(mut self) -> SegListDrain<T> {
let mut first = self.break_first_node();
let cur = if self.count == 0 {
unsafe {
first.dealloc();
}
None
} else {
Some(first)
};
core::mem::forget(self);
SegListDrain { cur, cur_idx: 0, forward: true }
}
pub fn into_rev(mut self) -> SegListDrain<T> {
let mut first = self.break_first_node();
let (cur, start_idx) = if self.count == 0 {
unsafe {
first.dealloc();
}
(None, 0)
} else {
let tail_seg = unsafe { Segment::from_raw(self.tail) };
let tail_header = tail_seg.get_header();
let start_idx = if tail_header.count > 0 { tail_header.count as usize - 1 } else { 0 };
(Some(tail_seg), start_idx)
};
core::mem::forget(self);
SegListDrain { cur, cur_idx: start_idx, forward: false }
}
#[inline]
pub fn first(&self) -> Option<&T> {
if self.count == 0 {
return None;
}
unsafe {
let first_seg = Segment::from_raw(self.first_ptr());
Some((*first_seg.item_ptr(0)).assume_init_ref())
}
}
#[inline]
pub fn first_mut(&self) -> Option<&T> {
if self.count == 0 {
return None;
}
unsafe {
let first_seg = Segment::from_raw(self.first_ptr());
Some((*first_seg.item_ptr(0)).assume_init_mut())
}
}
#[inline]
pub fn last(&self) -> Option<&T> {
unsafe {
let tail_seg = Segment::from_raw(self.tail);
let header = tail_seg.get_header();
if header.count == 0 {
return None;
}
let idx = (header.count - 1) as usize;
Some((*tail_seg.item_ptr(idx)).assume_init_ref())
}
}
#[inline]
pub fn last_mut(&mut self) -> Option<&mut T> {
unsafe {
let tail_seg = Segment::from_raw(self.tail);
let header = tail_seg.get_header();
if header.count == 0 {
return None;
}
let idx = (header.count - 1) as usize;
Some((*tail_seg.item_ptr(idx)).assume_init_mut())
}
}
#[inline(always)]
pub fn clear(&mut self) {
if self.count == 0 {
return;
}
unsafe {
let tail_header = self.tail.as_mut();
let first = tail_header.next;
let mut cur = Segment::from_raw(self.tail);
loop {
let next = cur.get_header().prev;
if next.is_null() {
if needs_drop::<T>() {
cur.drop_items();
}
self.count = 0;
let header = cur.get_header_mut();
header.count = 0;
header.next = first;
self.tail = NonNull::new_unchecked(first);
return;
} else {
cur.dealloc_with_items();
cur = Segment::from_raw(NonNull::new_unchecked(next));
}
}
}
}
}
impl<T> Default for SegList<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Drop for SegList<T> {
fn drop(&mut self) {
let mut cur = self.break_first_node();
loop {
let next = cur.get_header().next;
unsafe { cur.dealloc_with_items() };
if next.is_null() {
break;
}
cur = unsafe { Segment::from_raw(NonNull::new_unchecked(next)) };
}
}
}
impl<T> IntoIterator for SegList<T> {
type Item = T;
type IntoIter = SegListDrain<T>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.drain()
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for SegList<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("SegList").field("len", &self.len()).finish()
}
}
#[repr(C)]
struct SegHeader<T> {
count: u32,
cap: u32,
prev: *mut SegHeader<T>,
next: *mut SegHeader<T>,
_marker: core::marker::PhantomData<T>,
}
struct Segment<T> {
header: NonNull<SegHeader<T>>,
}
impl<T> Segment<T> {
const DATA_OFFSET: usize = Self::calc_data_offset();
const BASE_LAYOUT: (usize, Layout) = Self::calc_layout_const(CACHE_LINE_SIZE * 2);
const LARGE_LAYOUT: (usize, Layout) = Self::calc_layout_const(CACHE_LINE_SIZE * 4);
const fn calc_data_offset() -> usize {
let mut data_offset = size_of::<SegHeader<T>>();
let t_size = size_of::<T>();
let t_align = align_of::<MaybeUninit<T>>();
if t_size != 0 {
data_offset = (data_offset + t_align - 1) & !(t_align - 1);
}
data_offset
}
const fn calc_layout_const(cache_line: usize) -> (usize, Layout) {
let t_size = size_of::<T>();
let data_offset = Self::DATA_OFFSET;
let capacity;
let final_alloc_size;
let final_align;
if t_size == 0 {
capacity = 1024;
final_alloc_size = cache_line;
final_align = cache_line;
} else {
let min_elements = 2;
let min_required_size = data_offset + (t_size * min_elements);
let alloc_size = (min_required_size + cache_line - 1) & !(cache_line - 1);
final_align = if cache_line > align_of::<MaybeUninit<T>>() {
cache_line
} else {
align_of::<MaybeUninit<T>>()
};
final_alloc_size = (alloc_size + final_align - 1) & !(final_align - 1);
capacity = (final_alloc_size - data_offset) / t_size;
assert!(capacity >= min_elements);
}
match Layout::from_size_align(final_alloc_size, final_align) {
Ok(l) => (capacity, l),
Err(_) => panic!("Invalid layout"),
}
}
#[inline(always)]
const fn base_cap() -> usize {
Self::BASE_LAYOUT.0
}
#[inline(always)]
const fn large_cap() -> usize {
Self::LARGE_LAYOUT.0
}
#[inline(always)]
const fn data_offset() -> usize {
Self::DATA_OFFSET
}
#[inline]
unsafe fn alloc(prev: *mut SegHeader<T>, next: *mut SegHeader<T>, is_first: bool) -> Self {
let (cap, layout) = if is_first {
(Self::base_cap() as u32, Self::BASE_LAYOUT.1)
} else {
(Self::large_cap() as u32, Self::LARGE_LAYOUT.1)
};
let ptr: *mut u8 = unsafe { alloc(layout) };
if ptr.is_null() {
handle_alloc_error(layout);
}
unsafe {
let p = NonNull::new_unchecked(ptr as *mut SegHeader<T>);
let header = p.as_ptr();
(*header).count = 0;
(*header).cap = cap;
(*header).prev = prev;
(*header).next = next;
Self::from_raw(p)
}
}
#[inline(always)]
unsafe fn drop_items(&self) {
unsafe {
for i in 0..self.len() {
(*self.item_ptr(i)).assume_init_drop();
}
}
}
#[inline(always)]
unsafe fn dealloc_with_items(&mut self) {
unsafe {
if needs_drop::<T>() {
self.drop_items();
}
self.dealloc();
}
}
#[inline(always)]
unsafe fn dealloc(&mut self) {
unsafe {
let cap = (*self.header.as_ptr()).cap as usize;
let layout =
if cap == Self::base_cap() { Self::BASE_LAYOUT.1 } else { Self::LARGE_LAYOUT.1 };
dealloc(self.header.as_ptr() as *mut u8, layout);
}
}
#[inline(always)]
unsafe fn from_raw(header: NonNull<SegHeader<T>>) -> Self {
Self { header }
}
#[inline(always)]
fn len(&self) -> usize {
unsafe { (*self.header.as_ptr()).count as usize }
}
#[inline(always)]
fn get_header(&self) -> &SegHeader<T> {
unsafe { self.header.as_ref() }
}
#[inline(always)]
fn get_header_mut(&mut self) -> &mut SegHeader<T> {
unsafe { self.header.as_mut() }
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
fn is_full(&self) -> bool {
let header = self.get_header();
header.count >= header.cap
}
#[inline]
fn item_ptr(&self, index: usize) -> *mut MaybeUninit<T> {
unsafe {
let items =
(self.header.as_ptr() as *mut u8).add(Self::data_offset()) as *mut MaybeUninit<T>;
items.add(index)
}
}
#[inline]
fn push(&mut self, item: T) {
debug_assert!(!self.is_full());
let idx = self.get_header().count as usize;
unsafe {
(*self.item_ptr(idx)).write(item);
}
self.get_header_mut().count = (idx + 1) as u32;
}
#[inline]
fn pop(&mut self) -> (T, bool) {
debug_assert!(!self.is_empty());
let idx = self.get_header().count - 1;
let item = unsafe { (*self.item_ptr(idx as usize)).assume_init_read() };
self.get_header_mut().count = idx;
(item, idx == 0)
}
}
struct IterBase<T> {
cur: Segment<T>,
cur_idx: usize,
remaining: usize,
forward: bool,
}
impl<T> IterBase<T> {
#[inline]
fn next(&mut self) -> Option<*mut MaybeUninit<T>> {
if self.remaining == 0 {
return None;
}
self.remaining -= 1;
if self.forward {
let cur_header = self.cur.get_header();
let idx = if self.cur_idx >= cur_header.count as usize {
let next = cur_header.next;
self.cur = unsafe { Segment::from_raw(NonNull::new_unchecked(next)) };
self.cur_idx = 1;
0
} else {
let _idx = self.cur_idx;
self.cur_idx = _idx + 1;
_idx
};
Some(self.cur.item_ptr(idx))
} else {
let idx = self.cur_idx;
let item_ptr = self.cur.item_ptr(idx);
if self.cur_idx == 0 {
let cur_header = self.cur.get_header();
if !cur_header.prev.is_null() {
self.cur =
unsafe { Segment::from_raw(NonNull::new_unchecked(cur_header.prev)) };
let prev_header = self.cur.get_header();
self.cur_idx = prev_header.count as usize - 1;
}
} else {
self.cur_idx -= 1;
}
Some(item_ptr)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
pub struct SegListIter<'a, T> {
base: IterBase<T>,
_marker: core::marker::PhantomData<&'a T>,
}
impl<'a, T> Iterator for SegListIter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.base.next().map(|ptr| unsafe { (*ptr).assume_init_ref() })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.base.size_hint()
}
}
impl<'a, T> ExactSizeIterator for SegListIter<'a, T> {}
pub struct SegListIterMut<'a, T> {
base: IterBase<T>,
_marker: core::marker::PhantomData<&'a mut T>,
}
impl<'a, T> Iterator for SegListIterMut<'a, T> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.base.next().map(|ptr| unsafe { (*ptr).assume_init_mut() })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.base.size_hint()
}
}
impl<'a, T> ExactSizeIterator for SegListIterMut<'a, T> {}
pub struct SegListDrain<T> {
cur: Option<Segment<T>>,
cur_idx: usize,
forward: bool,
}
impl<T> Iterator for SegListDrain<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let cur_seg = self.cur.as_mut()?;
unsafe {
let item = (*cur_seg.item_ptr(self.cur_idx)).assume_init_read();
let header = cur_seg.get_header();
if self.forward {
let next_idx = self.cur_idx + 1;
if next_idx >= header.count as usize {
let next = header.next;
cur_seg.dealloc();
if next.is_null() {
self.cur = None;
} else {
self.cur = Some(Segment::from_raw(NonNull::new_unchecked(next)));
self.cur_idx = 0;
}
} else {
self.cur_idx = next_idx;
}
} else if self.cur_idx == 0 {
let prev = header.prev;
cur_seg.dealloc();
if prev.is_null() {
self.cur = None;
} else {
let _cur = Segment::from_raw(NonNull::new_unchecked(prev));
self.cur_idx = _cur.get_header().count as usize - 1;
self.cur = Some(_cur);
}
} else {
self.cur_idx -= 1;
}
Some(item)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = if let Some(_cur) = &self.cur {
1 } else {
0
};
(remaining, None)
}
}
impl<T> Drop for SegListDrain<T> {
fn drop(&mut self) {
if let Some(mut cur) = self.cur.take() {
unsafe {
if self.forward {
let header = cur.get_header();
let mut next = header.next;
if needs_drop::<T>() {
for i in self.cur_idx..header.count as usize {
(*cur.item_ptr(i)).assume_init_drop();
}
}
cur.dealloc();
while !next.is_null() {
cur = Segment::from_raw(NonNull::new_unchecked(next));
next = cur.get_header().next;
cur.dealloc_with_items();
}
} else {
let mut prev = cur.get_header().prev;
if needs_drop::<T>() {
for i in 0..=self.cur_idx {
(*cur.item_ptr(i)).assume_init_drop();
}
}
cur.dealloc();
while !prev.is_null() {
cur = Segment::from_raw(NonNull::new_unchecked(prev));
prev = cur.get_header().prev;
cur.dealloc_with_items();
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::{CounterI32, alive_count, reset_alive_count};
#[test]
fn test_multiple_segments() {
let mut list: SegList<i32> = SegList::new();
if CACHE_LINE_SIZE == 128 {
assert_eq!(Segment::<i32>::base_cap(), 26);
}
for i in 0..100 {
list.push(i);
}
assert_eq!(list.len(), 100);
for i in (0..100).rev() {
assert_eq!(list.pop(), Some(i));
}
assert_eq!(list.pop(), None);
}
#[test]
fn test_iter_single_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..10 {
list.push(i);
}
assert_eq!(list.first(), Some(&0));
assert_eq!(list.last(), Some(&9));
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
for item in list.iter_mut() {
*item *= 2;
}
assert_eq!(list.first(), Some(&0));
assert_eq!(list.last(), Some(&18));
let collected: Vec<i32> = list.iter().copied().collect();
assert_eq!(collected, vec![0, 2, 4, 6, 8, 10, 12, 14, 16, 18]);
for i in (0..10).rev() {
assert_eq!(list.pop(), Some(i * 2));
}
assert_eq!(list.pop(), None);
assert!(list.is_empty());
}
#[test]
fn test_iter_multi_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..200 {
list.push(i * 10);
}
assert_eq!(list.first(), Some(&0));
assert_eq!(list.last(), Some(&1990));
let collected: Vec<i32> = list.iter().copied().collect();
let expected: Vec<i32> = (0..200).map(|i| i * 10).collect();
assert_eq!(collected, expected);
for item in list.iter_mut() {
*item += 1;
}
assert_eq!(list.first(), Some(&1));
assert_eq!(list.last(), Some(&1991));
let collected: Vec<i32> = list.iter().copied().collect();
let expected: Vec<i32> = (0..200).map(|i| i * 10 + 1).collect();
assert_eq!(collected, expected);
for i in (0..200).rev() {
assert_eq!(list.pop(), Some(i * 10 + 1));
}
assert_eq!(list.pop(), None);
assert!(list.is_empty());
}
#[test]
fn test_drain() {
let cap = Segment::<CounterI32>::base_cap();
{
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
for i in 0..5 {
list.push(CounterI32::new(i));
}
assert!(list.len() < cap);
let drained: Vec<i32> = list.drain().map(|d| *d).collect();
assert_eq!(drained, vec![0, 1, 2, 3, 4]);
}
assert_eq!(alive_count(), 0);
}
{
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let total = cap * 2 + 5;
for i in 0..total {
list.push(CounterI32::new(i as i32));
}
assert_eq!(alive_count(), cap * 2 + 5);
let drain_count = cap / 2;
let mut drain_iter = list.drain();
for i in 0..drain_count {
assert_eq!(*drain_iter.next().unwrap(), i as i32);
}
drop(drain_iter);
}
assert_eq!(alive_count(), 0);
}
{
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let total = cap * 2 + 3;
for i in 0..total {
list.push(CounterI32::new(i as i32));
}
assert_eq!(alive_count(), cap * 2 + 3);
let mut drain_iter = list.drain();
for i in 0..cap {
assert_eq!(*drain_iter.next().unwrap(), i as i32);
}
drop(drain_iter);
}
assert_eq!(alive_count(), 0);
}
}
#[test]
fn test_drop_single_segment() {
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let cap = Segment::<CounterI32>::base_cap();
for i in 0..5 {
list.push(CounterI32::new(i));
}
assert!(list.len() < cap);
assert_eq!(alive_count(), 5);
}
assert_eq!(alive_count(), 0);
}
#[test]
fn test_drop_multi_segment() {
let cap = Segment::<CounterI32>::base_cap();
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let total = cap * 2 + 10;
for i in 0..total {
list.push(CounterI32::new(i as i32));
}
assert_eq!(alive_count(), cap * 2 + 10);
}
assert_eq!(alive_count(), 0);
}
#[test]
fn test_clear_1_segment() {
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let base_cap = Segment::<CounterI32>::base_cap();
for i in 0..base_cap as i32 {
list.push(CounterI32::new(i));
}
assert_eq!(alive_count(), base_cap);
list.clear();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert!(list.pop().is_none());
}
assert_eq!(alive_count(), 0);
}
#[test]
fn test_clear_2_segment() {
reset_alive_count();
{
let mut list: SegList<CounterI32> = SegList::new();
let count = Segment::<CounterI32>::base_cap() + Segment::<CounterI32>::large_cap();
for i in 0..count as i32 {
list.push(CounterI32::new(i));
}
assert_eq!(alive_count(), count);
list.clear();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert!(list.pop().is_none());
}
assert_eq!(alive_count(), 0);
}
#[test]
fn test_clear_3_segment() {
reset_alive_count();
let mut list: SegList<CounterI32> = SegList::new();
let count = Segment::<CounterI32>::base_cap() + Segment::<CounterI32>::large_cap() * 2;
for i in 0..count as i32 {
list.push(CounterI32::new(i));
}
assert_eq!(alive_count(), count);
list.clear();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert!(list.pop().is_none());
assert_eq!(alive_count(), 0);
}
#[derive(Debug, Clone, Copy, PartialEq)]
struct LargeStruct {
data: [u64; 16], }
impl LargeStruct {
fn new(val: u64) -> Self {
Self { data: [val; 16] }
}
}
#[test]
fn test_size() {
assert_eq!(size_of::<SegHeader::<LargeStruct>>(), 24);
let data_offset = Segment::<LargeStruct>::data_offset();
let base_cap = Segment::<LargeStruct>::base_cap();
let large_cap = Segment::<LargeStruct>::large_cap();
let base_layout = Segment::<LargeStruct>::BASE_LAYOUT.1;
let large_layout = Segment::<LargeStruct>::LARGE_LAYOUT.1;
println!(
"LargeStruct: offset={}, base(cap={} size={} align={}), large(cap={} size={} align={})",
data_offset,
base_cap,
base_layout.size(),
base_layout.align(),
large_cap,
large_layout.size(),
large_layout.align()
);
let data_offset = Segment::<u64>::data_offset();
let base_cap = Segment::<u64>::base_cap();
let large_cap = Segment::<u64>::large_cap();
let base_layout = Segment::<u64>::BASE_LAYOUT.1;
let large_layout = Segment::<u64>::LARGE_LAYOUT.1;
println!(
"u64: offset={}, base(cap={} size={} align={}), large(cap={} size={} align={})",
data_offset,
base_cap,
base_layout.size(),
base_layout.align(),
large_cap,
large_layout.size(),
large_layout.align()
);
let data_offset = Segment::<u32>::data_offset();
let base_cap = Segment::<u32>::base_cap();
let large_cap = Segment::<u32>::large_cap();
let base_layout = Segment::<u32>::BASE_LAYOUT.1;
let large_layout = Segment::<u32>::LARGE_LAYOUT.1;
println!(
"u32: offset={}, base(cap={} size={} align={}), large(cap={} size={} align={})",
data_offset,
base_cap,
base_layout.size(),
base_layout.align(),
large_cap,
large_layout.size(),
large_layout.align()
);
let data_offset = Segment::<u16>::data_offset();
let base_cap = Segment::<u16>::base_cap();
let large_cap = Segment::<u16>::large_cap();
let base_layout = Segment::<u16>::BASE_LAYOUT.1;
let large_layout = Segment::<u16>::LARGE_LAYOUT.1;
println!(
"u16: offset={}, base(cap={} size={} align={}), large(cap={} size={} align={})",
data_offset,
base_cap,
base_layout.size(),
base_layout.align(),
large_cap,
large_layout.size(),
large_layout.align()
);
}
#[test]
fn test_large_type_push_pop() {
let mut list: SegList<LargeStruct> = SegList::new();
for i in 0..50 {
list.push(LargeStruct::new(i));
}
assert_eq!(list.len(), 50);
for i in (0..50).rev() {
let val = list.pop().unwrap();
assert_eq!(val.data[0], i);
assert_eq!(val.data[7], i);
}
assert!(list.is_empty());
assert_eq!(list.pop(), None);
}
#[test]
fn test_large_type_iter() {
let mut list: SegList<LargeStruct> = SegList::new();
for i in 0..30 {
list.push(LargeStruct::new(i * 10));
}
let collected: Vec<u64> = list.iter().map(|s| s.data[0]).collect();
let expected: Vec<u64> = (0..30).map(|i| i * 10).collect();
assert_eq!(collected, expected);
}
#[test]
fn test_large_type_iter_mut() {
let mut list: SegList<LargeStruct> = SegList::new();
for i in 0..20 {
list.push(LargeStruct::new(i));
}
for item in list.iter_mut() {
item.data[0] *= 2;
}
let collected: Vec<u64> = list.iter().map(|s| s.data[0]).collect();
let expected: Vec<u64> = (0..20).map(|i| i * 2).collect();
assert_eq!(collected, expected);
}
#[test]
fn test_large_type_drain() {
let mut list: SegList<LargeStruct> = SegList::new();
for i in 0..40 {
list.push(LargeStruct::new(i));
}
let drained: Vec<u64> = list.drain().map(|s| s.data[0]).collect();
let expected: Vec<u64> = (0..40).collect();
assert_eq!(drained, expected);
}
#[test]
fn test_large_type_clear() {
let mut list: SegList<LargeStruct> = SegList::new();
for i in 0..60 {
list.push(LargeStruct::new(i));
}
assert_eq!(list.len(), 60);
list.clear();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
assert_eq!(list.pop(), None);
}
#[test]
fn test_iter_rev_single_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..10 {
list.push(i);
}
let collected: Vec<i32> = list.iter_rev().copied().collect();
let expected: Vec<i32> = (0..10).rev().collect();
assert_eq!(collected, expected);
for item in list.iter_mut_rev() {
*item *= 10;
}
assert_eq!(list.first(), Some(&0));
assert_eq!(list.last(), Some(&90));
let collected: Vec<i32> = list.iter().copied().collect();
let expected: Vec<i32> = vec![0, 10, 20, 30, 40, 50, 60, 70, 80, 90];
assert_eq!(collected, expected);
}
#[test]
fn test_iter_rev_multi_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..200 {
list.push(i);
}
let collected: Vec<i32> = list.iter_rev().copied().collect();
let expected: Vec<i32> = (0..200).rev().collect();
assert_eq!(collected, expected);
for item in list.iter_mut_rev() {
*item += 1000;
}
assert_eq!(list.first(), Some(&1000));
assert_eq!(list.last(), Some(&1199));
let collected: Vec<i32> = list.iter().copied().collect();
let expected: Vec<i32> = (0..200).map(|i| i + 1000).collect();
assert_eq!(collected, expected);
}
#[test]
fn test_iter_rev_empty() {
let list: SegList<i32> = SegList::new();
let collected: Vec<i32> = list.iter_rev().copied().collect();
assert!(collected.is_empty());
let mut list_mut: SegList<i32> = SegList::new();
let count = list_mut.iter_mut_rev().count();
assert_eq!(count, 0);
}
#[test]
fn test_iter_rev_exact_size() {
let mut list: SegList<i32> = SegList::new();
for i in 0..50 {
list.push(i);
}
let iter = list.iter_rev();
assert_eq!(iter.len(), 50);
let mut iter = list.iter_rev();
assert_eq!(iter.len(), 50);
iter.next();
assert_eq!(iter.len(), 49);
iter.next();
assert_eq!(iter.len(), 48);
let mut iter_mut = list.iter_mut_rev();
assert_eq!(iter_mut.len(), 50);
iter_mut.next();
assert_eq!(iter_mut.len(), 49);
}
#[test]
fn test_into_rev_single_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..10 {
list.push(i);
}
let drained: Vec<i32> = list.into_rev().collect();
let expected: Vec<i32> = (0..10).rev().collect();
assert_eq!(drained, expected);
}
#[test]
fn test_into_rev_multi_segment() {
let mut list: SegList<i32> = SegList::new();
for i in 0..200 {
list.push(i);
}
let drained: Vec<i32> = list.into_rev().collect();
let expected: Vec<i32> = (0..200).rev().collect();
assert_eq!(drained, expected);
}
#[test]
fn test_into_rev_empty() {
let list: SegList<i32> = SegList::new();
let drained: Vec<i32> = list.into_rev().collect();
assert!(drained.is_empty());
}
#[test]
fn test_into_rev_partial() {
let mut list: SegList<i32> = SegList::new();
for i in 0..50 {
list.push(i);
}
let mut drain = list.into_rev();
let mut drained = Vec::new();
for _ in 0..25 {
if let Some(item) = drain.next() {
drained.push(item);
}
}
drop(drain);
let expected: Vec<i32> = (25..50).rev().collect();
assert_eq!(drained, expected);
}
}