1use crate::internal::Sealed;
2use std::hash::Hash;
3
4pub unsafe trait RecordIndex: Sealed + Eq + Copy + Send + Sync + Ord + Hash {
20 fn contains_bounds(container: &Bounds<Self>, bounds: &Bounds<Self>) -> bool;
24
25 fn in_bounds(&self, bounds: &Bounds<Self>) -> bool;
27
28 fn enclose_index(bounds: &mut Bounds<Self>, index: Self);
30
31 fn empty_bounds() -> Bounds<Self>;
33
34 fn bounds_for_index(index: Self) -> Bounds<Self>;
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub struct Bounds<I> {
56 pub offset: I,
58 pub extent: I,
60}
61
62impl<I> Bounds<I> {
63 pub fn zip<I2>(self, other: Bounds<I2>) -> Bounds<(I, I2)> {
65 Bounds {
66 offset: (self.offset, other.offset),
67 extent: (self.extent, other.extent),
68 }
69 }
70}
71
72impl<I: RecordIndex> Bounds<I> {
73 pub fn contains_bounds(&self, other: &Bounds<I>) -> bool {
75 I::contains_bounds(self, other)
76 }
77
78 pub fn contains_index(&self, index: I) -> bool {
80 index.in_bounds(self)
81 }
82
83 pub fn enclose_index(&mut self, index: I) {
86 I::enclose_index(self, index)
87 }
88
89 pub fn new_empty() -> Self {
91 I::empty_bounds()
92 }
93
94 pub fn bounds_for_index(index: I) -> Self {
96 I::bounds_for_index(index)
97 }
98}
99
100macro_rules! impl_single_dim_index {
101 ($ty:ty) => {
102 unsafe impl RecordIndex for $ty {
103 #[inline]
104 fn contains_bounds(container: &Bounds<Self>, bounds: &Bounds<Self>) -> bool {
105 let left_contained = container.offset <= bounds.offset;
106 let right_contained =
107 bounds.offset + bounds.extent <= container.offset + container.extent;
108 left_contained && right_contained
109 }
110
111 #[inline]
112 fn in_bounds(&self, bounds: &Bounds<Self>) -> bool {
113 let Bounds { offset, extent } = *bounds;
114 let i = *self;
115 offset <= i && i < (offset + extent)
116 }
117
118 #[inline]
119 fn enclose_index(bounds: &mut Bounds<Self>, index: Self) {
120 let new_offset = Self::min(bounds.offset, index);
121 bounds.offset = new_offset;
122 bounds.extent = Self::max(bounds.extent, index - new_offset + 1)
123 }
124
125 #[inline]
126 fn empty_bounds() -> Bounds<Self> {
127 Bounds {
128 offset: 0,
129 extent: 0,
130 }
131 }
132
133 #[inline]
134 fn bounds_for_index(index: Self) -> Bounds<Self> {
135 Bounds {
136 offset: index,
137 extent: 1,
138 }
139 }
140 }
141 };
142}
143
144impl_single_dim_index!(usize);
145
146#[cfg(any(target_pointer_width = "32", target_pointer_width = "64",))]
147impl_single_dim_index!(u32);
148
149#[cfg(any(target_pointer_width = "64"))]
150impl_single_dim_index!(u64);
151
152macro_rules! join_expressions {
154 ($separator:tt; $token_head:expr, $($token_tail:expr),*) => {
155 $token_head $($separator $token_tail)*
156 }
157}
158
159macro_rules! impl_tuple_index {
161 (($($idx_type:tt),*), ($($idx:tt),*)) => {
162 unsafe impl<$($idx_type: RecordIndex),*> RecordIndex for ($($idx_type),*) {
163 #[inline]
164 fn contains_bounds(container: &Bounds<Self>, bounds: &Bounds<Self>) -> bool {
165 let container_bounds = (
167 $(Bounds { offset: container.offset.$idx, extent: container.extent.$idx }),*
168 );
169 let bounds = (
170 $(Bounds { offset: bounds.offset.$idx, extent: bounds.extent.$idx }),*
171 );
172 join_expressions!(
175 &&;
176 $($idx_type::contains_bounds(&container_bounds.$idx, &bounds.$idx)),*
177 )
178 }
179
180 #[inline]
181 fn in_bounds(&self, bounds: &Bounds<Self>) -> bool {
182 let bounds = (
184 $(Bounds { offset: bounds.offset.$idx, extent: bounds.extent.$idx }),*
185 );
186 join_expressions!(
188 &&;
189 $(self.$idx.in_bounds(&bounds.$idx)),*
190 )
191 }
192
193 #[inline]
194 fn enclose_index(bounds: &mut Bounds<Self>, index: Self) {
195 let mut bounds_1d = (
197 $(Bounds { offset: bounds.offset.$idx, extent: bounds.extent.$idx }),*
198 );
199 $(bounds_1d.$idx.enclose_index(index.$idx);)*
201
202 $(bounds.offset.$idx = bounds_1d.$idx.offset;)*
204 $(bounds.extent.$idx = bounds_1d.$idx.extent;)*
205 }
206
207 #[inline]
208 fn empty_bounds() -> Bounds<Self> {
209 let bounds_1d = ($($idx_type::empty_bounds()),*);
211
212 Bounds {
214 offset: ($(bounds_1d.$idx.offset),*),
215 extent: ($(bounds_1d.$idx.offset),*)
216 }
217 }
218
219 #[inline]
220 fn bounds_for_index(index: Self) -> Bounds<Self> {
221 let bounds_1d = ($($idx_type::bounds_for_index(index.$idx)),*);
223
224 Bounds {
226 offset: ($(bounds_1d.$idx.offset),*),
227 extent: ($(bounds_1d.$idx.offset),*)
228 }
229 }
230 }
231 };
232}
233
234impl_tuple_index!((I0, I1), (0, 1));
235impl_tuple_index!((I0, I1, I2), (0, 1, 2));
236impl_tuple_index!((I0, I1, I2, I3), (0, 1, 2, 3));
237impl_tuple_index!((I0, I1, I2, I3, I4), (0, 1, 2, 3, 4));
238
239#[cfg(test)]
240mod tests {
241 use crate::{Bounds, RecordIndex};
242
243 #[rustfmt::skip]
244 #[test]
245 fn usize_in_bounds() {
246 assert!(0usize.in_bounds(&Bounds { offset: 0, extent: 1 }));
248 assert!(1usize.in_bounds(&Bounds { offset: 1, extent: 1 }));
249 assert!(1usize.in_bounds(&Bounds { offset: 1, extent: 1 }));
250 assert!(1usize.in_bounds(&Bounds { offset: 0, extent: 2 }));
251
252 assert!(!0usize.in_bounds(&Bounds { offset: 0, extent: 0 }));
254 assert!(!1usize.in_bounds(&Bounds { offset: 0, extent: 0 }));
255 assert!(!1usize.in_bounds(&Bounds { offset: 0, extent: 1 }));
256 }
257
258 #[rustfmt::skip]
259 #[test]
260 fn usize_2dim_in_bounds() {
261 let bounds_zero_extent = Bounds { offset: (0, 0), extent: (0, 0) };
263 assert!(!(0usize, 0usize).in_bounds(&bounds_zero_extent)); assert!(!(1usize, 1usize).in_bounds(&bounds_zero_extent)); let bounds_normal = Bounds { offset: (0, 0), extent: (2, 2) };
268 assert!((0usize, 0usize).in_bounds(&bounds_normal)); assert!((1usize, 1usize).in_bounds(&bounds_normal)); assert!(!(2usize, 2usize).in_bounds(&bounds_normal)); let bounds_offset = Bounds { offset: (1, 1), extent: (2, 2) };
274 assert!(!(0usize, 0usize).in_bounds(&bounds_offset)); assert!((1usize, 1usize).in_bounds(&bounds_offset)); assert!((2usize, 2usize).in_bounds(&bounds_offset)); assert!(!(3usize, 3usize).in_bounds(&bounds_offset)); let bounds_large = Bounds { offset: (0, 0), extent: (5, 5) };
281 assert!((0usize, 0usize).in_bounds(&bounds_large)); assert!((4usize, 4usize).in_bounds(&bounds_large)); assert!(!(5usize, 5usize).in_bounds(&bounds_large)); }
285
286 #[rustfmt::skip]
287 #[test]
288 fn usize_3dim_in_bounds() {
289 let bounds_zero_extent = Bounds { offset: (0, 0, 0), extent: (0, 0, 0) };
291 assert!(!(0usize, 0usize, 0usize).in_bounds(&bounds_zero_extent)); assert!(!(1usize, 1usize, 1usize).in_bounds(&bounds_zero_extent)); let bounds_normal = Bounds { offset: (0, 0, 0), extent: (3, 3, 3) };
296 assert!((0usize, 0usize, 0usize).in_bounds(&bounds_normal)); assert!((1usize, 1usize, 1usize).in_bounds(&bounds_normal)); assert!((2usize, 2usize, 2usize).in_bounds(&bounds_normal)); assert!(!(3usize, 3usize, 3usize).in_bounds(&bounds_normal)); let bounds_offset = Bounds { offset: (1, 1, 1), extent: (2, 2, 2) };
303 assert!(!(0usize, 0usize, 0usize).in_bounds(&bounds_offset)); assert!((1usize, 1usize, 1usize).in_bounds(&bounds_offset)); assert!((2usize, 2usize, 2usize).in_bounds(&bounds_offset)); assert!(!(3usize, 3usize, 3usize).in_bounds(&bounds_offset)); let bounds_large = Bounds { offset: (0, 0, 0), extent: (5, 5, 5) };
310 assert!((0usize, 0usize, 0usize).in_bounds(&bounds_large)); assert!((4usize, 4usize, 4usize).in_bounds(&bounds_large)); assert!(!(5usize, 5usize, 5usize).in_bounds(&bounds_large)); }
314
315 #[rustfmt::skip]
316 #[test]
317 fn usize_contains_bounds() {
318 assert!(usize::contains_bounds(&Bounds { offset: 0, extent: 1 },
320 &Bounds { offset: 0, extent: 1 }));
321
322 assert!(usize::contains_bounds(&Bounds { offset: 0, extent: 5 },
324 &Bounds { offset: 1, extent: 3 }));
325
326 assert!(!usize::contains_bounds(&Bounds { offset: 1, extent: 3 },
328 &Bounds { offset: 0, extent: 5 }));
329
330 assert!(!usize::contains_bounds(&Bounds { offset: 0, extent: 3 },
332 &Bounds { offset: 2, extent: 2 }));
333
334 assert!(!usize::contains_bounds(&Bounds { offset: 0, extent: 2 },
336 &Bounds { offset: 3, extent: 2 }));
337
338 assert!(!usize::contains_bounds(&Bounds { offset: 0, extent: 2 },
340 &Bounds { offset: 2, extent: 1 }));
341
342 assert!(usize::contains_bounds(&Bounds { offset: 0, extent: 5 },
344 &Bounds { offset: 1, extent: 1 }));
345
346 assert!(usize::contains_bounds(&Bounds { offset: 0, extent: 4 },
348 &Bounds { offset: 0, extent: 4 }));
349 }
350
351 #[rustfmt::skip]
352 #[test]
353 fn usize_2dim_contains_bounds() {
354 assert!(<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (0, 0) },
356 &Bounds { offset: (0, 0), extent: (0, 0) }));
357 assert!(<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (1, 1) },
358 &Bounds { offset: (0, 0), extent: (1, 1) }));
359
360 assert!(<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (3, 3) },
362 &Bounds { offset: (1, 1), extent: (1, 1) }));
363 assert!(<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (5, 5) },
364 &Bounds { offset: (1, 1), extent: (3, 3) }));
365
366 assert!(!<(usize, usize)>::contains_bounds(&Bounds { offset: (1, 1), extent: (3, 3) },
368 &Bounds { offset: (0, 0), extent: (2, 2) }));
369
370 assert!(!<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (2, 2) },
372 &Bounds { offset: (1, 1), extent: (2, 2) }));
373
374 assert!(!<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (1, 1) },
376 &Bounds { offset: (2, 2), extent: (1, 1) }));
377
378 assert!(!<(usize, usize)>::contains_bounds(&Bounds { offset: (0, 0), extent: (2, 2) },
380 &Bounds { offset: (2, 2), extent: (1, 1) }));
381 }
382
383 #[rustfmt::skip]
384 #[test]
385 fn usize_3dim_contains_bounds() {
386 assert!(<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (0, 0, 0) },
388 &Bounds { offset: (0, 0, 0), extent: (0, 0, 0) }));
389 assert!(<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (1, 1, 1) },
390 &Bounds { offset: (0, 0, 0), extent: (1, 1, 1) }));
391
392 assert!(<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (3, 3, 3) },
394 &Bounds { offset: (1, 1, 1), extent: (1, 1, 1) }));
395 assert!(<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (5, 5, 5) },
396 &Bounds { offset: (1, 1, 1), extent: (3, 3, 3) }));
397
398 assert!(!<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (1, 1, 1), extent: (4, 4, 4) },
400 &Bounds { offset: (0, 0, 0), extent: (3, 3, 3) }));
401
402 assert!(!<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (2, 2, 2) },
404 &Bounds { offset: (1, 1, 1), extent: (2, 2, 2) }));
405
406 assert!(!<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (1, 1, 1) },
408 &Bounds { offset: (2, 2, 2), extent: (1, 1, 1) }));
409
410 assert!(!<(usize, usize, usize)>::contains_bounds(&Bounds { offset: (0, 0, 0), extent: (2, 2, 2) },
412 &Bounds { offset: (2, 2, 2), extent: (1, 1, 1) }));
413 }
414}