1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! An efficient representation of a 2D matrix.

use crate::prelude::*;

use std::ops::Index;
use std::ops::IndexMut;



// ============
// == Matrix ==
// ============

/// An efficient 2D matrix implemented on top of [`std::vec::Vec`].
#[derive(Clone,Debug,Default,PartialEq,Eq)]
#[allow(missing_docs)]
pub struct Matrix<T> {
    pub rows    : usize,
    pub columns : usize,
    pub matrix  : Vec<T>,
}

impl<T:Copy> Matrix<T> {
    /// Get the number of rows in the matrix.
    pub fn rows(&self) -> usize {
        self.rows
    }

    /// Get the number of columns in the matrix.
    pub fn columns(&self) -> usize {
        self.columns
    }

    /// Obtain the indices for the rows in this matrix.
    pub fn row_indices(&self) -> Range<usize> {
        0..self.rows()
    }

    /// Indexing with bounds checking.
    pub fn safe_index(&self, row:usize, column:usize) -> Option<T> {
        (row < self.rows && column < self.columns).as_some_from(|| {
            self.matrix[row*self.columns+column]
        })
    }
}

impl<T:Default> Matrix<T> {
    /// Construct a matrix with the dimensions given by `rows` and `columns`.
    pub fn new(rows:usize, columns:usize) -> Self {
        let mut matrix = Vec::with_capacity(rows*columns);
        for _ in 0..matrix.capacity() {
            matrix.push(default())
        }
        Self{rows,columns,matrix}
    }

    /// Add a new row to the matrix `self`, filled with default values.
    pub fn new_row(&mut self) {
        for _ in 0..self.columns {
            self.matrix.push(default());
        }
        self.rows += 1;
    }

    /// Add a new column to the matrix `self`, filled with default values.
    ///
    /// Note that this is an _expensive_ operation that requires moving potentially very large
    /// allocations around.
    pub fn new_column(&mut self) {
        for n in 0..self.rows {
            let index = self.columns*n + self.columns+n;
            self.matrix.insert(index,default());
        }
        self.columns += 1;
    }
}

// FIXME: Wrong indexing order!
// === Trait Impls ===

impl<T> Index<(usize,usize)> for Matrix<T> {
    type Output = T;
    fn index(&self, index:(usize,usize)) -> &T {
        &self.matrix[index.0*self.columns+index.1]
    }
}

impl<T> IndexMut<(usize,usize)> for Matrix<T> {
    fn index_mut(&mut self, index:(usize,usize)) -> &mut T {
        &mut self.matrix[index.0*self.columns+index.1]
    }
}



// =============
// === Tests ===
// =============

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_size() {
        let default = Matrix::<usize>::default();
        assert_eq!(default.rows,0);
        assert_eq!(default.columns,0);
    }

    #[test]
    fn construct_with_dimensions() {
        let matrix = Matrix::<usize>::new(5, 10);
        assert_eq!(matrix.rows,5);
        assert_eq!(matrix.columns,10);
    }

    #[test]
    fn add_row() {
        let mut matrix = Matrix::<usize>::new(2, 2);
        matrix[(0,0)] = 1;
        matrix[(0,1)] = 2;
        matrix[(1,0)] = 3;
        matrix[(1,1)] = 4;
        assert_eq!(matrix.rows,2);
        assert_eq!(matrix.columns,2);
        matrix.new_row();
        assert_eq!(matrix.rows,3);
        assert_eq!(matrix.columns,2);
        assert_eq!(matrix[(0,0)],1);
        assert_eq!(matrix[(0,1)],2);
        assert_eq!(matrix[(1,0)],3);
        assert_eq!(matrix[(1,1)],4);
        assert_eq!(matrix[(2,0)],0);
        assert_eq!(matrix[(2,1)],0);
    }

    #[test]
    fn add_column() {
        let mut matrix = Matrix::<usize>::new(2,2);
        matrix[(0,0)] = 1;
        matrix[(0,1)] = 2;
        matrix[(1,0)] = 3;
        matrix[(1,1)] = 4;
        assert_eq!(matrix.rows,2);
        assert_eq!(matrix.columns,2);
        matrix.new_column();
        assert_eq!(matrix.rows,2);
        assert_eq!(matrix.columns,3);
        assert_eq!(matrix[(0,0)],1);
        assert_eq!(matrix[(0,1)],2);
        assert_eq!(matrix[(1,0)],3);
        assert_eq!(matrix[(1,1)],4);
        assert_eq!(matrix[(0,2)],0);
        assert_eq!(matrix[(1,2)],0);
    }

    #[test]
    fn row_column_indexing() {
        let mut matrix = Matrix::<usize>::new(2,2);
        matrix[(0,0)] = 1;
        matrix[(0,1)] = 2;
        matrix[(1,0)] = 3;
        matrix[(1,1)] = 4;
        let mut output = Vec::default();
        for row in 0..2 {
            for col in 0..2 {
                output.push(matrix[(row,col)]);
            }
        }
        assert_eq!(output,vec![1,2,3,4]);
    }

    #[test]
    fn safe_indexing() {
        let matrix         = Matrix::<usize>::new(2,2);
        let exists         = matrix.safe_index(0,0);
        let does_not_exist = matrix.safe_index(3,0);
        assert_eq!(exists,Some(0));
        assert_eq!(does_not_exist,None);
    }
}