use std::mem;
use egglog_concurrency::ReadOptimizedLock;
use super::atomic_int::AtomicInt;
pub struct Buffer<T> {
data: ReadOptimizedLock<Vec<T>>,
}
impl<T: AtomicInt> Clone for Buffer<T> {
fn clone(&self) -> Self {
let reader = self.data.read();
let mut new = Vec::with_capacity(reader.capacity());
let mut i = 0;
new.resize_with(reader.len(), || {
let result = T::from_usize(T::as_usize(reader[i].load()));
i += 1;
result
});
Self {
data: ReadOptimizedLock::new(new),
}
}
}
impl<T: Send + Sync + 'static> Buffer<T> {
pub fn new(capacity: usize, mut init: impl FnMut(usize) -> T) -> Buffer<T> {
let mut vec = Vec::with_capacity(capacity);
let mut i = 0;
vec.resize_with(capacity, || {
let res = init(i);
i += 1;
res
});
Buffer {
data: ReadOptimizedLock::new(vec),
}
}
pub fn with_access<R>(
&self,
len: usize,
mut f: impl FnMut(&[T]) -> R,
mut init: impl FnMut(usize) -> T + Send + Clone + 'static,
) -> R {
let data = self.data.read();
if data.len() >= len {
return f(&data);
}
mem::drop(data);
let mut data = self.data.lock();
if data.len() < len {
let len = len.next_power_of_two();
let mut i = data.len();
data.resize_with(len, || {
let result = init(i);
i += 1;
result
});
}
mem::drop(data);
self.with_access(len, f, init)
}
pub fn re_init(&self, mut init: impl FnMut(usize) -> T + Send + Clone + 'static) {
let mut data = self.data.lock();
let mut i = 0;
data.iter_mut().for_each(|x| {
*x = init(i);
i += 1;
});
}
}