1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 extern crate libc; 16 17 mod ffi; 18 19 use std::ops; 20 use std::ptr; 21 22 /// Wrapper around pointer to FFI Matrix struct. 23 pub struct Matrix { 24 matrix: *mut ffi::Matrix, 25 } 26 27 /// Wrapper around low-level FFI Matrix API. 28 impl Matrix { 29 /// Constructs a new Matrix from the given data. Matrix returned contains a copy of the data 30 /// provided. 31 /// 32 /// # Panics 33 /// 34 /// If rows * cols does not equal data.len() or if matrix could not be allocated. new(rows: usize, cols: usize, data: &[u64]) -> Matrix35 pub fn new(rows: usize, cols: usize, data: &[u64]) -> Matrix { 36 if data.len() != rows * cols { 37 panic!( 38 "rows * cols ({}) do not equal data.len() ({})", 39 rows * cols, 40 data.len() 41 ); 42 } 43 44 let mut data_copy: Vec<u64> = vec![0; data.len()]; 45 data_copy.clone_from_slice(data); 46 unsafe { 47 let matrix: *mut ffi::Matrix = ffi::matrix_new(rows, cols, data_copy.as_ptr()); 48 if matrix.is_null() { 49 panic!("Failed to allocate Matrix."); 50 } 51 Matrix { matrix } 52 } 53 } 54 55 /// Fetches the value at the specified row and column. at(&self, row: usize, col: usize) -> Option<u64>56 pub fn at(&self, row: usize, col: usize) -> Option<u64> { 57 let mut n: u64 = 0; 58 unsafe { 59 if ffi::matrix_at(self.matrix, row, col, &mut n) == 0 { 60 return None; 61 } 62 } 63 Some(n) 64 } 65 66 /// Sets the value at the specified row and column. 67 /// 68 /// # Panics 69 /// 70 /// If row, col is out of bounds. set(&mut self, row: usize, col: usize, n: u64)71 pub fn set(&mut self, row: usize, col: usize, n: u64) { 72 unsafe { 73 if ffi::matrix_set(self.matrix, row, col, n) == 0 { 74 panic!("Row {}, col {} is out of bounds.", row, col); 75 } 76 } 77 } 78 79 /// Returns the number of rows of the matrix. rows(&self) -> usize80 pub fn rows(&self) -> usize { 81 unsafe { (*self.matrix).rows } 82 } 83 84 /// Returns the number of cols of the matrix. cols(&self) -> usize85 pub fn cols(&self) -> usize { 86 unsafe { (*self.matrix).cols } 87 } 88 89 /// Performs an in-place transposition of the matrix. transpose(&mut self)90 pub fn transpose(&mut self) { 91 unsafe { 92 ffi::matrix_transpose(self.matrix); 93 } 94 } 95 96 /// Checks whether the matrix is equal to the provided Matrix. equal(&self, other: &Matrix) -> bool97 pub fn equal(&self, other: &Matrix) -> bool { 98 unsafe { ffi::matrix_equal(self.matrix, other.matrix) != 0 } 99 } 100 } 101 102 impl ops::Drop for Matrix { drop(&mut self)103 fn drop(&mut self) { 104 unsafe { 105 ffi::matrix_free(self.matrix); 106 } 107 self.matrix = ptr::null_mut(); 108 } 109 } 110 111 #[cfg(test)] 112 mod test { 113 use super::Matrix; 114 115 #[test] test_size()116 fn test_size() { 117 let matrix = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]); 118 assert_eq!(2, matrix.rows()); 119 assert_eq!(4, matrix.cols()); 120 } 121 122 #[test] test_equal()123 fn test_equal() { 124 let matrix_a = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]); 125 let matrix_b = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]); 126 assert!(matrix_a.equal(&matrix_b)); 127 128 let matrix_c = Matrix::new(2, 4, &[12, 13, 14, 15, 23, 24, 25, 26]); 129 assert!(!matrix_a.equal(&matrix_c)); 130 } 131 132 #[test] test_transpose()133 fn test_transpose() { 134 let mut matrix = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]); 135 matrix.transpose(); 136 let expected = Matrix::new(4, 2, &[11, 21, 12, 22, 13, 23, 14, 24]); 137 assert!(matrix.equal(&expected)); 138 } 139 } 140