use std::fmt::Debug;
use std::mem::MaybeUninit;
use std::ptr;
use rand::seq::SliceRandom;
use rand::Rng;
pub struct MoveArena<M> {
storage: Vec<MaybeUninit<M>>,
len: usize,
taken: Option<usize>,
}
impl<M> MoveArena<M> {
#[inline]
pub fn new() -> Self {
Self {
storage: Vec::new(),
len: 0,
taken: None,
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self {
storage: Vec::with_capacity(capacity),
len: 0,
taken: None,
}
}
#[inline]
pub fn reset(&mut self) {
for i in 0..self.len {
if self.taken != Some(i) {
unsafe {
ptr::drop_in_place(self.storage[i].as_mut_ptr());
}
}
}
self.len = 0;
self.taken = None;
}
#[inline]
pub fn push(&mut self, m: M) {
if self.len < self.storage.len() {
self.storage[self.len] = MaybeUninit::new(m);
} else {
self.storage.push(MaybeUninit::new(m));
}
self.len += 1;
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &M> {
self.storage[..self.len]
.iter()
.map(|slot| unsafe { slot.assume_init_ref() })
}
#[inline]
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut M> {
self.storage[..self.len]
.iter_mut()
.map(|slot| unsafe { slot.assume_init_mut() })
}
#[inline]
pub fn get(&self, index: usize) -> Option<&M> {
if index < self.len {
Some(unsafe { self.storage[index].assume_init_ref() })
} else {
None
}
}
#[inline]
pub fn take(&mut self, index: usize) -> M {
assert!(index < self.len, "index out of bounds");
assert!(self.taken.is_none(), "move already taken this step");
self.taken = Some(index);
unsafe { self.storage[index].assume_init_read() }
}
#[inline]
pub fn extend<I: IntoIterator<Item = M>>(&mut self, iter: I) {
for m in iter {
self.push(m);
}
}
#[inline]
pub fn shuffle<R: Rng>(&mut self, rng: &mut R) {
if self.len < 2 {
return;
}
let slice = &mut self.storage[..self.len];
slice.shuffle(rng);
}
#[inline]
pub fn capacity(&self) -> usize {
self.storage.capacity()
}
}
impl<M> Default for MoveArena<M> {
fn default() -> Self {
Self::new()
}
}
impl<M: Debug> Debug for MoveArena<M> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MoveArena")
.field("len", &self.len)
.field("capacity", &self.storage.capacity())
.finish()
}
}
impl<M> Drop for MoveArena<M> {
fn drop(&mut self) {
for i in 0..self.len {
if self.taken != Some(i) {
unsafe {
ptr::drop_in_place(self.storage[i].as_mut_ptr());
}
}
}
}
}