1use core::marker::PhantomData;
2use core::ops::Range;
3
4use crate::Matrix;
5use crate::bitrev::BitReversibleMatrix;
6
7#[derive(Clone)]
13pub struct HorizontallyTruncated<T, Inner> {
14 inner: Inner,
16 column_range: Range<usize>,
18 _phantom: PhantomData<T>,
20}
21
22impl<T, Inner: Matrix<T>> HorizontallyTruncated<T, Inner>
23where
24 T: Send + Sync + Clone,
25{
26 pub fn new(inner: Inner, truncated_width: usize) -> Option<Self> {
36 Self::new_with_range(inner, 0..truncated_width)
37 }
38
39 pub fn new_with_range(inner: Inner, column_range: Range<usize>) -> Option<Self> {
47 let valid = column_range.start <= column_range.end && column_range.end <= inner.width();
51 valid.then(|| Self {
52 inner,
53 column_range,
54 _phantom: PhantomData,
55 })
56 }
57}
58
59impl<T, Inner> Matrix<T> for HorizontallyTruncated<T, Inner>
60where
61 T: Send + Sync + Clone,
62 Inner: Matrix<T>,
63{
64 #[inline(always)]
66 fn width(&self) -> usize {
67 self.column_range.len()
68 }
69
70 #[inline(always)]
72 fn height(&self) -> usize {
73 self.inner.height()
74 }
75
76 #[inline(always)]
77 unsafe fn get_unchecked(&self, r: usize, c: usize) -> T {
78 unsafe {
79 self.inner.get_unchecked(r, self.column_range.start + c)
83 }
84 }
85
86 unsafe fn row_unchecked(
87 &self,
88 r: usize,
89 ) -> impl IntoIterator<Item = T, IntoIter = impl Iterator<Item = T> + Send + Sync> {
90 unsafe {
91 self.inner
93 .row_subseq_unchecked(r, self.column_range.start, self.column_range.end)
94 }
95 }
96
97 unsafe fn row_subseq_unchecked(
98 &self,
99 r: usize,
100 start: usize,
101 end: usize,
102 ) -> impl IntoIterator<Item = T, IntoIter = impl Iterator<Item = T> + Send + Sync> {
103 unsafe {
104 self.inner.row_subseq_unchecked(
108 r,
109 self.column_range.start + start,
110 self.column_range.start + end,
111 )
112 }
113 }
114
115 unsafe fn row_subslice_unchecked(
116 &self,
117 r: usize,
118 start: usize,
119 end: usize,
120 ) -> impl core::ops::Deref<Target = [T]> {
121 unsafe {
122 self.inner.row_subslice_unchecked(
126 r,
127 self.column_range.start + start,
128 self.column_range.start + end,
129 )
130 }
131 }
132}
133
134impl<T: Clone + Send + Sync, Inner: BitReversibleMatrix<T>> BitReversibleMatrix<T>
135 for HorizontallyTruncated<T, Inner>
136{
137 type BitRev = HorizontallyTruncated<T, Inner::BitRev>;
138
139 fn bit_reverse_rows(self) -> Self::BitRev {
140 HorizontallyTruncated {
141 inner: self.inner.bit_reverse_rows(),
142 column_range: self.column_range,
143 _phantom: PhantomData,
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use alloc::vec;
151 use alloc::vec::Vec;
152
153 use super::*;
154 use crate::dense::RowMajorMatrix;
155
156 #[test]
157 fn test_truncate_width_by_one() {
158 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 4);
163
164 let truncated = HorizontallyTruncated::new(inner, 3).unwrap();
166
167 assert_eq!(truncated.width(), 3);
169
170 assert_eq!(truncated.height(), 3);
172
173 assert_eq!(truncated.get(0, 0), Some(1)); assert_eq!(truncated.get(1, 1), Some(6)); unsafe {
177 assert_eq!(truncated.get_unchecked(0, 1), 2); assert_eq!(truncated.get_unchecked(2, 2), 11); }
180
181 let row0: Vec<_> = truncated.row(0).unwrap().into_iter().collect();
183 assert_eq!(row0, vec![1, 2, 3]);
184 unsafe {
185 let row1: Vec<_> = truncated.row_unchecked(1).into_iter().collect();
187 assert_eq!(row1, vec![5, 6, 7]);
188
189 let row3_subset: Vec<_> = truncated
191 .row_subseq_unchecked(2, 1, 2)
192 .into_iter()
193 .collect();
194 assert_eq!(row3_subset, vec![10]);
195 }
196
197 unsafe {
198 let row1 = truncated.row_slice(1).unwrap();
199 assert_eq!(&*row1, &[5, 6, 7]);
200
201 let row2 = truncated.row_slice_unchecked(2);
202 assert_eq!(&*row2, &[9, 10, 11]);
203
204 let row0_subslice = truncated.row_subslice_unchecked(0, 0, 2);
205 assert_eq!(&*row0_subslice, &[1, 2]);
206 }
207
208 assert!(truncated.get(0, 3).is_none()); assert!(truncated.get(3, 0).is_none()); assert!(truncated.row(3).is_none()); assert!(truncated.row_slice(3).is_none()); let as_matrix = truncated.to_row_major_matrix();
215
216 let expected = RowMajorMatrix::new(vec![1, 2, 3, 5, 6, 7, 9, 10, 11], 3);
221
222 assert_eq!(as_matrix, expected);
223 }
224
225 #[test]
226 fn test_no_truncation() {
227 let inner = RowMajorMatrix::new(vec![7, 8, 9, 10], 2);
231
232 let truncated = HorizontallyTruncated::new(inner, 2).unwrap();
234
235 assert_eq!(truncated.width(), 2);
236 assert_eq!(truncated.height(), 2);
237 assert_eq!(truncated.get(0, 1).unwrap(), 8);
238 assert_eq!(truncated.get(1, 0).unwrap(), 9);
239
240 unsafe {
241 assert_eq!(truncated.get_unchecked(0, 0), 7);
242 assert_eq!(truncated.get_unchecked(1, 1), 10);
243 }
244
245 let row0: Vec<_> = truncated.row(0).unwrap().into_iter().collect();
246 assert_eq!(row0, vec![7, 8]);
247
248 let row1: Vec<_> = unsafe { truncated.row_unchecked(1).into_iter().collect() };
249 assert_eq!(row1, vec![9, 10]);
250
251 assert!(truncated.get(0, 2).is_none()); assert!(truncated.get(2, 0).is_none()); assert!(truncated.row(2).is_none()); assert!(truncated.row_slice(2).is_none()); }
256
257 #[test]
258 fn test_truncate_to_zero_width() {
259 let inner = RowMajorMatrix::new(vec![11, 12, 13], 3);
261
262 let truncated = HorizontallyTruncated::new(inner, 0).unwrap();
264
265 assert_eq!(truncated.width(), 0);
266 assert_eq!(truncated.height(), 1);
267
268 assert!(truncated.row(0).unwrap().into_iter().next().is_none());
270
271 assert!(truncated.get(0, 0).is_none()); assert!(truncated.get(1, 0).is_none()); assert!(truncated.row(1).is_none()); assert!(truncated.row_slice(1).is_none()); }
276
277 #[test]
278 fn test_invalid_truncation_width() {
279 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4], 2);
283
284 assert!(HorizontallyTruncated::new(inner, 5).is_none());
286 }
287
288 #[test]
289 fn test_column_range_middle() {
290 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 5);
295
296 let view = HorizontallyTruncated::new_with_range(inner, 1..4).unwrap();
298
299 assert_eq!(view.width(), 3);
301
302 assert_eq!(view.height(), 3);
304
305 assert_eq!(view.get(0, 0), Some(2)); assert_eq!(view.get(0, 1), Some(3)); assert_eq!(view.get(0, 2), Some(4)); assert_eq!(view.get(1, 0), Some(7)); assert_eq!(view.get(2, 2), Some(14)); unsafe {
313 assert_eq!(view.get_unchecked(1, 1), 8); assert_eq!(view.get_unchecked(2, 0), 12); }
316
317 let row0: Vec<_> = view.row(0).unwrap().into_iter().collect();
319 assert_eq!(row0, vec![2, 3, 4]);
320
321 let row1: Vec<_> = view.row(1).unwrap().into_iter().collect();
323 assert_eq!(row1, vec![7, 8, 9]);
324
325 unsafe {
326 let row2: Vec<_> = view.row_unchecked(2).into_iter().collect();
328 assert_eq!(row2, vec![12, 13, 14]);
329
330 let row1_subseq: Vec<_> = view.row_subseq_unchecked(1, 1, 3).into_iter().collect();
332 assert_eq!(row1_subseq, vec![8, 9]);
333 }
334
335 assert!(view.get(0, 3).is_none()); assert!(view.get(3, 0).is_none()); let as_matrix = view.to_row_major_matrix();
341
342 let expected = RowMajorMatrix::new(vec![2, 3, 4, 7, 8, 9, 12, 13, 14], 3);
347
348 assert_eq!(as_matrix, expected);
349 }
350
351 #[test]
352 fn test_column_range_end() {
353 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6, 7, 8], 4);
357
358 let view = HorizontallyTruncated::new_with_range(inner, 2..4).unwrap();
360
361 assert_eq!(view.width(), 2);
362 assert_eq!(view.height(), 2);
363
364 let row0: Vec<_> = view.row(0).unwrap().into_iter().collect();
366 assert_eq!(row0, vec![3, 4]);
367
368 let row1: Vec<_> = view.row(1).unwrap().into_iter().collect();
370 assert_eq!(row1, vec![7, 8]);
371
372 assert_eq!(view.get(0, 0), Some(3));
373 assert_eq!(view.get(1, 1), Some(8));
374 }
375
376 #[test]
377 fn test_column_range_single_column() {
378 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 4);
383
384 let view = HorizontallyTruncated::new_with_range(inner, 2..3).unwrap();
386
387 assert_eq!(view.width(), 1);
388 assert_eq!(view.height(), 3);
389
390 assert_eq!(view.get(0, 0), Some(3));
391 assert_eq!(view.get(1, 0), Some(7));
392 assert_eq!(view.get(2, 0), Some(11));
393
394 let row0: Vec<_> = view.row(0).unwrap().into_iter().collect();
396 assert_eq!(row0, vec![3]);
397 }
398
399 #[test]
400 fn test_column_range_empty() {
401 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6], 3);
405
406 let view = HorizontallyTruncated::new_with_range(inner, 2..2).unwrap();
408
409 assert_eq!(view.width(), 0);
410 assert_eq!(view.height(), 2);
411
412 assert!(view.row(0).unwrap().into_iter().next().is_none());
414 }
415
416 #[test]
417 fn test_invalid_column_range() {
418 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6], 3);
422
423 assert!(HorizontallyTruncated::new_with_range(inner, 1..5).is_none());
425 }
426
427 #[test]
428 fn test_inverted_column_range_is_rejected() {
429 let inner = RowMajorMatrix::new(vec![1, 2, 3, 4, 5, 6], 3);
433
434 let inverted = Range { start: 2, end: 1 };
441 assert!(HorizontallyTruncated::new_with_range(inner, inverted).is_none());
442 }
443}