use std::fmt::Debug;
use openvm_stark_backend::p3_maybe_rayon::prelude::*;
#[derive(Debug, Clone)]
pub struct PagedVec<T, const PAGE_SIZE: usize> {
pages: Vec<Option<Box<[T; PAGE_SIZE]>>>,
}
unsafe impl<T: Send, const PAGE_SIZE: usize> Send for PagedVec<T, PAGE_SIZE> {}
unsafe impl<T: Sync, const PAGE_SIZE: usize> Sync for PagedVec<T, PAGE_SIZE> {}
impl<T: Copy + Default, const PAGE_SIZE: usize> PagedVec<T, PAGE_SIZE> {
#[inline]
pub fn new(total_size: usize) -> Self {
let num_pages = total_size.div_ceil(PAGE_SIZE);
Self {
pages: vec![None; num_pages],
}
}
#[cold]
#[inline(never)]
fn create_zeroed_page() -> Box<[T; PAGE_SIZE]> {
unsafe {
let layout = std::alloc::Layout::array::<T>(PAGE_SIZE).unwrap();
let ptr = std::alloc::alloc_zeroed(layout) as *mut [T; PAGE_SIZE];
Box::from_raw(ptr)
}
}
#[inline]
pub fn get(&self, index: usize) -> T {
let page_idx = index / PAGE_SIZE;
let offset = index % PAGE_SIZE;
self.pages[page_idx]
.as_ref()
.map(|page| unsafe { *page.get_unchecked(offset) })
.unwrap_or_default()
}
#[inline]
pub fn set(&mut self, index: usize, value: T) {
let page_idx = index / PAGE_SIZE;
let offset = index % PAGE_SIZE;
let page = self.pages[page_idx].get_or_insert_with(Self::create_zeroed_page);
unsafe {
*page.get_unchecked_mut(offset) = value;
}
}
pub fn par_iter(&self) -> impl ParallelIterator<Item = (usize, T)> + '_
where
T: Send + Sync,
{
self.pages
.par_iter()
.enumerate()
.filter_map(move |(page_idx, page)| {
page.as_ref().map(move |p| {
p.par_iter()
.enumerate()
.map(move |(offset, &value)| (page_idx * PAGE_SIZE + offset, value))
})
})
.flatten()
}
pub fn iter(&self) -> impl Iterator<Item = (usize, T)> + '_
where
T: Send + Sync,
{
self.pages
.iter()
.enumerate()
.filter_map(move |(page_idx, page)| {
page.as_ref().map(move |p| {
p.iter()
.enumerate()
.map(move |(offset, &value)| (page_idx * PAGE_SIZE + offset, value))
})
})
.flatten()
}
}