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}