openvm_circuit/system/memory/online/
paged_vec.rs1use std::fmt::Debug;
2
3use openvm_stark_backend::p3_maybe_rayon::prelude::*;
4
5#[derive(Debug, Clone)]
6pub struct PagedVec<T, const PAGE_SIZE: usize> {
7 pages: Vec<Option<Box<[T; PAGE_SIZE]>>>,
8}
9
10unsafe impl<T: Send, const PAGE_SIZE: usize> Send for PagedVec<T, PAGE_SIZE> {}
11unsafe impl<T: Sync, const PAGE_SIZE: usize> Sync for PagedVec<T, PAGE_SIZE> {}
12
13impl<T: Copy + Default, const PAGE_SIZE: usize> PagedVec<T, PAGE_SIZE> {
14 #[inline]
15 pub fn new(total_size: usize) -> Self {
17 let num_pages = total_size.div_ceil(PAGE_SIZE);
18 Self {
19 pages: vec![None; num_pages],
20 }
21 }
22
23 #[cold]
24 #[inline(never)]
25 fn create_zeroed_page() -> Box<[T; PAGE_SIZE]> {
26 unsafe {
31 let layout = std::alloc::Layout::array::<T>(PAGE_SIZE).unwrap();
32 let ptr = std::alloc::alloc_zeroed(layout) as *mut [T; PAGE_SIZE];
33 Box::from_raw(ptr)
34 }
35 }
36
37 #[inline]
40 pub fn get(&self, index: usize) -> T {
41 let page_idx = index / PAGE_SIZE;
42 let offset = index % PAGE_SIZE;
43
44 self.pages[page_idx]
48 .as_ref()
49 .map(|page| unsafe { *page.get_unchecked(offset) })
50 .unwrap_or_default()
51 }
52
53 #[inline]
55 pub fn set(&mut self, index: usize, value: T) {
56 let page_idx = index / PAGE_SIZE;
57 let offset = index % PAGE_SIZE;
58
59 let page = self.pages[page_idx].get_or_insert_with(Self::create_zeroed_page);
60
61 unsafe {
63 *page.get_unchecked_mut(offset) = value;
64 }
65 }
66
67 pub fn par_iter(&self) -> impl ParallelIterator<Item = (usize, T)> + '_
68 where
69 T: Send + Sync,
70 {
71 self.pages
72 .par_iter()
73 .enumerate()
74 .filter_map(move |(page_idx, page)| {
75 page.as_ref().map(move |p| {
76 p.par_iter()
77 .enumerate()
78 .map(move |(offset, &value)| (page_idx * PAGE_SIZE + offset, value))
79 })
80 })
81 .flatten()
82 }
83
84 pub fn iter(&self) -> impl Iterator<Item = (usize, T)> + '_
85 where
86 T: Send + Sync,
87 {
88 self.pages
89 .iter()
90 .enumerate()
91 .filter_map(move |(page_idx, page)| {
92 page.as_ref().map(move |p| {
93 p.iter()
94 .enumerate()
95 .map(move |(offset, &value)| (page_idx * PAGE_SIZE + offset, value))
96 })
97 })
98 .flatten()
99 }
100}