#pragma once template class mm::vector_iterator { std::size_t index; // variable index mm::basic_matrix& M; const std::size_t position; // fixed index const bool direction; // true = row, false = column public: template friend class vector_iterator; vector_iterator(mm::basic_matrix& M, std::size_t position, bool direction); mm::vector_iterator operator++() { vector_iterator it = *this; ++index; return it; } mm::vector_iterator operator--() { vector_iterator it = *this; --index; return it; } mm::vector_iterator& operator++(int) { ++index; return *this; } mm::vector_iterator& operator--(int) { --index; return *this; } bool operator==(const mm::vector_iterator& other) const { return index == other.index; } bool operator=!(const mm::vector_iterator& other) const { return index != other.index; } T& operator*() const; T& operator[](std::size_t); }; template class diag_iterator { std::size_t index; // variable index mm::square_matrix& M; const int position; // fixed diagonal index public: template friend class diag_iterator; diag_iterator(mm::square_matrix& M, std::size_t position, bool direction); mm::diag_iterator operator++() { diag_iterator it = *this; ++index; return it; } mm::diag_iterator operator--() { diag_iterator it = *this; --index; return it; } mm::diag_iterator& operator++(int) { ++index; return *this; } mm::diag_iterator& operator--(int) { --index; return *this; } bool operator==(const mm::diag_iterator& other) const { return index == other.index; } bool operator=!(const mm::diag_iterator& other) const { return index != other.index; } T& operator*() const; }; /* Const Iterators */ template class mm::const_vector_iterator { std::size_t index; // variable index const mm::basic_matrix& M; const std::size_t position; // fixed index const bool direction; // true = row, false = column public: const_vector_iterator(mm::basic_matrix& M, std::size_t position, bool direction); mm::const_vector_iterator operator++() { vector_iterator it = *this; ++index; return it; } mm::const_vector_iterator operator--() { vector_iterator it = *this; --index; return it; } mm::const_vector_iterator& operator++(int) { ++index; return *this; } mm::const_vector_iterator& operator--(int) { --index; return *this; } bool operator==(const mm::const_vector_iterator& other) const { return index == other; } bool operator=!(const mm::const_vector_iterator& other) const { return index != other; } const T& operator*() const; const T& operator[](std::size_t) const; }; template class const_diag_iterator { std::size_t index; // variable index const mm::square_matrix& M; const int position; // fixed diagonal index public: template friend class const_diag_iterator; const_diag_iterator(const mm::square_matrix& M, std::size_t position, bool direction); mm::const_diag_iterator operator++() { const_diag_iterator it = *this; ++index; return it; } mm::const_diag_iterator operator--() { const_diag_iterator it = *this; --index; return it; } mm::const_diag_iterator& operator++(int) { ++index; return *this; } mm::const_diag_iterator& operator--(int) { --index; return *this; } bool operator==(const mm::const_diag_iterator& other) const { return index == other.index; } bool operator=!(const mm::const_diag_iterator& other) const { return index != other.index; } const T& operator*() const; }; /* Iterators implementations */ template mm::vector_iterator::vector_iterator(mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template T& mm::vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template T& mm::vector_iterator::operator[](std::size_t i) { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::diag_iterator::diag_iterator(mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template mm::const_vector_iterator::const_vector_iterator(const mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template const T& mm::const_vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template const T& mm::const_vector_iterator::operator[](std::size_t i) const { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::const_diag_iterator::const_diag_iterator(const mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::const_diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } /* Iterators implementations */ template mm::vector_iterator::vector_iterator(mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template T& mm::vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template T& mm::vector_iterator::operator[](std::size_t i) { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::diag_iterator::diag_iterator(mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template mm::const_vector_iterator::const_vector_iterator(const mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template const T& mm::const_vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template const T& mm::const_vector_iterator::operator[](std::size_t i) const { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::const_diag_iterator::const_diag_iterator(const mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::const_diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } /* Iterators implementations */ template mm::vector_iterator::vector_iterator(mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template T& mm::vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template T& mm::vector_iterator::operator[](std::size_t i) { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::diag_iterator::diag_iterator(mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template mm::const_vector_iterator::const_vector_iterator(const mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template const T& mm::const_vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template const T& mm::const_vector_iterator::operator[](std::size_t i) const { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::const_diag_iterator::const_diag_iterator(const mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::const_diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } /* Iterators implementations */ template mm::vector_iterator::vector_iterator(mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template T& mm::vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template T& mm::vector_iterator::operator[](std::size_t i) { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::diag_iterator::diag_iterator(mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template mm::const_vector_iterator::const_vector_iterator(const mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template const T& mm::const_vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template const T& mm::const_vector_iterator::operator[](std::size_t i) const { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::const_diag_iterator::const_diag_iterator(const mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::const_diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } /* Iterators implementations */ template mm::vector_iterator::vector_iterator(mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template T& mm::vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template T& mm::vector_iterator::operator[](std::size_t i) { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::diag_iterator::diag_iterator(mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template mm::const_vector_iterator::const_vector_iterator(const mm::basic_matrix& _M, std::size_t pos, bool dir) index(0), M(_M), position(pos), direction(dir) { assert((dir && pos < Cols) || (!dir && pos < Rows)) } template const T& mm::const_vector_iterator::operator*() const { return (direction) ? M.data[position * Cols + index] : M.data[index * Cols + position]; } template const T& mm::const_vector_iterator::operator[](std::size_t i) const { return (direction) ? M.data[position * Cols + i] : M.data[i * Cols + position]; } template mm::const_diag_iterator::const_diag_iterator(const mm::square_matrix& _M, int pos) index(0), M(_M), position(pos) { assert(abs(pos) < N) // pos bounded between ]-N, N[ } template T& mm::const_diag_iterator::operator*() const { return (k > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } /* * SECOND IMPLEMENTATION * */ // TODO, short term solution #define MM_ROW_ITER 0 #define MM_COL_ITER 1 #define MM_DIAG_ITER 2 template class mm::vector_iterator { std::size_t index; // variable index Grid& M; const int position; // fixed index, negative too for diagonal iterator public: vector_iterator(Grid& M, int position, std::size_t index = 0); operator T&() { return *(*this); } mm::vector_iterator operator++() { vector_iterator it = *this; ++index; return it; } mm::vector_iterator operator--() { vector_iterator it = *this; --index; return it; } mm::vector_iterator& operator++(int) { ++index; return *this; } mm::vector_iterator& operator--(int) { --index; return *this; } bool operator==(const mm::vector_iterator& other) const { return index == other.index; } bool operator!=(const mm::vector_iterator& other) const { return index != other.index; } bool ok() const { if constexpr(IterType == MM_ROW_ITER) return index < Cols; else return index < Rows; } T& operator*(); T& operator[](std::size_t); mm::vector_iterator begin() { return mm::vector_iterator(M, position, 0); } mm::vector_iterator end() { if constexpr(IterType == MM_ROW_ITER) return mm::vector_iterator(M, position, Cols); else return mm::vector_iterator(M, position, Rows); } /* * Scalar product */ template T operator*(const mm::vector_iterator& v) { T out(0); for (unsigned k(0); k < Rows; ++k) out += (*this)[k] * v[k]; return out; } template T operator*(const mm::vector_iterator& v) { T out(0); for (unsigned k(0); k < Cols; ++k) out += (*this)[k] * v[k]; return out; } }; /* Row Iterators */ namespace mm { template using row_iterator = vector_iterator>; template using col_iterator = vector_iterator>; template using const_row_iterator = vector_iterator::type, Rows, Cols, MM_ROW_ITER, typename std::add_const>::type>; template using const_col_iterator = vector_iterator::type, Rows, Cols, MM_COL_ITER, typename std::add_const>::type>; template using diag_iterator = vector_iterator>; template using const_diag_iterator = vector_iterator::type, N, N, MM_DIAG_ITER, typename std::add_const>::type>; } /* Iterators implementation */ template mm::vector_iterator::vector_iterator(Grid& _M, int pos, std::size_t i) : index(i), M(_M), position(pos) { if constexpr (IterType == MM_ROW_ITER) { assert(pos < Rows); } else if constexpr (IterType == MM_COL_ITER) { assert(pos < Cols); } else if constexpr (IterType == MM_DIAG_ITER) { assert(abs(pos) < Rows); } } template T& mm::vector_iterator::operator*() { if constexpr (IterType == MM_ROW_ITER) return M.data[position * Cols + index]; else if constexpr (IterType == MM_COL_ITER) return M.data[index * Cols + position]; else if constexpr (IterType == MM_DIAG_ITER) return (position > 0) ? M.data[(index + position) * Cols + index] : M.data[index * Cols + (index - position)]; } template T& mm::vector_iterator::operator[](std::size_t i) { if constexpr (IterType == MM_ROW_ITER) return M.data[position * Cols + i]; else if constexpr (IterType == MM_COL_ITER) return M.data[i * Cols + position]; else if constexpr (IterType == MM_DIAG_ITER) return (position > 0) ? M.data[(i + position) * Cols + i] : M.data[i * Cols + (i - position)]; }