use crate::atomic_once_cell_array::AtomicOnceCellArray;
use std::ops::Range;
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct AtomicOnceCellStack<T> {
data: AtomicOnceCellArray<T>,
last_index: AtomicUsize,
}
impl<T> AtomicOnceCellStack<T> {
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: AtomicOnceCellArray::with_capacity(capacity),
last_index: AtomicUsize::new(0),
}
}
pub fn push(
&self,
val: T,
) -> usize {
let last_len = self.last_index.fetch_add(1, Ordering::Relaxed);
self.data.set(last_len, val);
last_len
}
pub fn reserve_uninit(
&self,
num_to_reserve: usize,
) -> usize {
let last_len = self.last_index.fetch_add(num_to_reserve, Ordering::Relaxed);
if last_len + num_to_reserve > self.capacity() {
panic!(
"len {} + num_to_reserve {} must be <= capacity {}",
last_len,
num_to_reserve,
self.capacity()
);
}
last_len
}
pub fn set(
&self,
index: usize,
val: T,
) {
if index < self.len() {
self.data.set(index, val);
} else {
panic!(
"index {} must be < len {} (did you forget to `reserve_uninit` first?)",
index,
self.capacity()
);
}
}
pub fn get(
&self,
index: usize,
) -> &T {
self.data.get(index)
}
pub unsafe fn get_range_unchecked(
&self,
range: Range<usize>,
) -> &[T] {
let len = self.len();
if range.end > len {
panic!("end of range {} must be < len {}", range.end, len);
}
&self.data.get_all_unchecked()[range]
}
pub unsafe fn get_all_unchecked(&self) -> &[T] {
let len = self.len();
let capacity = self.capacity();
if len < capacity {
panic!("length {} must be == capacity {}", len, capacity);
}
self.data.get_all_unchecked()
}
pub fn capacity(&self) -> usize {
self.data.capacity()
}
pub fn len(&self) -> usize {
self.last_index.load(Ordering::Acquire)
}
pub fn iter(&self) -> Iter<T> {
self.into_iter()
}
}
impl<'a, T> IntoIterator for &'a AtomicOnceCellStack<T> {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
Iter::new(self)
}
}
pub struct Iter<'a, T> {
source: &'a AtomicOnceCellStack<T>,
next_index: usize,
}
impl<'a, T> Iter<'a, T> {
#[inline]
pub fn new(source: &'a AtomicOnceCellStack<T>) -> Self {
Self {
source,
next_index: 0,
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
if self.next_index < self.source.len() {
let index = self.next_index;
self.next_index += 1;
Some(self.source.get(index))
} else {
None
}
}
}