use core::{
cell::{Cell, UnsafeCell},
mem::{needs_drop, MaybeUninit},
sync::atomic::{AtomicUsize, Ordering},
};
pub struct CallOnDrop<F: FnMut()>(pub F);
impl<F: FnMut()> Drop for CallOnDrop<F> {
fn drop(&mut self) {
(self.0)();
}
}
pub struct Slot<T> {
slot: UnsafeCell<MaybeUninit<T>>,
flag: AtomicUsize,
}
const NONE: usize = 0;
const LOCK: usize = 1;
const SOME: usize = 2;
impl<T> Slot<T> {
pub const fn empty() -> Slot<T> {
Slot {
slot: UnsafeCell::new(MaybeUninit::uninit()),
flag: AtomicUsize::new(NONE),
}
}
pub fn put(&self, value: T) -> Option<T> {
match self
.flag
.compare_exchange(NONE, LOCK, Ordering::Acquire, Ordering::Relaxed)
{
Err(_) => Some(value),
Ok(_) => {
unsafe {
let slot = &mut *(self.slot.get());
slot.write(value);
};
self.flag.store(SOME, Ordering::Release);
None
}
}
}
pub fn take(&self) -> Option<T> {
match self
.flag
.compare_exchange(SOME, LOCK, Ordering::Acquire, Ordering::Relaxed)
{
Err(_) => None,
Ok(_) => {
let value;
unsafe {
let slot = &mut *(self.slot.get());
value = slot.assume_init_read();
};
self.flag.store(NONE, Ordering::Release);
Some(value)
}
}
}
}
impl<T> Drop for Slot<T> {
fn drop(&mut self) {
if needs_drop::<T>() {
let Slot { flag, slot } = self;
unsafe {
if *flag.get_mut() == SOME {
slot.get_mut().as_mut_ptr().drop_in_place();
}
}
}
}
}
unsafe impl<T> Send for Slot<T> where T: Send {}
unsafe impl<T> Sync for Slot<T> where T: Send {}
pub struct XorShift64Star {
state: Cell<u64>,
}
impl XorShift64Star {
pub fn new(seed: u64) -> Self {
XorShift64Star {
state: Cell::new(seed),
}
}
pub fn next(&self) -> u64 {
let mut x = self.state.get();
debug_assert_ne!(x, 0);
x ^= x >> 12;
x ^= x << 25;
x ^= x >> 27;
self.state.set(x);
x.wrapping_mul(0x2545_f491_4f6c_dd1d)
}
pub fn next_usize(&self, n: usize) -> usize {
(self.next() % n as u64) as usize
}
}