1mod alloc_tracker;
4mod mutable_subgrid;
5mod shared_subgrid;
6mod simd;
7pub use alloc_tracker::*;
8pub use mutable_subgrid::*;
9pub use shared_subgrid::*;
10pub use simd::SimdVector;
11
12#[cfg(test)]
13mod test;
14
15#[derive(Debug)]
17pub struct OutOfMemory {
18 bytes: usize,
19}
20
21impl OutOfMemory {
22 fn new(bytes: usize) -> Self {
23 Self { bytes }
24 }
25
26 pub fn bytes(&self) -> usize {
28 self.bytes
29 }
30}
31
32impl std::error::Error for OutOfMemory {}
33
34impl std::fmt::Display for OutOfMemory {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 write!(f, "failed to allocate {} byte(s)", self.bytes)
37 }
38}
39
40pub struct AlignedGrid<S> {
44 width: usize,
45 height: usize,
46 offset: usize,
47 buf: Vec<S>,
48 handle: Option<AllocHandle>,
49}
50
51impl<S> std::fmt::Debug for AlignedGrid<S> {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 f.debug_struct("AlignedGrid")
54 .field("width", &self.width)
55 .field("height", &self.height)
56 .field("offset", &self.offset)
57 .finish_non_exhaustive()
58 }
59}
60
61impl<S> AlignedGrid<S> {
62 #[inline]
64 pub fn empty() -> Self {
65 Self {
66 width: 0,
67 height: 0,
68 offset: 0,
69 buf: Vec::new(),
70 handle: None,
71 }
72 }
73}
74
75impl<S: Default + Clone> AlignedGrid<S> {
76 const ALIGN: usize = 32;
77
78 #[inline]
80 pub fn with_alloc_tracker(
81 width: usize,
82 height: usize,
83 tracker: Option<&AllocTracker>,
84 ) -> Result<Self, OutOfMemory> {
85 let len = width
86 .checked_mul(height)
87 .expect("grid dimensions overflow usize");
88 let buf_len = len
89 .checked_add((Self::ALIGN - 1) / std::mem::size_of::<S>())
90 .expect("aligned grid buffer length overflows usize");
91 let handle = tracker
92 .map(|tracker| tracker.alloc::<S>(buf_len))
93 .transpose()?;
94 let mut buf = vec![S::default(); buf_len];
95
96 let extra = buf.as_ptr() as usize & (Self::ALIGN - 1);
97 let offset = ((Self::ALIGN - extra) % Self::ALIGN) / std::mem::size_of::<S>();
98 let len_with_offset = len
99 .checked_add(offset)
100 .expect("aligned grid buffer length overflows usize");
101 buf.resize_with(len_with_offset, S::default);
102
103 Ok(Self {
104 width,
105 height,
106 offset,
107 buf,
108 handle,
109 })
110 }
111
112 #[inline]
113 fn empty_aligned(
114 width: usize,
115 height: usize,
116 tracker: Option<&AllocTracker>,
117 ) -> Result<Self, OutOfMemory> {
118 let len = width
119 .checked_mul(height)
120 .expect("grid dimensions overflow usize");
121 let buf_len = len
122 .checked_add((Self::ALIGN - 1) / std::mem::size_of::<S>())
123 .expect("aligned grid buffer length overflows usize");
124 let handle = tracker
125 .map(|tracker| tracker.alloc::<S>(buf_len))
126 .transpose()?;
127 let mut buf = Vec::with_capacity(buf_len);
128
129 let extra = buf.as_ptr() as usize & (Self::ALIGN - 1);
130 let offset = ((Self::ALIGN - extra) % Self::ALIGN) / std::mem::size_of::<S>();
131 buf.resize_with(offset, S::default);
132
133 Ok(Self {
134 width,
135 height,
136 offset,
137 buf,
138 handle,
139 })
140 }
141
142 pub fn clone_untracked(&self) -> Self {
144 let mut out = Self::empty_aligned(self.width, self.height, None).unwrap();
145 out.buf.extend_from_slice(self.buf());
146 out
147 }
148
149 pub fn try_clone(&self) -> Result<Self, OutOfMemory> {
152 let mut out = Self::empty_aligned(self.width, self.height, self.tracker().as_ref())?;
153 out.buf.extend_from_slice(self.buf());
154 Ok(out)
155 }
156}
157
158impl<S> AlignedGrid<S> {
159 #[inline]
161 pub fn width(&self) -> usize {
162 self.width
163 }
164
165 #[inline]
167 pub fn height(&self) -> usize {
168 self.height
169 }
170
171 #[inline]
173 pub fn tracker(&self) -> Option<AllocTracker> {
174 self.handle.as_ref().map(|handle| handle.tracker())
175 }
176
177 #[inline]
182 pub fn get_ref(&self, x: usize, y: usize) -> &S {
183 let width = self.width;
184 let height = self.height;
185 let Some(r) = self.try_get_ref(x, y) else {
186 panic!("coordinate out of range: ({x}, {y}) not in {width}x{height}");
187 };
188
189 r
190 }
191
192 #[inline]
194 pub fn try_get_ref(&self, x: usize, y: usize) -> Option<&S> {
195 if x >= self.width || y >= self.height {
196 return None;
197 }
198
199 Some(&self.buf[y * self.width + x + self.offset])
200 }
201
202 #[inline]
207 pub fn get_mut(&mut self, x: usize, y: usize) -> &mut S {
208 let width = self.width;
209 let height = self.height;
210 let Some(r) = self.try_get_mut(x, y) else {
211 panic!("coordinate out of range: ({x}, {y}) not in {width}x{height}");
212 };
213
214 r
215 }
216
217 #[inline]
220 pub fn try_get_mut(&mut self, x: usize, y: usize) -> Option<&mut S> {
221 if x >= self.width || y >= self.height {
222 return None;
223 }
224
225 Some(&mut self.buf[y * self.width + x + self.offset])
226 }
227
228 #[inline]
233 pub fn get_row(&self, row: usize) -> &[S] {
234 let height = self.height;
235 let Some(slice) = self.try_get_row(row) else {
236 panic!("row index out of range: height is {height} but index is {row}");
237 };
238
239 slice
240 }
241
242 #[inline]
244 pub fn try_get_row(&self, y: usize) -> Option<&[S]> {
245 if y >= self.height {
246 return None;
247 }
248
249 Some(&self.buf[y * self.width + self.offset..][..self.width])
250 }
251
252 #[inline]
257 pub fn get_row_mut(&mut self, row: usize) -> &mut [S] {
258 let height = self.height;
259 let Some(slice) = self.try_get_row_mut(row) else {
260 panic!("row index out of range: height is {height} but index is {row}");
261 };
262
263 slice
264 }
265
266 #[inline]
268 pub fn try_get_row_mut(&mut self, y: usize) -> Option<&mut [S]> {
269 if y >= self.height {
270 return None;
271 }
272
273 Some(&mut self.buf[y * self.width + self.offset..][..self.width])
274 }
275
276 #[inline]
278 pub fn buf(&self) -> &[S] {
279 &self.buf[self.offset..]
280 }
281
282 #[inline]
284 pub fn buf_mut(&mut self) -> &mut [S] {
285 &mut self.buf[self.offset..]
286 }
287
288 #[inline]
290 pub fn as_subgrid(&self) -> SharedSubgrid<'_, S> {
291 SharedSubgrid::from(self)
292 }
293
294 #[inline]
296 pub fn as_subgrid_mut(&mut self) -> MutableSubgrid<'_, S> {
297 MutableSubgrid::from(self)
298 }
299}
300
301impl<V: Copy> AlignedGrid<V> {
302 #[inline]
307 pub fn get(&self, x: usize, y: usize) -> V {
308 *self.get_ref(x, y)
309 }
310}