use std::{
alloc::Layout,
collections::HashMap,
iter::FromIterator,
mem::{self, MaybeUninit},
ops::{Index, IndexMut},
ptr::{self, NonNull},
slice,
};
use bitvec::vec::BitVec;
use num_traits::{AsPrimitive, PrimInt};
#[macro_export]
macro_rules! stablevec {
() => {
$crate::vec::StableVec::new()
};
($elem:expr; $n:expr) => {
unsafe {
$crate::vec::StableVec::from_parts(
Vec::from_elem($elem, $n),
bitvec::vec::BitVec::repeat(true, $n),
)
}
};
($($x:expr),+ $(,)?) => {
unsafe{
let data = Box::new([$(std::mem::MaybeUninit::new($x)),+]);
let cap = data.len();
$crate::vec::StableVec::from_parts(
std::ptr::NonNull::new_unchecked(Box::leak(data) as *mut _),
bitvec::vec::BitVec::repeat(true, cap),
cap,
cap,
Some(cap)
)
}
}
}
#[derive(Debug)]
pub struct StableVec<T> {
data: NonNull<MaybeUninit<T>>,
flags: BitVec,
cap: usize,
init_amt: usize,
farthest_init: Option<usize>,
}
impl<T> Default for StableVec<T> {
fn default() -> Self {
Self {
data: NonNull::dangling(),
flags: BitVec::new(),
cap: 0,
init_amt: 0,
farthest_init: None,
}
}
}
impl<T: Copy> Clone for StableVec<T> {
fn clone(&self) -> Self {
let (cap, data) = match self.flags.last_one() {
Some(l) => unsafe {
let cap = l + 1;
if std::mem::size_of::<T>() == 0 {
(cap, NonNull::dangling())
} else {
let p = Self::alloc(cap);
ptr::copy_nonoverlapping(self.data.as_ptr(), p.as_ptr(), cap);
(cap, p)
}
},
None => (0, NonNull::dangling()),
};
Self {
data,
flags: BitVec::from_bitslice(&self.flags[0..cap + 1]),
cap,
init_amt: self.init_amt,
farthest_init: self.farthest_init,
}
}
}
impl<T> StableVec<T> {
pub unsafe fn from_parts(
data: NonNull<MaybeUninit<T>>,
flags: BitVec,
cap: usize,
init_amt: usize,
farthest_init: Option<usize>,
) -> Self {
Self {
data,
flags,
cap,
init_amt,
farthest_init,
}
}
pub fn new() -> Self {
Self {
data: NonNull::dangling(),
flags: BitVec::default(),
cap: 0,
init_amt: 0,
farthest_init: None,
}
}
pub fn farthest_init_index(&self) -> Option<usize> {
self.farthest_init
}
pub fn with_capacity(cap: usize) -> Self {
let mut res = Self::new();
unsafe {
res.realloc_unchecked(cap);
}
res
}
pub fn spare_slots(&self) -> usize {
self.flags.len() - self.init_amt
}
pub fn spare_capacity(&self) -> usize {
self.cap - self.init_amt
}
pub fn len_init(&self) -> usize {
self.init_amt
}
pub unsafe fn get_raw_unsafe(&self, index: usize) -> &MaybeUninit<T> {
debug_assert!(index < self.cap);
&*self.data.as_ptr().add(index)
}
pub unsafe fn get_raw_unsafe_mut(&mut self, index: usize) -> &mut MaybeUninit<T> {
debug_assert!(index < self.cap);
&mut *self.data.as_ptr().add(index)
}
pub unsafe fn get_unsafe(&self, index: usize) -> &T {
debug_assert!(self.is_init(index));
self.get_raw_unsafe(index).assume_init_ref()
}
pub unsafe fn get_unsafe_mut(&mut self, index: usize) -> &mut T {
debug_assert!(self.is_init(index));
self.get_raw_unsafe_mut(index).assume_init_mut()
}
pub fn get_unchecked(&self, index: usize) -> &T {
debug_assert!(self.is_init(index));
if !self.flags[index] {
panic!("attempted to access uninitialized value in StableVec")
}
unsafe { self.get_unsafe(index) }
}
pub fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
debug_assert!(self.is_init(index));
if !self.flags[index] {
panic!("attempted to access uninitialized value in StableVec")
}
unsafe { self.get_unsafe_mut(index) }
}
pub fn get(&self, index: usize) -> Option<&T> {
match self.flags.get(index).as_deref() {
None | Some(false) => None,
Some(true) => Some(unsafe { self.get_unsafe(index) }),
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
match self.flags.get(index).map(|b| *b) {
None | Some(false) => None,
Some(true) => Some(unsafe { self.get_unsafe_mut(index) }),
}
}
pub fn clear(&mut self) {
unsafe {
let p = self.data.as_ptr();
for i in self.flags.iter_ones() {
ptr::drop_in_place::<T>(&mut *p.add(i).cast::<T>());
}
}
self.init_amt = 0;
self.farthest_init = None;
self.flags.clear();
}
pub fn dealloc(&mut self) {
if self.cap == 0 {
return;
}
self.clear();
self.cap = 0;
self.flags.shrink_to_fit();
unsafe {
std::alloc::dealloc(
self.data.as_ptr() as *mut u8,
Layout::array::<MaybeUninit<T>>(self.cap).unwrap(),
)
};
}
unsafe fn alloc(cap: usize) -> NonNull<MaybeUninit<T>> {
if mem::size_of::<T>() == 0 || cap == 0 {
return NonNull::dangling();
}
NonNull::new_unchecked(
std::alloc::alloc(Layout::array::<MaybeUninit<T>>(cap).unwrap()) as *mut MaybeUninit<T>,
)
}
unsafe fn realloc_unchecked(&mut self, new_cap: usize) {
debug_assert!(new_cap >= self.flags.len());
if mem::size_of::<T>() == 0 {
self.cap = new_cap;
return;
}
let new_data = Self::alloc(new_cap);
if self.cap > 0 {
ptr::copy_nonoverlapping(self.data.as_ptr(), new_data.as_ptr(), new_cap);
std::alloc::dealloc(
self.data.as_ptr() as *mut u8,
Layout::array::<MaybeUninit<T>>(self.cap).unwrap(),
);
}
self.cap = new_cap;
self.data = new_data;
}
fn realloc_exact(&mut self, new_cap: usize) {
if new_cap < self.flags.len() {
panic!()
}
if mem::size_of::<T>() == 0 {
self.cap = new_cap;
return;
}
if self.cap == new_cap {
return;
}
unsafe { self.realloc_unchecked(new_cap) };
}
fn realloc_at_least(&mut self, new_cap: usize) {
if new_cap < self.flags.len() {
panic!()
}
if mem::size_of::<T>() == 0 {
self.cap = self.cap.max(new_cap);
return;
}
if self.cap >= new_cap {
return;
}
unsafe { self.realloc_unchecked(new_cap) };
}
pub fn shrink_to_fit(&mut self) {
if self.cap == 0 || self.cap == self.init_amt {
return;
}
if self.init_amt == 0 {
self.dealloc();
return;
}
unsafe { self.realloc_unchecked(self.flags.iter_ones().last().unwrap() + 1) };
self.flags.truncate(self.cap);
self.flags.shrink_to_fit();
}
pub fn from_vec(data: Vec<T>) -> Self {
let cap = data.capacity();
let len = data.len();
Self {
data: unsafe {
NonNull::new_unchecked(data.leak().as_mut_ptr() as *mut MaybeUninit<T>)
},
flags: BitVec::repeat(true, len),
cap,
init_amt: len,
farthest_init: Some(len - 1),
}
}
pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
let f_idx = self.farthest_init.unwrap_or(0);
unsafe { slice::from_raw_parts_mut(self.data.as_ptr().add(f_idx), self.cap - f_idx) }
}
pub(crate) unsafe fn remove_at_unchecked(&mut self, index: usize) -> Option<T> {
if self.flags.replace_unchecked(index, false) {
self.init_amt -= 1;
if self.farthest_init == Some(index) {
self.farthest_init = self.flags.last_one();
}
Some(self.data.as_ptr().add(index).cast::<T>().read())
} else {
None
}
}
unsafe fn set_at_unchecked(&mut self, index: usize, data: T) {
(*self.data.as_ptr().add(index)).write(data);
if !self.flags.replace_unchecked(index, true) {
self.init_amt += 1;
match self.farthest_init {
Some(i) if i < index => self.farthest_init = Some(index),
_ => {}
}
}
}
pub fn next_push_index(&self) -> usize {
if self.spare_capacity() == 0 {
self.cap
} else {
self.flags.first_zero().unwrap_or(self.cap)
}
}
pub fn push(&mut self, data: T) -> usize {
let idx;
if self.spare_capacity() == 0 {
idx = self.cap;
self.reserve(1);
} else {
idx = self.flags.first_zero().unwrap_or(self.cap);
}
unsafe {
self.set_at_unchecked(idx, data);
}
idx
}
pub fn remove(&mut self, index: usize) -> Option<T> {
if index >= self.cap {
return None;
}
unsafe { self.remove_at_unchecked(index) }
}
pub fn replace(&mut self, index: usize, data: T) -> Option<T> {
if index >= self.cap {
return None;
}
if !unsafe { self.flags.replace_unchecked(index, true) } {
self.init_amt += 1;
unsafe {
self.set_at_unchecked(index, data);
None
}
} else {
unsafe {
let res = self.data.as_ptr().add(index).cast::<T>().read();
self.set_at_unchecked(index, data);
Some(res)
}
}
}
pub fn reserve_exact(&mut self, mut amt: usize) {
amt = match amt.checked_sub(self.spare_capacity()) {
None | Some(0) => return,
Some(a) => a,
};
self.flags.reserve_exact(amt);
if std::mem::size_of::<T>() == 0 {
self.cap += amt;
} else {
unsafe { self.realloc_unchecked(amt + self.cap) };
}
}
pub fn reserve(&mut self, mut amt: usize) {
amt = match 8.max(amt).checked_sub(self.spare_capacity()) {
None | Some(0) => return,
Some(a) => a,
};
self.flags.reserve(amt);
if std::mem::size_of::<T>() == 0 {
self.cap += amt;
} else {
unsafe { self.realloc_unchecked(self.cap + amt) };
}
}
#[must_use]
#[allow(clippy::double_must_use)]
pub fn push_iter<'s, Idx: PrimInt + 'static>(
&'s mut self,
iter: impl IntoIterator<Item = T> + 's,
) -> impl Iterator<Item = Idx> + 's
where
usize: AsPrimitive<Idx>,
{
iter.into_iter().map(|item| self.push(item).as_())
}
pub fn extend_from_iter(&mut self, iter: impl IntoIterator<Item = T>) -> Vec<usize> {
let mut res = Vec::new();
for item in iter {
res.push(self.push(item));
}
res
}
pub fn extend_from_other(&mut self, mut other: Self) -> HashMap<usize, usize> {
match other.farthest_init {
Some(f) => {
self.reserve_exact(other.len_init());
let odata = other.data.as_ptr() as *mut T;
let mut res = HashMap::new();
for i in 0..=f {
if other.flags[i] {
res.insert(i, self.push(unsafe { odata.add(i).read() }));
unsafe { other.flags.set_unchecked(i, false) };
}
}
res
}
None => HashMap::with_capacity(0),
}
}
#[must_use]
#[allow(clippy::uninit_assumed_init, clippy::needless_lifetimes)]
pub unsafe fn prepare_raw_array<'s, const LEN: usize>(
&'s mut self,
) -> [&'s mut MaybeUninit<T>; LEN] {
let sp = self as *mut Self;
let mut res: [&mut MaybeUninit<T>; LEN] = MaybeUninit::uninit().assume_init();
self.reserve_exact(LEN);
let mut idx = 0;
for e in &mut res {
idx = self.next_push_index();
*e = (*sp).get_raw_unsafe_mut(idx);
self.flags.set(idx, true);
}
self.init_amt += LEN;
self.farthest_init = Some(self.farthest_init.map_or(idx, |f| f.max(idx)));
res
}
pub fn extend_from_slice_cloned(&mut self, slice: &[T]) -> Vec<usize>
where
T: Clone,
{
todo!()
}
pub fn extend_from_slice_copied(&mut self, slice: &[T]) -> Vec<usize>
where
T: Copy,
{
todo!()
}
pub fn as_uninit_slice(&self) -> &[MaybeUninit<T>] {
unsafe { slice::from_raw_parts(self.data.as_ptr() as *const _, self.cap) }
}
pub fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<T>] {
unsafe { slice::from_raw_parts_mut(self.data.as_ptr() as *mut _, self.cap) }
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.flags.iter_ones().map(|i| &self[i])
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
self.flags.iter_ones().map(|i| todo!())
}
pub fn enumerate(&self) -> impl Iterator<Item = (usize, &T)> {
self.flags.iter_ones().map(|i| (i, &self[i]))
}
pub fn is_init(&self, index: usize) -> bool {
self.flags.get(index).map(|b| *b).unwrap_or(false)
}
pub fn is_fragmented(&self) -> bool {
match self.flags.first_zero() {
None => false,
Some(i) => i <= self.init_amt,
}
}
pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
let data = self.data.as_ptr();
let ap = data.add(a);
let bp = data.add(b);
std::ptr::swap_nonoverlapping(ap, bp, 1);
self.flags.swap_unchecked(a, b);
}
pub fn swap(&mut self, a: usize, b: usize) {
if a >= self.cap || b >= self.cap {
panic!()
}
unsafe {
self.swap_unchecked(a, b);
}
}
pub fn defragment(&mut self) -> Vec<(usize, usize)> {
match self.farthest_init {
Some(f) => {
let mut first_uninit = match self.flags.first_zero() {
Some(l) => l,
None => return Vec::with_capacity(0), };
let mut res = Vec::new();
let mut i = f;
let data = self.data.as_ptr();
while i > first_uninit {
if self.flags[i] {
unsafe {
std::ptr::copy_nonoverlapping(data.add(i), data.add(first_uninit), 1);
self.flags.set_unchecked(first_uninit, true);
self.flags.set_unchecked(i, false);
}
res.push((i, first_uninit));
first_uninit = match self.flags[(first_uninit + 1)..i].first_zero() {
Some(z) => z,
None => break, };
}
i -= 1;
}
self.farthest_init = Some(self.init_amt - 1);
res
}
None => Vec::with_capacity(0),
}
}
pub fn compress(&mut self) -> Vec<(usize, usize)> {
let res = self.defragment();
self.flags.truncate(self.init_amt);
unsafe {
self.realloc_unchecked(self.init_amt);
}
res
}
pub fn as_slice(&self) -> Option<&[T]> {
if self.is_fragmented() {
None
} else {
Some(unsafe {
std::slice::from_raw_parts(self.data.as_ptr() as *const T, self.init_amt)
})
}
}
pub fn as_slice_mut(&mut self) -> Option<&mut [T]> {
if self.is_fragmented() {
None
} else {
Some(unsafe {
std::slice::from_raw_parts_mut(self.data.as_ptr() as *mut T, self.init_amt)
})
}
}
pub fn init_flags(&self) -> &BitVec {
&self.flags
}
}
impl<T> Drop for StableVec<T> {
fn drop(&mut self) {
self.dealloc();
}
}
impl<T> Index<usize> for StableVec<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
self.get_unchecked(index)
}
}
impl<T> IndexMut<usize> for StableVec<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_unchecked_mut(index)
}
}
impl<T> FromIterator<T> for StableVec<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self::from_vec(iter.into_iter().collect())
}
}