LCOV - code coverage report
Current view: top level - include - matrix.hpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 82 82 100.0 %
Date: 2020-12-14 08:13:14 Functions: 19 19 100.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <cstring>
       4             : #include <initializer_list>
       5             : #include <iomanip>
       6             : #include <iostream>
       7             : #include <memory>
       8             : #include <vector>
       9             : #include "exceptions.hpp"
      10             : 
      11             : // ============
      12             : // Declarations
      13             : // ============
      14             : 
      15             : template <typename T>
      16             : class matrix
      17             : {
      18             :  public:
      19             :   // === Constructors ===
      20             : 
      21             :   // Constructor to create an UNINITIALIZED matrix
      22             :   // WARNING: Good for performance, but make sure to never use any uninitialized
      23             :   // elements! First argument: number of rows Second argument: number of columns
      24             :   matrix(const size_t &, const size_t &);
      25             : 
      26             :   // Constructor to create a diagonal matrix
      27             :   // Argument: a vector containing the elements on the diagonal
      28             :   // Number of rows and columns is inferred automatically
      29             :   matrix(const std::vector<T> &);
      30             : 
      31             :   // Constructor to create a diagonal matrix
      32             :   // Argument: an initializer_list containing the elements on the diagonal
      33             :   // Number of rows and columns is inferred automatically
      34             :   matrix(const std::initializer_list<T> &);
      35             : 
      36             :   // Constructor to create a matrix and initialize it to the given elements
      37             :   // First argument: number of rows
      38             :   // Second argument: number of columns
      39             :   // Third argument: a vector containing the elements (flattened)
      40             :   matrix(const size_t &, const size_t &, const std::vector<T> &);
      41             : 
      42             :   // Constructor to create a matrix and initialize it to the given elements
      43             :   // First argument: number of rows
      44             :   // Second argument: number of columns
      45             :   // Third argument: an initializer_list containing the elements (flattened)
      46             :   matrix(const size_t &, const size_t &, const std::initializer_list<T> &);
      47             : 
      48             :   // Copy constructor to create a new matrix with the same elements as an
      49             :   // existing matrix
      50             :   matrix(const matrix &);
      51             : 
      52             :   // Move constructor to move the elements of an existing matrix to a new matrix
      53             :   matrix(matrix &&);
      54             : 
      55             :   // === Member functions ===
      56             : 
      57             :   // Overloaded operator = to assign the elements of one matrix to another
      58             :   // matrix
      59             :   matrix &operator=(const matrix &);
      60             : 
      61             :   // Overloaded operator = to move the elements of one matrix to another matrix
      62             :   matrix &operator=(matrix &&);
      63             : 
      64             :   // Member function used to obtain (but not modify) the number of rows in the
      65             :   // matrix
      66             :   size_t get_rows() const;
      67             : 
      68             :   // Member function used to obtain (but not modify) the number of columns in
      69             :   // the matrix
      70             :   size_t get_cols() const;
      71             : 
      72             :   // Overloaded operator () used to access matrix elements WITHOUT range
      73             :   // checking The indices start from 1: m(1, 2) would be the element at row 1,
      74             :   // column 2 First version: returns a reference, thus allows modification of
      75             :   // the element
      76             :   T &operator()(const size_t &, const size_t &);
      77             : 
      78             :   // Overloaded operator () used to access matrix elements WITHOUT range
      79             :   // checking The indices start from 1: m(1, 2) would be the element at row 1,
      80             :   // column 2 Second version: does not return a reference and declared as const,
      81             :   // does not allow modification of the element
      82             :   T operator()(const size_t &, const size_t &) const;
      83             : 
      84             :   // Static member function used to set the character width of the elements
      85             :   // when printing a matrix (will be used with std::setw)
      86             :   static void set_output_width(const int &);
      87             : 
      88             :   // === Friend functions ===
      89             : 
      90             :   // Overloaded binary operator << used to easily print out a matrix to a stream
      91             :   template <typename U>
      92             :   friend std::ostream &operator<<(std::ostream &, const matrix<U> &);
      93             : 
      94             :  private:
      95             :   // The number of rows
      96             :   size_t rows{0};
      97             : 
      98             :   // The number of columns
      99             :   size_t cols{0};
     100             : 
     101             :   // A pointer to an array storing the elements of the matrix in flattened
     102             :   // (1-dimensional) form
     103             :   T *elements{nullptr};
     104             : 
     105             :   // A smart pointer to manage the memory allocated for the elements
     106             :   std::unique_ptr<T[]> smart{nullptr};
     107             : 
     108             :   // The character width of the elements when printing a matrix (will be used
     109             :   // with std::setw)
     110             :   static int output_width;
     111             : };
     112             : 
     113             : // Initialize output_width to have a default value of 5
     114             : template <typename T>
     115             : int matrix<T>::output_width{5};
     116             : 
     117             : // ==============
     118             : // Implementation
     119             : // ==============
     120             : 
     121             : // === Constructors ===
     122             : 
     123             : // Uninitialized constructor
     124             : template <typename T>
     125          60 : matrix<T>::matrix(const size_t &input_rows, const size_t &input_cols)
     126          64 :     : rows(input_rows), cols(input_cols)
     127             : {
     128          60 :   if (rows == 0 or cols == 0)
     129           2 :     throw sayMessage{"Dimentions of matrix must be positive.\n"};
     130          58 :   smart.reset(new T[ rows * cols ]);
     131          56 :   elements = smart.get();
     132          56 : }
     133             : 
     134             : // Diagonal matrix initialized with vector
     135             : template <typename T>
     136           2 : matrix<T>::matrix(const std::vector<T> &input_diagonal)
     137           2 :     : rows(input_diagonal.size()), cols(input_diagonal.size())
     138             : {
     139           2 :   if (rows == 0) throw sayMessage{"Dimentions of matrix must be positive.\n"};
     140           2 :   smart.reset(new T[ rows * cols ]);
     141           2 :   elements = smart.get();
     142           9 :   for (size_t i{0}; i < rows; i++)
     143          32 :     for (size_t j{0}; j < cols; j++)
     144          25 :       elements[ (cols * i) + j ] = ((i == j) ? input_diagonal[ i ] : 0);
     145           2 : }
     146             : 
     147             : // Diagonal matrix initialized with initializer_list
     148             : template <typename T>
     149           1 : matrix<T>::matrix(const std::initializer_list<T> &input_diagonal)
     150           1 :     : matrix(std::vector<T>{input_diagonal})
     151             : {
     152           1 : }
     153             : 
     154             : // Full matrix initialized with vector
     155             : template <typename T>
     156          32 : matrix<T>::matrix(const size_t &input_rows, const size_t &input_cols,
     157             :                   const std::vector<T> &input_elements)
     158          36 :     : rows(input_rows), cols(input_cols)
     159             : {
     160          32 :   if (rows == 0 or cols == 0)
     161           2 :     throw sayMessage{"Dimentions of matrix must be positive.\n"};
     162          30 :   if (input_elements.size() != rows * cols)
     163           2 :     throw sayMessage{"Size of vector must equal rows*cols.\n"};
     164          28 :   smart.reset(new T[ rows * cols ]);
     165          28 :   elements = smart.get();
     166         394 :   for (size_t i{0}; i < rows * cols; i++) elements[ i ] = input_elements[ i ];
     167          28 : }
     168             : 
     169             : // Full matrix initialized with initializer_list
     170             : template <typename T>
     171           1 : matrix<T>::matrix(const size_t &input_rows, const size_t &input_cols,
     172             :                   const std::initializer_list<T> &input_elements)
     173           1 :     : matrix(input_rows, input_cols, std::vector<T>{input_elements})
     174             : {
     175           1 : }
     176             : 
     177             : // Copy constructor
     178             : template <typename T>
     179           2 : matrix<T>::matrix(const matrix<T> &m) : rows(m.rows), cols(m.cols)
     180             : {
     181           2 :   smart.reset(new T[ rows * cols ]);
     182           2 :   elements = smart.get();
     183           2 :   std::memcpy(elements, m.elements, rows * cols * sizeof(T));
     184           2 : }
     185             : 
     186             : // Move constructor
     187             : template <typename T>
     188           1 : matrix<T>::matrix(matrix<T> &&m) : rows(m.rows), cols(m.cols)
     189             : {
     190           1 :   smart = move(m.smart);
     191           1 :   elements = smart.get();
     192           1 :   m.rows = 0;
     193           1 :   m.cols = 0;
     194           1 :   m.elements = nullptr;
     195           1 : }
     196             : 
     197             : // === Member functions ===
     198             : 
     199             : // Copy assignment
     200             : template <typename T>
     201           3 : matrix<T> &matrix<T>::operator=(const matrix<T> &m)
     202             : {
     203           3 :   if (m.rows != rows or m.cols != cols)
     204           1 :     throw sayMessage{"Copy assignment requires equal matrix dimensions.\n"};
     205           2 :   if (elements == m.elements) return *this;
     206           1 :   rows = m.rows;
     207           1 :   cols = m.cols;
     208           1 :   smart.reset(new T[ rows * cols ]);
     209           1 :   elements = smart.get();
     210           1 :   std::memcpy(elements, m.elements, rows * cols * sizeof(T));
     211           1 :   return *this;
     212             : }
     213             : 
     214             : // Move assignment
     215             : template <typename T>
     216           3 : matrix<T> &matrix<T>::operator=(matrix<T> &&m)
     217             : {
     218           3 :   if (m.rows != rows or m.cols != cols)
     219           1 :     throw sayMessage{"Move assignment requires equal matrix dimensions.\n"};
     220           2 :   if (elements == m.elements) return *this;
     221           1 :   rows = m.rows;
     222           1 :   cols = m.cols;
     223           1 :   smart = move(m.smart);
     224           1 :   elements = smart.get();
     225           1 :   m.rows = 0;
     226           1 :   m.cols = 0;
     227           1 :   m.elements = nullptr;
     228           1 :   return *this;
     229             : }
     230             : 
     231             : template <typename T>
     232         411 : inline size_t matrix<T>::get_rows() const
     233             : {
     234         411 :   return rows;
     235             : }
     236             : 
     237             : template <typename T>
     238          75 : inline size_t matrix<T>::get_cols() const
     239             : {
     240          75 :   return cols;
     241             : }
     242             : 
     243             : // With reference
     244             : template <typename T>
     245        1039 : inline T &matrix<T>::operator()(const size_t &row, const size_t &col)
     246             : {
     247        1039 :   return elements[ (rows * (col - 1)) + (row - 1) ];
     248             : }
     249             : 
     250             : // No reference
     251             : template <typename T>
     252          15 : inline T matrix<T>::operator()(const size_t &row, const size_t &col) const
     253             : {
     254          15 :   return elements[ (rows * (col - 1)) + (row - 1) ];
     255             : }
     256             : 
     257             : // For pretty printing
     258             : template <typename T>
     259             : inline void matrix<T>::set_output_width(const int &w)
     260             : {
     261             :   output_width = w;
     262             : }
     263             : 
     264             : // === Friend functions ===
     265             : 
     266             : template <typename T>
     267           1 : std::ostream &operator<<(std::ostream &out, const matrix<T> &m)
     268             : {
     269             :   // if (m.rows == 0 and m.cols == 0)
     270             :   //   out << "()\n";
     271             :   // else
     272             :   // {
     273           4 :   for (size_t i{1}; i <= m.rows; i++)
     274             :   {
     275           3 :     out << "( ";
     276          18 :     for (size_t j{1}; j <= m.cols; j++)
     277          15 :       out << std::setw(m.output_width) << m(i, j) << ' ';
     278           3 :     out << ")\n";
     279             :   }
     280           1 :   out << '\n';
     281             :   // }
     282           1 :   return out;
     283             : }

Generated by: LCOV version 1.14