implemented safe versions of .insert, .add, and .at
This commit is contained in:
parent
87ab2fefb4
commit
9228e28eeb
@ -1,4 +1,3 @@
|
|||||||
use std::ops::{Add, Index, IndexMut};
|
|
||||||
|
|
||||||
// TODO: create a generic type that has some restrictions:
|
// TODO: create a generic type that has some restrictions:
|
||||||
// Needs to implement the add trait
|
// Needs to implement the add trait
|
||||||
@ -7,118 +6,105 @@ struct Matrix {
|
|||||||
elements : Vec<Vec<i32>>
|
elements : Vec<Vec<i32>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Undefined behavior enumerations
|
||||||
|
enum Illegal<A, B> {
|
||||||
|
Congruency(A, B),
|
||||||
|
InvalidSize,
|
||||||
|
InvalidEntry,
|
||||||
|
EntryOutOfBounds
|
||||||
|
}
|
||||||
|
|
||||||
|
//Helper functions
|
||||||
|
|
||||||
|
// Checks if size1
|
||||||
|
fn upper_bounded(bound : (usize, usize), size : (usize, usize)) -> bool
|
||||||
|
{
|
||||||
|
bound.0 >= size.1 && bound.1 >= size.1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//This will implement all the "safe" and well-defined operations
|
||||||
|
//These return Error objects
|
||||||
impl Matrix {
|
impl Matrix {
|
||||||
|
|
||||||
//Creates a matrix struct
|
//Creates a matrix struct
|
||||||
pub fn new(rows : usize, columns : usize) -> Matrix {
|
pub fn new(rows : usize, columns : usize) -> Result<Matrix, Illegal<(), ()>>
|
||||||
|
{
|
||||||
|
|
||||||
|
//Pass an error if they use values that are zero
|
||||||
|
if rows == 0 || columns == 0
|
||||||
|
{
|
||||||
|
return Err(Illegal::InvalidSize);
|
||||||
|
}
|
||||||
|
|
||||||
//Construct an empty vector
|
//Construct an empty vector
|
||||||
let elements : Vec<Vec<i32>> = vec![vec![0;columns];rows];
|
let elements : Vec<Vec<i32>> = vec![vec![0;columns];rows];
|
||||||
|
|
||||||
//Construct the struct
|
//Construct the struct
|
||||||
Matrix {
|
Ok(Matrix{size: (rows, columns), elements})
|
||||||
size : (rows , columns),
|
|
||||||
elements
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the size of the matrix
|
// Gets the size of the matrix
|
||||||
pub fn size(& self) -> (usize, usize) {
|
pub fn size(& self) -> (usize, usize)
|
||||||
|
{
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// implementation of the fmt::Display trait
|
|
||||||
|
|
||||||
// implementation of index ([])
|
pub fn at(& self, index : (usize, usize)) -> Option<&i32>
|
||||||
// Technically ([]) is unsafe too, but...
|
{
|
||||||
// I probably should just let the vector handle the error
|
let row : Option<&Vec<i32>> = self.elements.get(index.0);
|
||||||
|
|
||||||
// After doing more research, I can instead use get in order to make the output
|
//Matches!!
|
||||||
// an Option<>
|
match row
|
||||||
impl Index<(usize, usize)> for Matrix {
|
{
|
||||||
type Output = Option<i32>;
|
//Neat for when you want to propagate a None
|
||||||
|
Some(row) =>
|
||||||
fn index(&self, index: (usize, usize)) -> &Self::Output {
|
{
|
||||||
//Since it returns an Option, its not as simple as a get
|
let column = row.get(index.1);
|
||||||
let row : Option<&Vec<i32>> = self.elements.get(index.0); //the 'T' in Option<T> from get is a reference
|
match column
|
||||||
//Now, we need to unpack the Option
|
{
|
||||||
match row {
|
|
||||||
// Lifetimes???
|
|
||||||
|
|
||||||
// Turbofish is used in expressions
|
|
||||||
Some(row) => {
|
|
||||||
//Within THIS match:
|
|
||||||
let column : Option<&i32> = row.get(index.1);
|
|
||||||
match column {
|
|
||||||
Some(entry) => Some(entry),
|
Some(entry) => Some(entry),
|
||||||
|
None => None
|
||||||
None => &None,
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
None => &None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
None => None,
|
||||||
|
|
||||||
//mutable variant - so we can modify the entries
|
|
||||||
impl IndexMut<(usize, usize)> for Matrix {
|
|
||||||
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
|
||||||
&mut self.elements[index.0][index.1]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, entry : (usize, usize), value : i32) -> Result<(), Illegal<(), ()>> {
|
||||||
|
|
||||||
// implementation of add (+)
|
//The neat thing about our .at method is that its possible to return nothing
|
||||||
// (+) is unsafe; they could add two matricies of different sizes
|
if !upper_bounded(self.size, entry)
|
||||||
// that's undefined behavior. SO, we're going to pass an error if that happens
|
{
|
||||||
impl Add for Matrix {
|
|
||||||
type Output = Result<Matrix, String>;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Result<Matrix, String> {
|
return Err(Illegal::EntryOutOfBounds);
|
||||||
// Returns Err if they are not the same size
|
|
||||||
if self.size() != rhs.size() {
|
}
|
||||||
return Err("Both matricies must be of the same size!".to_string());
|
self.elements[entry.0][entry.1] = value;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Makes a new matrix
|
pub fn add(&mut self, other : Matrix) -> Result<(), Illegal<(usize, usize), (usize, usize)>>
|
||||||
let mut return_matrix = Matrix::new(self.size.0, self.size.1);
|
{
|
||||||
|
if self.size() == other.size() {
|
||||||
|
return Err(Illegal::Congruency(self.size(), other.size()));
|
||||||
|
}
|
||||||
|
|
||||||
//Go through each element
|
//We've confirmed that both matricies are the same size
|
||||||
for r in 0..self.size().0{
|
//Now, we can add them together
|
||||||
for c in 0..self.size().1 {
|
|
||||||
//Can't assign it???
|
for row in 0..self.size.0{
|
||||||
//Ahhhhh ok, so I must implement both the immutable and mutable versions of an
|
for col in 0..self.size.1 {
|
||||||
//index before I am able to call it
|
|
||||||
return_matrix[(r,c)] = self[(r,c)] + rhs[(r,c)];
|
// This is where I would do those operator overloads
|
||||||
|
// TODO: implement operator overloads for Add, []
|
||||||
|
// Since its not using the Result...
|
||||||
|
self.insert((row, col), self.elements[row][col] + other.elements[row][col] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(return_matrix)
|
//All good!
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementation of eq (==)
|
|
||||||
impl PartialEq for Matrix {
|
|
||||||
fn eq(& self, other : &Matrix) -> bool {
|
|
||||||
|
|
||||||
//First check if they are the same size
|
|
||||||
if self.size != other.size {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Next check if each element is the same
|
|
||||||
//We dont need to check EVERY element, just each vector
|
|
||||||
let rows = self.size.1;
|
|
||||||
|
|
||||||
for i in 0..rows {
|
|
||||||
//Oh nice, it implements PartialEq. I would have to check
|
|
||||||
//in C++ normally, and it would probably be the same address of stuff
|
|
||||||
if self.elements[i] != other.elements[i] {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user