/*! \file pivector2d.h * \brief 2D wrapper around PIVector * * This file declares PIVector */ /* PIP - Platform Independent Primitives 2D wrapper around PIVector Andrey Bychkov work.a.b@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIVECTOR2D_H #define PIVECTOR2D_H #include "pivector.h" /*! \brief 2D array, * \details This class used to store 2D array of any type elements as plain vector. * You can read/write any element via operators [][], first dimension - row, second - column. * The first dimension is Row, and you can operate with Row as PIVector: modify any element, assign to another Row and etc. * You can't add values to array, but you can modify any elements or create another PIVector2D. * PIVector2D has constructors from PIVector and PIVector > */ template class PIVector2D { public: inline PIVector2D() { rows_ = cols_ = 0; } inline PIVector2D(size_t rows, size_t cols, const T & f = T()) { rows_ = rows; cols_ = cols; mat.resize(rows * cols, f); } inline PIVector2D(size_t rows, size_t cols, const PIVector & v): rows_(rows), cols_(cols), mat(v) { mat.resize(rows * cols); } inline PIVector2D(size_t rows, size_t cols, PIVector && v): rows_(rows), cols_(cols), mat(std::move(v)) { mat.resize(rows * cols); } inline PIVector2D(const PIVector> & v) { rows_ = v.size(); if (rows_) { cols_ = v[0].size(); mat.reserve(rows_ * cols_); for (size_t i = 0; i < rows_; i++) { mat.append(v[i]); } mat.resize(rows_ * cols_); } if (mat.isEmpty()) rows_ = cols_ = 0; } inline size_t rows() const { return rows_; } inline size_t cols() const { return cols_; } inline size_t size() const { return mat.size(); } inline ssize_t size_s() const { return mat.size_s(); } inline size_t length() const { return mat.length(); } inline size_t capacity() const { return mat.capacity(); } inline bool isEmpty() const { return mat.isEmpty(); } inline bool isNotEmpty() const { return mat.isNotEmpty(); } class Row { friend class PIVector2D; private: inline Row(PIVector2D * p, size_t row): p_(&(p->mat)) { st_ = p->cols_ * row; sz_ = p->cols_; } PIVector * p_; size_t st_, sz_; public: inline size_t size() const { return sz_; } inline T & operator[](size_t index) { return (*p_)[st_ + index]; } inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; } inline T * data(size_t index = 0) { return p_->data(st_ + index); } inline const T * data(size_t index = 0) const { return p_->data(st_ + index); } inline Row & operator=(const Row & other) { if (p_ == other.p_ && st_ == other.st_) return *this; size_t sz = piMin(sz_, other.sz_); p_->_copyRaw(p_->data(st_), other.data(), sz); return *this; } inline Row & operator=(const PIVector & other) { size_t sz = piMin(sz, other.size()); p_->_copyRaw(p_->data(st_), other.data(), sz); return *this; } inline PIVector toVector() const { return PIVector(p_->data(st_), sz_); } }; class Col { friend class PIVector2D; private: inline Col(PIVector2D * p, size_t row): p_(&(p->mat)) { step_ = p->cols_; row_ = row; sz_ = p->rows_; } PIVector * p_; size_t step_, row_, sz_; public: inline size_t size() const { return sz_; } inline T & operator[](size_t index) { return (*p_)[index * step_ + row_]; } inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; } inline T * data(size_t index = 0) { return p_->data(index * step_ + row_); } inline const T * data(size_t index = 0) const { return p_->data(index * step_ + row_); } inline Col & operator=(const Col & other) { if (p_ == other.p_ && row_ == other.row_) return *this; size_t sz = piMin(sz_, other.sz_); for (int i = 0; i < sz; ++i) (*p_)[i * step_ + row_] = other[i]; return *this; } inline Row & operator=(const PIVector & other) { size_t sz = piMin(sz_, other.size()); for (int i = 0; i < sz; ++i) (*p_)[i * step_ + row_] = other[i]; return *this; } inline PIVector toVector() const { PIVector ret; ret.reserve(sz_); for (size_t i = 0; i < sz_; i++) ret << (*p_)[i * step_ + row_]; return ret; } }; class RowConst { friend class PIVector2D; private: inline RowConst(const PIVector2D * p, size_t row): p_(&(p->mat)) { st_ = p->cols_ * row; sz_ = p->cols_; } const PIVector * p_; size_t st_, sz_; public: inline size_t size() const { return sz_; } inline const T & operator[](size_t index) const { return (*p_)[st_ + index]; } inline const T * data(size_t index = 0) const { return p_->data(st_ + index); } inline PIVector toVector() const { return PIVector(p_->data(st_), sz_); } }; class ColConst { friend class PIVector2D; private: inline ColConst(const PIVector2D * p, size_t row): p_(&(p->mat)) { step_ = p->cols_; row_ = row; sz_ = p->rows_; } const PIVector * p_; size_t step_, row_, sz_; public: inline size_t size() const { return p_->rows_; } inline const T & operator[](size_t index) const { return (*p_)[index * step_ + row_]; } inline const T * data(size_t index = 0) const { return p_->data(index * step_ + row_); } inline PIVector toVector() const { PIVector ret; ret.reserve(sz_); for (int i = 0; i < size(); i++) ret << (*p_)[i * step_ + row_]; return ret; } }; inline T & element(size_t row, size_t col) { return mat[row * cols_ + col]; } inline const T & element(size_t row, size_t col) const { return mat[row * cols_ + col]; } inline const T & at(size_t row, size_t col) const { return mat[row * cols_ + col]; } inline Row operator[](size_t index) { return Row(this, index); } inline RowConst operator[](size_t index) const { return RowConst(this, index); } inline T * data(size_t index = 0) { return mat.data(index); } inline const T * data(size_t index = 0) const { return mat.data(index); } inline Row row(size_t index) { return Row(this, index); } inline RowConst row(size_t index) const { return RowConst(this, index); } inline Col col(size_t index) { return Col(this, index); } inline ColConst col(size_t index) const { return ColConst(this, index); } inline PIVector2D & setRow(size_t row, const Row & other) { size_t sz = piMin(cols_, other.sz_); mat._copyRaw(mat.data(cols_ * row), other.data(), sz); return *this; } inline PIVector2D & setRow(size_t row, const RowConst & other) { size_t sz = piMin(cols_, other.sz_); mat._copyRaw(mat.data(cols_ * row), other.data(), sz); return *this; } inline PIVector2D & setRow(size_t row, const PIVector & other) { size_t sz = piMin(cols_, other.size()); mat._copyRaw(mat.data(cols_ * row), other.data(), sz); return *this; } inline PIVector2D & addRow(const Row & other) { if (cols_ == 0) cols_ = other.sz_; size_t sz = piMin(cols_, other.sz_); size_t ps = mat.size(); mat.resize(mat.size() + cols_); mat._copyRaw(mat.data(ps), other.data(), sz); rows_++; return *this; } inline PIVector2D & addRow(const RowConst & other) { if (cols_ == 0) cols_ = other.sz_; size_t sz = piMin(cols_, other.sz_); size_t ps = mat.size(); mat.resize(mat.size() + cols_); mat._copyRaw(mat.data(ps), other.data(), sz); rows_++; return *this; } inline PIVector2D & addRow(const PIVector & other) { if (cols_ == 0) cols_ = other.size(); size_t sz = piMin(cols_, other.size()); size_t ps = mat.size(); mat.resize(mat.size() + cols_); mat._copyRaw(mat.data(ps), other.data(), sz); rows_++; return *this; } inline PIVector2D & resize(size_t rows, size_t cols, const T & f = T()) { mat.resize(rows * cols_, f); rows_ = rows; int cs = (cols - cols_); if (cs < 0) { for (size_t r = 0; r < rows; ++r) { mat.remove(r * cols + cols, -cs); } } mat.resize(rows * cols, f); if (!mat.isEmpty()) { if (cs > 0) { for (size_t r = 0; r < rows_; ++r) { for (int i = 0; i < cs; ++i) mat.insert(r * cols + cols_, mat.take_back()); } } } cols_ = cols; return *this; } inline bool operator==(const PIVector2D & t) const { if (cols_ != t.cols_ || rows_ != t.rows_) return false; return mat == t.mat; } inline bool operator!=(const PIVector2D & t) const { return !(*this == t); } inline PIVector> toVectors() const { PIVector> ret; ret.reserve(rows_); for (size_t i = 0; i < rows_; ++i) ret << PIVector(mat.data(i * cols_), cols_); return ret; } inline PIVector toPlainVector() const { return mat; } inline PIVector & plainVector() { return mat; } inline const PIVector & plainVector() const { return mat; } inline void swap(PIVector2D & other) { mat.swap(other.mat); piSwap(rows_, other.rows_); piSwap(cols_, other.cols_); } template::value, int>::type = 0> inline PIVector2D & _resizeRaw(size_t r, size_t c) { rows_ = r; cols_ = c; mat._resizeRaw(r * c); return *this; } inline void clear() { rows_ = cols_ = 0; mat.clear(); } template inline PIVector2D map(std::function f) const { return PIVector2D(rows_, cols_, mat.map(f)); } inline void forEach(std::function f) const { mat.forEach(f); } inline PIVector2D & forEach(std::function f) { mat.forEach(f); return *this; } protected: size_t rows_, cols_; PIVector mat; }; template inline PICout operator<<(PICout s, const PIVector2D & v) { s.saveAndSetControls(0); s << "{"; for (size_t i = 0; i < v.rows(); ++i) { s << "{ "; for (size_t j = 0; j < v.cols(); ++j) { s << v[i][j]; if (j < v.cols() - 1) s << ", "; } s << " }"; if (i < v.rows() - 1) s << PICoutManipulators::NewLine; } if (v.isEmpty()) s << "{ }"; s << "}"; s.restoreControls(); return s; } #endif // PIVECTOR2D_H