use std::{fmt, marker::PhantomData, mem::ManuallyDrop};
use thiserror::Error;
#[allow(missing_docs)]
#[derive(Debug, Error)]
pub enum Error {
#[error(
"Cannot build JaggedVec: `ends` represents the end of each row in `data`, \
it should be monotonically increasing. \
Found `end` at position {i} lower than `end` at position {}", .i - 1
)]
BadEnd { i: usize },
#[error(
"Cannot build JaggedVec: `ends` represents the end of each row in `data`, \
Yet, `end` at position {i} ({end}) is larger than the length of data ({len})"
)]
TooLongEnd { i: usize, len: u32, end: u32 },
}
pub struct PoppedRow<'a, T> {
array: ManuallyDrop<Box<[T]>>,
lifetime: PhantomData<&'a ()>,
}
#[rustfmt::skip]
mod popped_row_impls {
use super::PoppedRow;
use std::ops::{Deref, DerefMut};
use std::ptr;
impl<'a, T> Deref for PoppedRow<'a, T> {
type Target = [T];
fn deref(&self) -> &Self::Target { self.as_ref() }
}
impl<'a, T> DerefMut for PoppedRow<'a, T> { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } }
impl<'a, T> AsRef<[T]> for PoppedRow<'a, T> { fn as_ref(&self) -> &[T] { self.array.as_ref() } }
impl<'a, T> AsMut<[T]> for PoppedRow<'a, T> { fn as_mut(&mut self) -> &mut [T] { self.array.as_mut() } }
impl<'a, T> Drop for PoppedRow<'a, T> {
fn drop(&mut self) {
let (ptr, len) = (self.array.as_mut_ptr(), self.array.len());
let slice = ptr::slice_from_raw_parts_mut(ptr, len);
unsafe { ptr::drop_in_place(slice) };
}
}
}
#[derive(PartialEq, Eq, Clone)]
pub struct JaggedVec<T> {
ends: Vec<u32>,
data: Vec<T>,
fully_popped: bool,
}
impl<T> Default for JaggedVec<T> {
fn default() -> Self {
Self::empty()
}
}
impl<T> JaggedVec<T> {
pub fn push_row(&mut self, row: impl IntoIterator<Item = T>) -> &mut Self {
if !self.fully_popped {
self.ends.push(self.data.len() as u32);
}
self.data.extend(row);
self.fully_popped = false;
self
}
pub fn push(&mut self, elem: T) {
self.fully_popped = false;
self.data.push(elem);
}
pub fn extend_last_row(&mut self, elems: impl IntoIterator<Item = T>) {
self.fully_popped = false;
self.data.extend(elems);
}
pub fn clear(&mut self) {
self.fully_popped = true;
self.data.clear();
self.ends.clear();
}
pub fn pop_row(&mut self) -> Option<PoppedRow<T>> {
if self.fully_popped {
return None;
}
self.fully_popped = self.ends.is_empty();
let last_end = self.ends.pop().unwrap_or(0) as usize;
let last_len = self.data.len();
let popped_len = last_len - last_end;
unsafe { self.data.set_len(last_end) };
let popped_row = unsafe {
let popped_ptr = self.data.as_mut_ptr().add(last_end);
Vec::from_raw_parts(popped_ptr, popped_len, popped_len)
};
Some(PoppedRow {
array: ManuallyDrop::new(popped_row.into_boxed_slice()),
lifetime: PhantomData,
})
}
#[must_use]
pub fn len(&self) -> usize {
self.data.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
#[must_use]
pub fn height(&self) -> usize {
if self.fully_popped {
0
} else {
self.ends.len() + 1
}
}
#[must_use]
pub const fn empty() -> Self {
Self {
data: Vec::new(),
ends: Vec::new(),
fully_popped: true,
}
}
pub fn new(ends: Vec<u32>, data: Vec<T>) -> Result<Self, Error> {
let mut previous_end = 0;
let last_end = data.len() as u32;
for (i, end) in ends.iter().enumerate() {
if *end > last_end {
return Err(Error::TooLongEnd { i, len: last_end, end: *end });
}
if *end < previous_end {
return Err(Error::BadEnd { i });
}
previous_end = *end;
}
Ok(Self { ends, data, fully_popped: false })
}
#[inline]
#[must_use]
pub fn row(&self, index: usize) -> &[T] {
self.get_row(index).unwrap()
}
#[inline]
#[must_use]
pub fn get_row(&self, index: usize) -> Option<&[T]> {
if index > self.ends.len() {
return None;
}
let get_end = |end: &u32| *end as usize;
let start = index.checked_sub(1).map_or(0, |i| self.ends[i]) as usize;
let end = self.ends.get(index).map_or(self.data.len(), get_end);
Some(unsafe { self.data.get_unchecked(start..end) })
}
#[inline]
#[must_use]
pub fn get(&self, direct_index: usize) -> Option<&T> {
self.data.get(direct_index)
}
#[must_use]
pub fn into_vecs(self) -> Vec<Vec<T>> {
let Self { ends, mut data, fully_popped } = self;
if fully_popped {
return Vec::new();
}
let mut iliffe = Vec::with_capacity(ends.len() + 1);
let mut last_end = 0;
for end in ends {
let size = (end - last_end) as usize;
iliffe.push(data.drain(..size).collect());
last_end = end;
}
iliffe.push(data);
iliffe
}
pub fn rows(&self) -> impl Iterator<Item = &[T]> {
(0..self.height()).map(|i| unsafe { self.get_row(i).unwrap_unchecked() })
}
}
impl<T: fmt::Debug> fmt::Debug for JaggedVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for row in self.rows() {
list.entry(&row);
}
list.finish()
}
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::atomic::{AtomicI64, Ordering};
struct RefCount<'a>(&'a AtomicI64);
impl<'a> RefCount<'a> {
fn new(atomic: &'a AtomicI64) -> Self {
atomic.fetch_add(1, Ordering::Relaxed);
Self(atomic)
}
}
impl Drop for RefCount<'_> {
fn drop(&mut self) {
self.0.fetch_sub(1, Ordering::Relaxed);
}
}
#[test]
fn count_drops() {
let count = AtomicI64::new(0);
let mk_ref = || RefCount::new(&count);
let mut jagged = JaggedVec::empty();
jagged
.push_row([mk_ref(), mk_ref()])
.push_row([mk_ref(), mk_ref(), mk_ref(), mk_ref()])
.push_row([mk_ref()]);
assert_eq!(count.load(Ordering::Relaxed), 7);
let popped = jagged.pop_row().unwrap();
assert_eq!(count.load(Ordering::Relaxed), 7);
drop(popped);
assert_eq!(count.load(Ordering::Relaxed), 6);
jagged.pop_row();
assert_eq!(count.load(Ordering::Relaxed), 2);
drop(jagged);
assert_eq!(count.load(Ordering::Relaxed), 0);
}
}