lzma_rs/util/
vec2d.rs

1use std::ops::{Index, IndexMut};
2
3/// A 2 dimensional matrix in row-major order backed by a contiguous slice.
4#[derive(Debug)]
5pub struct Vec2D<T> {
6    data: Box<[T]>,
7    cols: usize,
8}
9
10impl<T> Vec2D<T> {
11    /// Initialize a grid of size (`rows`, `cols`) with the given data element.
12    pub fn init(data: T, size: (usize, usize)) -> Vec2D<T>
13    where
14        T: Clone,
15    {
16        let (rows, cols) = size;
17        let len = rows
18            .checked_mul(cols)
19            .unwrap_or_else(|| panic!("{} rows by {} cols exceeds usize::MAX", rows, cols));
20        Vec2D {
21            data: vec![data; len].into_boxed_slice(),
22            cols,
23        }
24    }
25
26    /// Fills the grid with elements by cloning `value`.
27    pub fn fill(&mut self, value: T)
28    where
29        T: Clone,
30    {
31        self.data.fill(value)
32    }
33}
34
35impl<T> Index<usize> for Vec2D<T> {
36    type Output = [T];
37
38    #[inline]
39    fn index(&self, row: usize) -> &Self::Output {
40        let start_row = row
41            .checked_mul(self.cols)
42            .unwrap_or_else(|| panic!("{} row by {} cols exceeds usize::MAX", row, self.cols));
43        &self.data[start_row..start_row + self.cols]
44    }
45}
46
47impl<T> IndexMut<usize> for Vec2D<T> {
48    #[inline]
49    fn index_mut(&mut self, row: usize) -> &mut Self::Output {
50        let start_row = row
51            .checked_mul(self.cols)
52            .unwrap_or_else(|| panic!("{} row by {} cols exceeds usize::MAX", row, self.cols));
53        &mut self.data[start_row..start_row + self.cols]
54    }
55}
56
57#[cfg(test)]
58mod test {
59    use super::*;
60
61    #[test]
62    fn init() {
63        let vec2d = Vec2D::init(1, (2, 3));
64        assert_eq!(vec2d[0], [1, 1, 1]);
65        assert_eq!(vec2d[1], [1, 1, 1]);
66    }
67
68    #[test]
69    #[should_panic]
70    fn init_overflow() {
71        Vec2D::init(1, (usize::MAX, usize::MAX));
72    }
73
74    #[test]
75    fn fill() {
76        let mut vec2d = Vec2D::init(0, (2, 3));
77        vec2d.fill(7);
78        assert_eq!(vec2d[0], [7, 7, 7]);
79        assert_eq!(vec2d[1], [7, 7, 7]);
80    }
81
82    #[test]
83    fn index() {
84        let vec2d = Vec2D {
85            data: vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(),
86            cols: 2,
87        };
88        assert_eq!(vec2d[0], [0, 1]);
89        assert_eq!(vec2d[1], [2, 3]);
90        assert_eq!(vec2d[2], [4, 5]);
91        assert_eq!(vec2d[3], [6, 7]);
92    }
93
94    #[test]
95    fn indexmut() {
96        let mut vec2d = Vec2D {
97            data: vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(),
98            cols: 2,
99        };
100
101        vec2d[1][1] = 9;
102        assert_eq!(vec2d[0], [0, 1]);
103        // (1, 1) should be 9.
104        assert_eq!(vec2d[1], [2, 9]);
105        assert_eq!(vec2d[2], [4, 5]);
106        assert_eq!(vec2d[3], [6, 7]);
107    }
108
109    #[test]
110    #[should_panic]
111    fn index_out_of_bounds() {
112        let vec2d = Vec2D::init(1, (2, 3));
113        let _x = vec2d[2][3];
114    }
115
116    #[test]
117    #[should_panic]
118    fn index_out_of_bounds_vec_edge() {
119        let vec2d = Vec2D::init(1, (2, 3));
120        let _x = vec2d[1][3];
121    }
122
123    #[test]
124    #[should_panic]
125    fn index_column_out_of_bounds() {
126        let vec2d = Vec2D::init(1, (2, 3));
127        let _x = vec2d[0][3];
128    }
129
130    #[test]
131    #[should_panic]
132    fn index_row_out_of_bounds() {
133        let vec2d = Vec2D::init(1, (2, 3));
134        let _x = vec2d[2][0];
135    }
136
137    #[test]
138    #[should_panic]
139    fn index_mul_overflow() {
140        // Matrix with 4 columns.
141        let matrix = Vec2D::init(0, (3, 4));
142        // 2^{usize.numbits() - 2}.
143        let row = (usize::MAX / 4) + 1;
144        // Returns the same as matrix[0] if overflow is not caught.
145        let _ = matrix[row];
146    }
147
148    #[test]
149    #[should_panic]
150    fn index_add_overflow() {
151        // Matrix with 5 columns.
152        let matrix = Vec2D::init(0, (3, 5));
153        // Somehow, as long as numbits(usize) is a multiple of 4, then 5 divides usize::MAX.
154        // This is clear in hexadecimal: usize::MAX is 0xFFF...F and usize::MAX / 5 is 0x333...3.
155        let row = usize::MAX / 5;
156        // This will therefore try to index data[usize::MAX..4].
157        let _ = matrix[row];
158    }
159
160    #[test]
161    #[should_panic]
162    fn indexmut_out_of_bounds() {
163        let mut vec2d = Vec2D::init(1, (2, 3));
164        vec2d[2][3] = 0;
165    }
166
167    #[test]
168    #[should_panic]
169    fn indexmut_out_of_bounds_vec_edge() {
170        let mut vec2d = Vec2D::init(1, (2, 3));
171        vec2d[1][3] = 0;
172    }
173
174    #[test]
175    #[should_panic]
176    fn indexmut_column_out_of_bounds() {
177        let mut vec2d = Vec2D::init(1, (2, 3));
178        vec2d[0][3] = 0;
179    }
180
181    #[test]
182    #[should_panic]
183    fn indexmut_row_out_of_bounds() {
184        let mut vec2d = Vec2D::init(1, (2, 3));
185        vec2d[2][0] = 0;
186    }
187
188    #[test]
189    #[should_panic]
190    fn indexmut_mul_overflow() {
191        // Matrix with 4 columns.
192        let mut matrix = Vec2D::init(0, (3, 4));
193        // 2^{usize.numbits() - 2}.
194        let row = (usize::MAX / 4) + 1;
195        // Returns the same as matrix[0] if overflow is not caught.
196        matrix[row][0] = 9;
197    }
198
199    #[test]
200    #[should_panic]
201    fn indexmut_add_overflow() {
202        // Matrix with 5 columns.
203        let mut matrix = Vec2D::init(0, (3, 5));
204        // Somehow, as long as numbits(usize) is a multiple of 4, then 5 divides usize::MAX.
205        // This is clear in hexadecimal: usize::MAX is 0xFFF...F and usize::MAX / 5 is 0x333...3.
206        let row = usize::MAX / 5;
207        // This will therefore try to index data[usize::MAX..4].
208        matrix[row][0] = 9;
209    }
210}