vec2dim/
vec2d.rs

1
2/// A two-dimensional array. Unlike a standard vector, `Vec2d` must maintain a constant
3/// number of elements equal to its number of rows times its number of columns.
4#[derive (Clone)]
5pub struct Vec2d<T> {
6    data: Vec<T>,
7    width: usize,
8}
9
10
11impl<T: Default> Vec2d<T> {
12    /// Creates a new `Vec2d<T>` and initializes all the values to `T::default()`.
13    pub fn new_with_default(rows: usize, cols: usize) -> Vec2d<T> {
14        Vec2d::new_empty(rows, cols).initialize_to_default()
15    }
16
17    /// Adds a new row to the vector and sets all elements of that row to `T::default()`.
18    /// If the array is empty, creates a row of one element.
19    pub fn add_row_of_default(&mut self) {
20        // pushes a number of elements to data equal to the width
21        // width does not change unless array was empty
22        if self.width == 0 { self.width += 1; }
23        let size = self.count() + self.width;
24        while self.data.len() < size {
25            self.data.push(T::default());
26        }
27    }
28
29    /// Adds a new column to the array and sets all elements of the column to `T::default()`.
30    pub fn add_col_of_default(&mut self) {
31        // inserts a default item at the position representing the end of each row
32        // note that this position shifts as elements are added
33        let new_width = self.width + 1;
34        let mut idx = self.width;
35        for _row in 0..self.count_rows() {
36            self.data.insert(idx, T::default());
37            idx += new_width;
38        }
39        self.width = new_width;
40    }
41
42    // private methods
43    fn initialize_to_default(mut self) -> Vec2d<T> {
44        let size = self.data.capacity();
45        while self.data.len() < size {
46            self.data.push(T::default());
47        }
48        self
49    }
50}
51
52impl<T: Copy> Vec2d<T> {
53    /// Creates a new `Vec2d<T>` and initializes all the values to a copy of `val`.
54    pub fn new_with_value(rows: usize, cols: usize, val:T) -> Vec2d<T> {
55        Vec2d::new_empty(rows, cols).initialize_to_value(val)
56    }
57
58    /// Creates a new `Vec2d<T>` from an array slice.
59    /// The slice must have a length that is divisible by `cols` in order to fill the new array.
60    /// The array is filled left to right, top to bottom.
61    pub fn from(width: usize, arr: &[T]) -> Vec2d<T> {
62        let size = arr.len();
63        assert_eq!(size % width, 0);
64        let mut data: Vec<T> = Vec::with_capacity(size);
65        for idx in 0..size {
66            data.push(arr[idx]);
67        }
68        Vec2d {
69            data,
70            width,
71        }
72    }
73
74    /// Inserts a column of data before the columns indicated by `index`.
75    pub fn insert_col(&mut self, index: usize, data: &[T]) {
76        let size: usize = data.len();
77        // Data must have same size as array height
78        if self.width == 0 {
79            self.width = 1;
80            for item in data {
81                self.data.push(*item);
82            }
83        }
84        else {
85            assert_eq!(size, self.count_rows());
86            let mut idx = index;
87            self.width += 1;
88            for row in 0..size {
89                self.data.insert(idx, data[row]);
90                idx += self.width;
91            }
92        }
93    }
94
95    /// Inserts a row of data before the row indicated by `index`. If `index` is `0`, calls
96    /// `push_row(data)`.
97    pub fn insert_row(&mut self, index: usize, data: &[T]) {
98        // If array isn't empty, row length must match width
99        // if it is empty, add the entire data vector as a new row
100        // and set width to the length of the data
101        if self.width > 0 {
102            assert_eq!(self.width, data.len());
103            // currently just pushes items one by one
104            // TODO: implement this more efficiently
105            let mut idx = self.width * index;
106            for item in data {
107                self.data.insert(idx, *item);
108                idx += 1;
109            }
110        }
111        else { self.push_row(data); }
112    }
113
114    /// Adds a new column of data to the right edge of the array. The length of the slice `data`
115    /// must be exactly equal to the height of the array.
116    pub fn push_col(&mut self, data: &[T]) {
117        self.insert_col(self.count_cols(), data);
118    }
119
120    /// Adds a row of data at the bottom of the array. The length of the slice `data` must be
121    /// exactly equal to the array width or the method will panic.
122    pub fn push_row(&mut self, data: &[T]) {
123        // If array isn't empty, row length must match width
124        // if it is empty, add the entire data vector as a new row
125        // and set width to the length of the data
126        if self.width > 0 { assert_eq!(self.width, data.len()); }
127        else { self.width = data.len(); }
128        for item in data {
129            self.data.push(*item);
130        }
131    }
132
133    // private
134    fn initialize_to_value(mut self, val: T) -> Vec2d<T> {
135        let size = self.data.capacity();
136        while self.data.len() < size {
137            self.data.push(val);
138        }
139        self
140    }
141}
142
143impl<T: PartialEq> Vec2d<T> {
144
145    /// Checks if `val` is equivalent to any of the elements in the array.
146    /// Returns `true` if there is a match, `false` otherwise.
147    pub fn contains(&self, val: &T) -> bool {
148        for idx in 0..self.count() {
149            if *val == self.data[idx] { return true; }
150        }
151        false
152    }
153}
154
155
156impl<T> Vec2d<T> {
157    /// Creates a new `Vec2d<T>` with no rows, columns, or elements.
158    pub fn new() -> Vec2d<T> {
159        // a vector without any data has width 0
160        Vec2d {
161            data: Vec::new(),
162            width: 0,
163        }
164    }
165
166    /// Creates a new `Vec2d<T>` and initializes its values from `initializer`,
167    /// a passed-in function that takes the current cell index (row and column)
168    /// and returns a `T`.
169    pub fn from_fn(rows: usize, cols: usize, initializer: &dyn Fn(usize, usize) -> T) -> Vec2d<T> {
170        Vec2d::new_empty(rows, cols).initialize_from_fn(initializer)
171    }
172
173    /// Returns a raw pointer to the underlying vector's buffer.
174    pub fn as_ptr(&self) -> *const T {
175        self.data.as_ptr()
176    }
177
178    /// Returns a reference to the underlying vector.
179    pub fn as_vec(&self) -> &Vec<T> {
180        &self.data
181    }
182
183    /// Returns the number of elements in the array.
184    /// Equal to the number of rows times the number of columns.
185    pub fn count(&self) -> usize {
186        self.width * self.count_rows()
187    }
188
189    /// Returns the number of columns of the array.
190    pub fn count_cols(&self) -> usize {
191        self.width
192    }
193
194    /// Returns the number of rows of the array.
195    pub fn count_rows(&self) -> usize {
196        if self.width == 0 { 0 } else { self.data.len() / self.width }
197    }
198
199    /// Returns the dimensions of the array as a tuple of (row, col).
200    pub fn size(&self) -> (usize, usize) {
201        (self.count_rows(), self.count_cols())
202    }
203
204    // private
205    fn new_empty(rows: usize, cols: usize) -> Vec2d<T> {
206        Vec2d {
207            data: Vec::with_capacity(rows*cols),
208            width: cols,
209        }
210    }
211
212    fn initialize_from_fn(mut self, initializer: &dyn Fn(usize, usize) -> T) -> Vec2d<T> {
213        let size = self.data.capacity();
214        for idx in 0..size {
215            let row = idx / self.width;
216            let col = idx - (row * self.width);
217            self.data.push(initializer(row, col));
218        }
219        self
220    }
221}
222
223impl<T> std::ops::Index<usize> for Vec2d<T> {
224    type Output = [T];
225
226    fn index(&self, row: usize) -> &[T] {
227        let start = row * self.width;
228        let end = start + self.width;
229        &self.data[start..end]
230    }
231}
232
233impl<T> std::ops::IndexMut<usize> for Vec2d<T> {
234    fn index_mut(&mut self, row: usize) -> &mut Self::Output {
235        let start = row * self.width;
236        let end = start + self.width;
237        &mut self.data[start..end]
238    }
239}
240
241#[cfg(test)]
242mod tests {
243    use super::*;
244
245    #[test]
246    fn check_initializer() {
247        let v = Vec2d::from_fn(3, 3, &|row, col| row + col);
248        for idx in 0..v.count() {
249            let row = idx / v.count_cols();
250            let col = idx - (row * v.count_cols());
251            assert_eq!(v[row][col], row+col);
252        }
253    }
254
255    #[test]
256    #[should_panic]
257    fn panics_on_mismatched_arr_size() {
258        let arr: [i32;4] = [1,2,3,4];
259        let slc: &[i32] = &arr[0..3];
260        let _v: Vec2d<i32> = Vec2d::from(2, slc);
261        let arr: [i32;5] = [1,2,3,4,5];
262        let _v = Vec2d::from(2, &arr);
263    }
264
265    #[test]
266    fn build_from_data() {
267        let data: [i32;12] = [1,2,3,4,5,6,7,8,9,10,11,12];
268        for divs in 1..13 {
269            if 12 % divs == 0 {
270                let _v = Vec2d::from(divs, &data);
271                for row in 0.._v.count_rows() {
272                    for col in 0.._v.count_cols() {
273                        let idx = row * _v.count_cols() + col;
274                        assert_eq!(data[idx], _v[row][col]);
275                    }
276                }
277            }
278        }
279    }
280
281    #[test]
282    fn build_from_defaults() {
283        type DataType = i32;
284        let mut v:Vec2d<DataType> = Vec2d::new();
285        assert_eq!(v.count(), 0);
286        v.add_row_of_default();
287        assert_eq!(v.count_rows(), 1);
288        v.add_row_of_default();
289        v.add_col_of_default();
290        assert_eq!(v.count(), 4);
291        assert_eq!(v.count_rows(), 2);
292        assert_eq!(v.count_cols(), 2);
293    }
294
295    #[test]
296    fn test_data_pushing() {
297        type DataType = i32;
298        let mut v: Vec2d<DataType> = Vec2d::new();
299        let data = [1,2,3,4,5,6,7,8,9,10,11,12];
300        v.push_row(&data[0..1]);
301        v.push_col(&data[1..2]);
302        v.push_row(&data[2..4]);
303        v.push_row(&data[4..6]);
304        v.push_col(&data[6..9]);
305        v.push_col(&data[9..12]);
306        assert_eq!(v.count(), 12);
307        assert_eq!(v.count_rows(), 3);
308        assert_eq!(v.count_cols(), 4);
309        let answers = [1,2,7,10,3,4,8,11,5,6,9,12];
310        let mut idx: usize = 0;
311        for row in 0..v.count_rows() {
312            for col in 0..v.count_cols() {
313                assert_eq!(v[row][col], answers[idx]);
314                idx += 1;
315            }
316        }
317    }
318
319    #[test]
320    fn test_data_insertion() {
321        type DataType = i32;
322        let mut v: Vec2d<DataType> = Vec2d::new();
323        let data = [1,2,3,4,5,6,7,8,9,10,11,12];
324        v.insert_row(0,&data[0..1]);
325        v.insert_col(0,&data[1..2]);
326        v.insert_row(1,&data[2..4]);
327        v.insert_row(1, &data[4..6]);
328        v.insert_col(1,&data[6..9]);
329        v.insert_col(3,&data[9..12]);
330        assert_eq!(v.count(), 12);
331        assert_eq!(v.count_rows(), 3);
332        assert_eq!(v.count_cols(), 4);
333        let answers = [2,7,1,10,5,8,6,11,3,9,4,12];
334        let mut idx: usize = 0;
335        for row in 0..v.count_rows() {
336            for col in 0..v.count_cols() {
337                assert_eq!(v[row][col], answers[idx]);
338                idx += 1;
339            }
340        }
341    }
342}