1use bytemuck::{Pod, Zeroable};
20use std::fmt;
21use std::mem::size_of;
22use std::ops::Range;
23use std::sync::Arc;
24
25use crate::{ExecutionContext, MemoryBudgetError, MemoryReservation};
26
27const LANE: usize = 16;
30
31#[repr(C, align(64))]
32#[derive(Clone, Copy, Pod, Zeroable)]
33struct CoordLane([[f32; 3]; LANE]);
34
35#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
42#[repr(transparent)]
43pub struct CoordinateGeneration(u64);
44
45impl CoordinateGeneration {
46 pub const INITIAL: Self = Self(0);
48
49 #[must_use]
56 pub const fn from_raw(value: u64) -> Self {
57 Self(value)
58 }
59
60 #[must_use]
62 pub const fn next(self) -> Option<Self> {
63 match self.0.checked_add(1) {
64 Some(next) => Some(Self(next)),
65 None => None,
66 }
67 }
68
69 #[must_use]
71 pub const fn get(self) -> u64 {
72 self.0
73 }
74}
75
76#[derive(Clone, Copy, PartialEq, Debug)]
82pub struct Aabb {
83 pub min: [f32; 3],
85 pub max: [f32; 3],
87}
88
89impl Aabb {
90 pub const EMPTY: Self = Self {
92 min: [f32::INFINITY; 3],
93 max: [f32::NEG_INFINITY; 3],
94 };
95
96 #[must_use]
98 #[inline]
99 pub fn is_empty(&self) -> bool {
100 self.min[0] > self.max[0] || self.min[1] > self.max[1] || self.min[2] > self.max[2]
101 }
102
103 #[inline]
109 pub fn extend(&mut self, point: [f32; 3]) {
110 extend_axis(&mut self.min[0], &mut self.max[0], point[0]);
111 extend_axis(&mut self.min[1], &mut self.max[1], point[1]);
112 extend_axis(&mut self.min[2], &mut self.max[2], point[2]);
113 }
114
115 #[inline]
117 pub fn union(&mut self, other: &Self) {
118 if other.is_empty() {
119 return;
120 }
121
122 self.extend(other.min);
123 self.extend(other.max);
124 }
125
126 #[must_use]
130 #[inline]
131 pub fn within(&self, other: &Self, distance: f32) -> bool {
132 if self.is_empty() || other.is_empty() {
133 return false;
134 }
135
136 let maximum_gap_squared = distance * distance;
137
138 let x = axis_gap(self.min[0], self.max[0], other.min[0], other.max[0]);
139 let mut gap_squared = x * x;
140
141 if gap_squared > maximum_gap_squared {
142 return false;
143 }
144
145 let y = axis_gap(self.min[1], self.max[1], other.min[1], other.max[1]);
146 gap_squared += y * y;
147
148 if gap_squared > maximum_gap_squared {
149 return false;
150 }
151
152 let z = axis_gap(self.min[2], self.max[2], other.min[2], other.max[2]);
153 gap_squared += z * z;
154
155 gap_squared <= maximum_gap_squared
156 }
157}
158
159impl Default for Aabb {
160 fn default() -> Self {
162 Self::EMPTY
163 }
164}
165
166#[derive(Clone, Default)]
181pub struct CoordinateBlock {
182 lanes: Arc<Vec<CoordLane>>,
183 len: u32,
184 reservation: Option<Arc<MemoryReservation>>,
185}
186
187impl CoordinateBlock {
188 #[must_use]
190 pub fn new() -> Self {
191 Self {
192 lanes: Arc::new(Vec::new()),
193 len: 0,
194 reservation: None,
195 }
196 }
197
198 #[must_use]
200 pub fn with_capacity(positions: usize) -> Self {
201 Self {
202 lanes: Arc::new(Vec::with_capacity(lanes_for_positions(positions))),
203 len: 0,
204 reservation: None,
205 }
206 }
207
208 #[must_use]
210 pub const fn len(&self) -> u32 {
211 self.len
212 }
213
214 #[must_use]
216 pub const fn is_empty(&self) -> bool {
217 self.len == 0
218 }
219
220 pub fn push(&mut self, position: [f32; 3]) {
225 let Some((index, next_len)) = append_indices(self.len) else {
226 return;
227 };
228
229 let lanes = Arc::make_mut(&mut self.lanes);
230
231 if write_position(lanes, index, position) {
232 self.len = next_len;
233 }
234 }
235
236 #[must_use]
241 #[inline]
242 pub fn as_slice(&self) -> &[[f32; 3]] {
243 let all: &[[f32; 3]] = bytemuck::cast_slice(self.lanes.as_slice());
244 visible_slice(all, self.len)
245 }
246
247 #[inline]
253 pub(crate) fn as_mut_slice(&mut self) -> &mut [[f32; 3]] {
254 let lanes = Arc::make_mut(&mut self.lanes);
255 let all: &mut [[f32; 3]] = bytemuck::cast_slice_mut(lanes.as_mut_slice());
256
257 visible_mut_slice(all, self.len)
258 }
259
260 pub(crate) fn make_unique_in(
266 &mut self,
267 context: &ExecutionContext,
268 ) -> Result<(), MemoryBudgetError> {
269 if Arc::strong_count(&self.lanes) == 1 {
270 return Ok(());
271 }
272 let bytes = self.allocated_bytes();
273 let mut reservation = context.try_reserve(bytes)?;
274 let mut lanes = Vec::with_capacity(self.lanes.capacity());
275 lanes.extend_from_slice(&self.lanes);
276 let retained = lanes.capacity().saturating_mul(size_of::<CoordLane>());
277 if retained > bytes {
278 reservation.try_grow(retained - bytes)?;
279 } else {
280 reservation.shrink_to(retained);
281 }
282 self.lanes = Arc::new(lanes);
283 self.reservation = Some(Arc::new(reservation));
284 Ok(())
285 }
286
287 #[must_use]
289 #[inline]
290 pub fn range(&self, range: Range<u32>) -> Option<&[[f32; 3]]> {
291 let range = usize_range(range)?;
292 self.as_slice().get(range)
293 }
294
295 #[must_use]
297 pub fn bounds(&self, range: Range<u32>) -> Aabb {
298 let Some(positions) = self.range(range) else {
299 return Aabb::EMPTY;
300 };
301
302 let mut bounds = Aabb::EMPTY;
303
304 for &position in positions {
305 bounds.extend(position);
306 }
307
308 bounds
309 }
310
311 #[must_use]
313 pub fn allocated_bytes(&self) -> usize {
314 self.lanes.capacity() * size_of::<CoordLane>()
315 }
316}
317
318impl fmt::Debug for CoordinateBlock {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321 f.debug_struct("CoordinateBlock")
322 .field("positions", &self.len)
323 .finish_non_exhaustive()
324 }
325}
326
327impl FromIterator<[f32; 3]> for CoordinateBlock {
328 fn from_iter<T: IntoIterator<Item = [f32; 3]>>(iter: T) -> Self {
333 let mut iter = iter.into_iter();
334 let hinted_positions = iter.size_hint().0;
335
336 let mut lanes = Vec::new();
337 let hinted_lanes = lanes_for_positions(hinted_positions);
338
339 if hinted_lanes != 0 {
342 let _reserve_failed = lanes.try_reserve_exact(hinted_lanes).is_err();
343 }
344
345 let mut len = 0u32;
346
347 for position in &mut iter {
348 let Some((index, next_len)) = append_indices(len) else {
349 break;
350 };
351
352 if !write_position(&mut lanes, index, position) {
353 break;
354 }
355
356 len = next_len;
357 }
358
359 Self {
360 lanes: Arc::new(lanes),
361 len,
362 reservation: None,
363 }
364 }
365}
366
367#[inline]
369fn extend_axis(minimum: &mut f32, maximum: &mut f32, value: f32) {
370 if !value.is_finite() {
371 return;
372 }
373
374 *minimum = minimum.min(value);
375 *maximum = maximum.max(value);
376}
377
378#[inline]
380fn axis_gap(own_min: f32, own_max: f32, other_min: f32, other_max: f32) -> f32 {
381 (other_min - own_max).max(own_min - other_max).max(0.0)
382}
383
384#[inline]
386fn lanes_for_positions(positions: usize) -> usize {
387 positions.div_ceil(LANE)
388}
389
390#[inline]
395fn append_indices(len: u32) -> Option<(usize, u32)> {
396 let next_len = len.checked_add(1)?;
397 let index = usize::try_from(len).ok()?;
398
399 Some((index, next_len))
400}
401
402#[inline]
407fn write_position(lanes: &mut Vec<CoordLane>, index: usize, position: [f32; 3]) -> bool {
408 let (lane_index, slot) = lane_position(index);
409
410 if lane_index > lanes.len() {
411 return false;
412 }
413
414 if lane_index == lanes.len() {
415 let mut lane = CoordLane([[0.0; 3]; LANE]);
416
417 let Some(target) = lane.0.get_mut(slot) else {
418 return false;
419 };
420
421 *target = position;
422 lanes.push(lane);
423 return true;
424 }
425
426 let Some(target) = lanes
427 .get_mut(lane_index)
428 .and_then(|lane| lane.0.get_mut(slot))
429 else {
430 return false;
431 };
432
433 *target = position;
434 true
435}
436
437#[inline]
439const fn lane_position(position: usize) -> (usize, usize) {
440 (position / LANE, position % LANE)
441}
442
443#[inline]
448fn visible_slice<T>(values: &[T], len: u32) -> &[T] {
449 let Ok(len) = usize::try_from(len) else {
450 return &[];
451 };
452
453 match values.get(..len) {
454 Some(values) => values,
455 None => &[],
456 }
457}
458
459#[inline]
464fn visible_mut_slice<T>(values: &mut [T], len: u32) -> &mut [T] {
465 let Ok(len) = usize::try_from(len) else {
466 return &mut [];
467 };
468
469 match values.get_mut(..len) {
470 Some(values) => values,
471 None => &mut [],
472 }
473}
474
475#[inline]
477fn usize_range(range: Range<u32>) -> Option<Range<usize>> {
478 let start = usize::try_from(range.start).ok()?;
479 let end = usize::try_from(range.end).ok()?;
480
481 Some(start..end)
482}
483
484#[cfg(test)]
485#[path = "storage_tests.rs"]
486mod tests;