dynamic_matrix/
row_major.rs

1use std::{
2    ops::{Index, IndexMut},
3    vec::Vec,
4};
5
6use crate::errors::{indexing_error::IndexingError, shape_error::ShapeError};
7
8#[macro_export]
9/// A macro to construct a DynamicMatrix
10///
11/// There are three ways to invoke this macro:
12///
13/// 1. With a single argument, the number of columns in this DynamicMatrix.
14/// ```
15/// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
16/// let mat: DynamicMatrix<isize> = dynamic_matrix!(3);
17///
18/// assert_eq!(mat.shape(), (0, 3));
19/// ```
20///
21/// 2. With a list of arguments followed the number of columns in this DynamicMatrix.
22/// ```
23/// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
24/// let mat = dynamic_matrix![1, 2, 3, 4, 5, 6, 7, 8, 9; 3];
25///
26/// assert_eq!(mat.shape(), (3, 3));
27/// assert_eq!(mat.as_slice(), [1, 2, 3, 4, 5, 6, 7, 8, 9]);
28/// ```
29///
30/// 3. A "nested array". "," seperating elements at the row level and ";" at the column level.
31/// ```
32/// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
33/// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
34///
35/// assert_eq!(mat.shape(), (3, 3));
36/// assert_eq!(mat.as_slice(), [1, 2, 3, 4, 5, 6, 7, 8, 9]);
37/// ```
38macro_rules! dynamic_matrix {
39    ($cols:expr) => {
40        $crate::DynamicMatrix::new_with_cols($cols)
41    };
42    ($($elem:expr),+; $cols:expr) => (
43            $crate::DynamicMatrix::from_boxed_slice(::std::boxed::Box::new([$($elem),+]), $cols)
44    );
45    ($($($elem:expr),+);+$(;)?) => (
46        $crate::DynamicMatrix::new([$([$($elem),+]),+])
47    )
48}
49
50#[derive(Debug, Clone)]
51/// A dynamic matrix in stored in row-major order.
52///
53/// Adding a new row is cheap while adding a new column is expensive.
54///
55/// ```
56/// use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
57///
58/// let mut mat = dynamic_matrix![
59///     1, 2;
60///     4, 5;
61/// ];
62/// // let mat: DynamicMatrix<isize> = DynamicMatrix::new([[1, 2], [4, 5]]);
63///
64/// assert_eq!(mat.shape(), (2, 2));
65///
66/// mat.push_row(vec![7, 8]).unwrap();
67/// mat.push_col(vec![3, 6, 10]).unwrap();
68///
69/// assert_eq!(mat.shape(), (3, 3));
70///
71/// assert_eq!(mat[(1, 2)], 6);
72/// mat[(2, 2)] = 9;
73///
74/// assert_eq!(mat.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
75/// ```
76pub struct DynamicMatrix<T> {
77    data: Vec<T>,
78    cols: usize,
79}
80
81impl<T> DynamicMatrix<T> {
82    /// Constructs a new DynamicMatrix from a nested array
83    ///
84    /// ```
85    /// # use dynamic_matrix::DynamicMatrix;
86    /// let mat: DynamicMatrix<isize> = DynamicMatrix::new([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);
87    ///
88    /// assert_eq!(mat.shape(), (3, 3));
89    /// assert_eq!(mat.as_slice(), [1, 2, 3, 4, 5, 6, 7, 8, 9]);
90    /// ```
91    pub fn new<const COLS: usize, const ROWS: usize>(data: [[T; COLS]; ROWS]) -> Self {
92        let cols = data[0].len();
93
94        Self {
95            data: data.into_iter().flatten().collect(),
96            cols,
97        }
98    }
99
100    /// Constructs a new empty DynamicMatrix with a set number of columns
101    ///
102    /// ```
103    /// # use dynamic_matrix::DynamicMatrix;
104    /// let mat: DynamicMatrix<isize> = DynamicMatrix::new_with_cols(3);
105    ///
106    /// assert_eq!(mat.rows(), 0);
107    /// assert_eq!(mat.cols(), 3);
108    /// ```
109    pub fn new_with_cols(cols: usize) -> Self {
110        Self {
111            data: Vec::new(),
112            cols,
113        }
114    }
115
116    /// Constructs a new DynamicMatrix and allocates enough space to accomodate a matrix of the provided shape without
117    /// reallocation
118    ///
119    /// ```
120    /// # use dynamic_matrix::DynamicMatrix;
121    /// let mat: DynamicMatrix<isize> = DynamicMatrix::with_capacity((3, 3));
122    ///
123    /// assert_eq!(mat.rows(), 0);
124    /// assert_eq!(mat.cols(), 3);
125    /// assert_eq!(mat.capacity(), 9);
126    /// ```
127    pub fn with_capacity(shape: (usize, usize)) -> Self {
128        Self {
129            data: Vec::with_capacity(shape.0 * shape.1),
130            cols: shape.1,
131        }
132    }
133
134    /// Returns the number of rows in the DynamicMatrix
135    ///
136    /// ```
137    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
138    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
139    ///
140    /// assert_eq!(mat.rows(), 3);
141    /// ```
142    pub fn rows(&self) -> usize {
143        self.data.len() / self.cols()
144    }
145
146    /// Returns the number of columns in the DynamicMatrix
147    ///
148    /// ```
149    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
150    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
151    ///
152    /// assert_eq!(mat.cols(), 3);
153    /// ```
154    pub fn cols(&self) -> usize {
155        self.cols
156    }
157
158    /// Returns a tuple containing the number of rows as the first element and number of columns as the second element
159    ///
160    /// ```
161    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
162    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
163    ///
164    /// assert_eq!(mat.shape(), (3, 3));
165    /// ```
166    pub fn shape(&self) -> (usize, usize) {
167        (self.rows(), self.cols())
168    }
169
170    /// Returns the length of the underlying Vec
171    ///
172    /// ```
173    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
174    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
175    ///
176    /// assert_eq!(mat.len(), 9);
177    pub fn len(&self) -> usize {
178        self.data.capacity()
179    }
180
181    /// Returns the capacity of the underlying Vec
182    ///
183    /// ```
184    /// # use dynamic_matrix::DynamicMatrix;
185    /// let mat: DynamicMatrix<isize> = DynamicMatrix::with_capacity((3, 3));
186    ///
187    /// assert_eq!(mat.capacity(), 9);
188    pub fn capacity(&self) -> usize {
189        self.data.capacity()
190    }
191
192    /// Appends a new row to the DynamicMatrix
193    ///
194    /// ```
195    /// # use dynamic_matrix::DynamicMatrix;
196    /// let mut mat: DynamicMatrix<isize> = DynamicMatrix::new_with_cols(3);
197    ///
198    /// mat.push_row(vec![1, 2, 3]).unwrap();
199    /// mat.push_row(vec![4, 5, 6]).unwrap();
200    /// mat.push_row(vec![7, 8, 9]).unwrap();
201    ///
202    /// assert_eq!(mat.as_slice(), [1, 2, 3, 4, 5, 6, 7, 8, 9]);
203    /// assert_eq!(mat.rows(), 3);
204    /// ```
205    ///
206    /// Trying to append a new row with unequal number of columns will return a `ShapeError`:
207    /// ```should_panic
208    /// # use dynamic_matrix::DynamicMatrix;
209    /// let mut mat: DynamicMatrix<isize> = DynamicMatrix::new_with_cols(3);
210    ///
211    /// // Trying to push a vector with length 4 into a matrix with only 3 columns
212    /// mat.push_row(vec![1, 2, 3, 4]).unwrap();
213    /// ```
214    pub fn push_row(&mut self, row: Vec<T>) -> Result<(), ShapeError> {
215        if row.len() != self.cols() {
216            Err(ShapeError::new_cols_error(self.cols(), row.len()))
217        } else {
218            self.data.extend(row.into_iter());
219            Ok(())
220        }
221    }
222
223    /// Appends a new columns to the DynamicMatrix
224    ///
225    /// ```
226    /// # use dynamic_matrix::DynamicMatrix;
227    /// let mut mat: DynamicMatrix<isize> = DynamicMatrix::new_with_cols(2);
228    ///
229    /// mat.push_row(vec![1, 2]).unwrap();
230    /// mat.push_row(vec![4, 5]).unwrap();
231    /// mat.push_row(vec![7, 8]).unwrap();
232    ///
233    /// mat.push_col(vec![3, 6, 9]).unwrap();
234    ///
235    /// assert_eq!(mat.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
236    /// assert_eq!(mat.cols(), 3);
237    /// ```
238    ///
239    /// Trying to append a new row with unequal number of columns will return a `ShapeError`:
240    /// ```should_panic
241    /// # use dynamic_matrix::DynamicMatrix;
242    /// let mut mat: DynamicMatrix<isize> = DynamicMatrix::new_with_cols(2);
243    ///
244    /// mat.push_row(vec![1, 2]).unwrap();
245    /// mat.push_row(vec![4, 5]).unwrap();
246    /// mat.push_row(vec![7, 8]).unwrap();
247    ///
248    /// // Trying to push a column with less elements than the number of rows
249    /// mat.push_col(vec![3, 6]).unwrap();
250    /// ```
251    pub fn push_col(&mut self, col: Vec<T>) -> Result<(), ShapeError> {
252        if col.len() != self.rows() {
253            Err(ShapeError::new_rows_error(self.rows(), col.len()))
254        } else {
255            for (i, e) in col.into_iter().enumerate() {
256                self.data.insert(self.cols() + self.cols() * i + i, e);
257            }
258            self.cols += 1;
259
260            Ok(())
261        }
262    }
263
264    /// Gives a raw pointer to the underlying Vec's buffer
265    ///
266    /// ```
267    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
268    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
269    ///
270    /// let mat_ptr = mat.as_ptr();
271    /// for i in 0..(mat.rows() * mat.cols()) {
272    ///     assert_eq!(unsafe { *mat_ptr.add(i) }, i as isize + 1);
273    /// }
274    /// ```
275    pub fn as_ptr(&self) -> *const T {
276        self.data.as_ptr()
277    }
278
279    /// Gives a raw mutable pointer to the underlying Vec's buffer
280    ///
281    /// ```
282    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
283    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
284    ///
285    /// let mat_ptr = mat.as_mut_ptr();
286    /// for i in 0..(mat.rows() * mat.cols()) {
287    ///     unsafe {
288    ///         *mat_ptr.add(i) = i as isize + 10;
289    ///     }
290    /// }
291    ///
292    /// assert_eq!(mat.as_slice(), &[10, 11, 12, 13, 14, 15, 16, 17, 18]);
293    /// ```
294    pub fn as_mut_ptr(&mut self) -> *mut T {
295        self.data.as_mut_ptr()
296    }
297
298    /// Extracts a slice containing the underlying Vec
299    ///
300    /// ```
301    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
302    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
303    ///
304    /// assert_eq!(mat.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
305    /// ```
306    pub fn as_slice(&self) -> &[T] {
307        self.data.as_slice()
308    }
309
310    /// Extracts a mut slice containing the underlying Vec
311    ///
312    /// ```
313    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
314    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
315    /// let mut mat_slice = mat.as_mut_slice();
316    ///
317    /// mat_slice[0] = 10;
318    /// mat_slice[1] = 11;
319    /// mat_slice[2] = 12;
320    ///
321    /// assert_eq!(mat.as_slice(), &[10, 11, 12, 4, 5, 6, 7, 8, 9]);
322    /// ```
323    pub fn as_mut_slice(&mut self) -> &mut [T] {
324        self.data.as_mut_slice()
325    }
326
327    /// Decomposes the DynamicMatrix into the raw compoenents of it's underlying Vec
328    /// The returned tuple has three elements: (raw parts of the underlying vector, number of columns)
329    // TODO tests
330    #[cfg(vec_into_raw_parts)]
331    pub fn into_raw_parts(self) -> ((*mut T, usize, usize), usize) {
332        let cols = self.cols();
333
334        (self.data.into_raw_parts(), cols)
335    }
336
337    /// Creates a DynamicMatrix from it's underlying raw components
338    // TODO tests
339    pub unsafe fn from_raw_parts(vec_parts: (*mut T, usize, usize), cols: usize) -> Self {
340        Self {
341            data: Vec::from_raw_parts(vec_parts.0, vec_parts.1, vec_parts.2),
342            cols,
343        }
344    }
345
346    /// Decomposes the DynamicMatrix into the boxed slice of it's underlying Vec
347    ///
348    /// ```
349    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
350    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
351    ///
352    /// let (slice, cols) = mat.into_boxed_slice();
353    ///
354    /// assert_eq!(cols, 3);
355    /// assert_eq!(slice.as_ref(), [1, 2, 3, 4, 5, 6, 7, 8, 9]);
356    /// ```
357    pub fn into_boxed_slice(self) -> (Box<[T]>, usize) {
358        let cols = self.cols();
359
360        (self.data.into_boxed_slice(), cols)
361    }
362
363    /// Creates a DynamicMatrix from a Boxed slice
364    ///
365    /// ```
366    /// # use dynamic_matrix::DynamicMatrix;
367    /// let boxed_slice = Box::new([1, 2, 3, 4, 5, 6, 7, 8, 9]);
368    /// let mat = DynamicMatrix::from_boxed_slice(boxed_slice, 3);
369    ///
370    /// assert_eq!(mat.cols(), 3);
371    /// assert_eq!(mat.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
372    /// ```
373    pub fn from_boxed_slice(boxed_slice: Box<[T]>, cols: usize) -> Self {
374        Self {
375            data: boxed_slice.into_vec(),
376            cols,
377        }
378    }
379
380    /// Returns a `Result` containing a shared reference to the value at the given index
381    ///
382    /// ```
383    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
384    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
385    ///
386    /// for row in 0..mat.rows() {
387    ///     for col in 0..mat.cols() {
388    ///         assert_eq!(*mat.get((row, col)).unwrap(), 3 * row + col + 1);
389    ///     }
390    /// }
391    /// ```
392    ///
393    /// Indexing outside bounds will return an `IndexingError`.
394    /// ```should_panic
395    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
396    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
397    ///
398    /// mat.get((3, 3)).unwrap();
399    /// ```
400    pub fn get(&self, index: (usize, usize)) -> Result<&T, IndexingError> {
401        let (row, col) = index;
402        if row < self.rows() && col < self.cols() {
403            match self.data.get(row * self.cols() + col) {
404                Some(v) => Ok(v),
405                None => unreachable!(),
406            }
407        } else {
408            Err(IndexingError::new(index, self.shape()))
409        }
410    }
411
412    /// Returns a `Result` containing an exclusive reference to the value at the given index
413    ///
414    /// ```
415    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
416    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
417    ///
418    /// for row in 0..mat.rows() {
419    ///     for col in 0..mat.cols() {
420    ///         *mat.get_mut((row, col)).unwrap() += 9;
421    ///     }
422    /// }
423    ///
424    /// assert_eq!(mat.as_slice(), &[10, 11, 12, 13, 14, 15, 16, 17, 18]);
425    /// ```
426    ///
427    /// Indexing outside bounds will return an `IndexingError`.
428    /// ```should_panic
429    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
430    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
431    ///
432    /// *mat.get_mut((3, 3)).unwrap() += 1;
433    /// ```
434    pub fn get_mut(&mut self, index: (usize, usize)) -> Result<&mut T, IndexingError> {
435        let (row, col) = index;
436        let cols = self.cols();
437
438        if row < self.rows() && col < self.cols() {
439            match self.data.get_mut(row * cols + col) {
440                Some(v) => Ok(v),
441                None => unreachable!(),
442            }
443        } else {
444            Err(IndexingError::new(index, self.shape()))
445        }
446    }
447}
448
449impl<T> Index<(usize, usize)> for DynamicMatrix<T> {
450    type Output = T;
451
452    /// Returns a shared reference to the value at the given index
453    ///
454    /// ```
455    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
456    /// let mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
457    ///
458    /// for row in 0..mat.rows() {
459    ///     for col in 0..mat.cols() {
460    ///         assert_eq!(mat[(row, col)], 3 * row + col + 1);
461    ///     }
462    /// }
463    /// ```
464    fn index(&self, index: (usize, usize)) -> &Self::Output {
465        self.get(index).unwrap()
466    }
467}
468
469impl<T> IndexMut<(usize, usize)> for DynamicMatrix<T> {
470    /// Returns an exclusive reference to the value at the given index
471    ///
472    /// ```
473    /// # use dynamic_matrix::{dynamic_matrix, DynamicMatrix};
474    /// let mut mat = dynamic_matrix![1, 2, 3; 4, 5, 6; 7, 8, 9];
475    ///
476    /// for row in 0..mat.rows() {
477    ///     for col in 0..mat.cols() {
478    ///         mat[(row, col)] += 9;
479    ///     }
480    /// }
481    ///
482    /// assert_eq!(mat.as_slice(), &[10, 11, 12, 13, 14, 15, 16, 17, 18]);
483    /// ```
484    fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
485        self.get_mut(index).unwrap()
486    }
487}