#![allow(clippy::declare_interior_mutable_const)]
use core::mem::{self, MaybeUninit};
use core::ops::Index;
use core::panic::RefUnwindSafe;
use core::ptr;
use crate::buckets::{self, buckets_for_index_bits, Buckets, MaybeZeroable};
use crate::loom::atomic::{AtomicBool, AtomicUsize, Ordering};
use crate::loom::cell::UnsafeCell;
use crate::loom::AtomicMut;
pub struct Vec<T> {
inflight: AtomicUsize,
buckets: Buckets<Entry<T>, BUCKETS>,
count: AtomicUsize,
}
impl<T> Vec<T> {
#[cfg(not(loom))]
pub const fn new() -> Vec<T> {
let Some(zero) = <buckets::Index<BUCKETS>>::new(0) else {
unreachable!();
};
Vec {
inflight: AtomicUsize::new(zero.into_raw().get()),
buckets: Buckets::new(),
count: AtomicUsize::new(0),
}
}
#[cfg(loom)]
pub fn new() -> Vec<T> {
Vec {
inflight: AtomicUsize::new(<buckets::Index<BUCKETS>>::new(0).unwrap().into_raw().get()),
buckets: Buckets::new(),
count: AtomicUsize::new(0),
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Vec<T> {
let mut this = Self::new();
if let Some(highest_index) = capacity.checked_sub(1) {
this.buckets
.reserve_mut(buckets::Index::new_saturating(highest_index));
}
this
}
#[inline]
pub fn count(&self) -> usize {
self.count.load(Ordering::Acquire)
}
#[inline]
pub fn get(&self, index: usize) -> Option<&T> {
let entry = self.buckets.get(buckets::Index::new(index)?)?;
if entry.active.load(Ordering::Acquire) {
unsafe { return Some(entry.value_unchecked()) }
}
None
}
#[inline]
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
unsafe {
let entry = self
.buckets
.get_unchecked(buckets::Index::new_unchecked(index));
(*entry).value_unchecked()
}
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
let entry = self.buckets.get_mut(buckets::Index::new(index)?)?;
if entry.active.read_mut() {
unsafe { return Some(entry.value_unchecked_mut()) }
}
None
}
#[inline]
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
unsafe {
let entry = self
.buckets
.get_unchecked_mut(buckets::Index::new_unchecked(index));
(*entry).value_unchecked_mut()
}
}
#[inline]
fn next_index(&self) -> buckets::Index<BUCKETS> {
let index = self.inflight.fetch_add(1, Ordering::Relaxed);
let Some(index) = (unsafe { buckets::Index::from_raw_checked_above(index) }) else {
self.next_index_overflow();
};
index
}
#[cold]
#[inline(never)]
fn next_index_overflow(&self) -> ! {
self.inflight.fetch_sub(1, Ordering::Relaxed);
panic!("capacity overflow");
}
#[inline]
pub fn push_with<F>(&self, f: F) -> usize
where
F: FnOnce(usize) -> T,
{
let index = self.next_index();
let value = f(index.get());
unsafe { self.write(index, value) }
}
#[inline]
pub fn push(&self, value: T) -> usize {
unsafe { self.write(self.next_index(), value) }
}
#[inline]
unsafe fn write(&self, index: buckets::Index<BUCKETS>, value: T) -> usize {
let entry = self.buckets.get_or_alloc(index);
unsafe {
entry
.slot
.with_mut(|slot| slot.write(MaybeUninit::new(value)));
entry.active.store(true, Ordering::Release);
}
self.count.fetch_add(1, Ordering::Release);
index.get()
}
pub fn reserve(&self, additional: usize) {
let len = self.count.load(Ordering::Acquire);
if let Some(highest_index) = len.saturating_add(additional).checked_sub(1) {
self.buckets
.reserve(buckets::Index::new_saturating(highest_index));
}
}
#[inline]
pub fn iter(&self) -> Iter<'_, T> {
Iter {
inner: self.buckets.iter(),
after_inflight: unsafe {
buckets::Index::from_raw_checked_above(self.inflight.load(Ordering::Relaxed))
},
}
}
#[inline]
pub fn into_iter(mut self) -> IntoIter<T> {
IntoIter {
inner: self.buckets.into_iter(),
remaining: self.count.read_mut(),
}
}
#[inline]
pub fn clear(&mut self) {
self.buckets
.iter_mut()
.filter_map(|(_, entry)| entry.take())
.take(self.count.read_mut())
.for_each(drop);
self.count.write_mut(0);
self.inflight
.write_mut(<buckets::Index<BUCKETS>>::new(0).unwrap().into_raw().get());
}
}
impl<T> Index<usize> for Vec<T> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
#[cold]
#[inline(never)]
fn assert_failed(index: usize) -> ! {
panic!("index {index} is uninitialized");
}
match self.get(index) {
Some(value) => value,
None => assert_failed(index),
}
}
}
struct Entry<T> {
active: AtomicBool,
slot: UnsafeCell<MaybeUninit<T>>,
}
impl<T> Default for Entry<T> {
fn default() -> Self {
Self {
active: AtomicBool::new(false),
slot: UnsafeCell::new(MaybeUninit::uninit()),
}
}
}
unsafe impl<T> MaybeZeroable for Entry<T> {
fn zeroable() -> bool {
cfg!(not(loom))
}
}
unsafe impl<T: Send> Send for Entry<T> {}
unsafe impl<T: Send + Sync> Sync for Entry<T> {}
impl<T> RefUnwindSafe for Entry<T> {}
impl<T> Entry<T> {
#[inline]
unsafe fn value_unchecked(&self) -> &T {
self.slot.with(|slot| unsafe { (*slot).assume_init_ref() })
}
#[inline]
unsafe fn value_unchecked_mut(&mut self) -> &mut T {
self.slot
.with_mut(|slot| unsafe { (*slot).assume_init_mut() })
}
fn take(&mut self) -> Option<T> {
if self.active.read_mut() {
self.active.write_mut(false);
let value = mem::replace(&mut self.slot, UnsafeCell::new(MaybeUninit::uninit()));
Some(unsafe { value.into_inner().assume_init() })
} else {
None
}
}
}
impl<T> Drop for Entry<T> {
fn drop(&mut self) {
if self.active.read_mut() {
unsafe { ptr::drop_in_place(self.slot.with_mut(|slot| (*slot).as_mut_ptr())) }
}
}
}
const BUCKETS: usize = buckets_for_index_bits(usize::BITS - 1);
pub struct Iter<'a, T> {
inner: buckets::Iter<'a, Entry<T>, BUCKETS>,
after_inflight: Option<buckets::Index<BUCKETS>>,
}
impl<T> Clone for Iter<'_, T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
after_inflight: self.after_inflight,
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (usize, &'a T);
fn next(&mut self) -> Option<Self::Item> {
loop {
let (index, entry) = self.inner.next()?;
if self
.after_inflight
.is_some_and(|after_inflight| index >= after_inflight)
{
return None;
}
if entry.active.load(Ordering::Acquire) {
return Some((index.get(), unsafe { entry.value_unchecked() }));
}
}
}
}
pub struct IntoIter<T> {
inner: buckets::IntoIter<Entry<T>, BUCKETS>,
remaining: usize,
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
loop {
self.remaining = self.remaining.checked_sub(1)?;
let (_, mut entry) = self.inner.next()?;
if let Some(value) = entry.take() {
return Some(value);
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.remaining
}
}