diff --git a/docs/HTML/self_contained.html b/docs/HTML/self_contained.html
index 44def6e1..35c17038 100644
--- a/docs/HTML/self_contained.html
+++ b/docs/HTML/self_contained.html
@@ -51,7 +51,7 @@
It also has some disadvantages:
- There might be functionalities that are hard/time-consuming to implement that are already there
- - If you find a battle-test library, the debugging is already done for you
+ - If you find a battle-tested library, the debugging is already done for you
- There might be industry-wide standards/trends that you want to follow by using a reputed library
diff --git a/include/DataFrame/Utils/Matrix.h b/include/DataFrame/Utils/Matrix.h
index b10b03f2..964b3897 100644
--- a/include/DataFrame/Utils/Matrix.h
+++ b/include/DataFrame/Utils/Matrix.h
@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include
#include
+#include
#include
// ----------------------------------------------------------------------------
@@ -75,20 +76,22 @@ class Matrix {
void reserve(size_type rows, size_type cols);
size_type rows() const noexcept;
- size_type columns() const noexcept;
+ size_type cols() const noexcept;
+
+ static constexpr matrix_orient orientation();
public:
void resize(size_type rows, size_type cols, const_reference def_v = T());
- reference at (size_type r, size_type c);
- const_reference at (size_type r, size_type c) const;
+ reference at(size_type r, size_type c);
+ const_reference at(size_type r, size_type c) const;
reference operator() (size_type r, size_type c);
const_reference operator() (size_type r, size_type c) const;
// Set the given column or row from the given iterator.
// col_data/row_Data iterators must be valid for the length of
- // cols_/rows_.
+ // columns/rows.
//
template
void set_column(I col_data, size_type col);
@@ -104,15 +107,801 @@ class Matrix {
size_type cols_ { 0 };
storage_t matrix_ { };
+ //
+ // Iterators
+ //
+
public:
+ class row_iterator;
+ class row_const_iterator : public std::random_access_iterator_tag {
+
+ public:
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T;
+ using size_type = long;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using difference_type = typename std::vector::difference_type;
+
+ public:
+
+ inline row_const_iterator () = default;
+
+ inline row_const_iterator(const self_t *m,
+ size_type row = 0,
+ size_type col = 0)
+ : mptr_ (m), row_ (row), col_(col) { }
+
+ inline bool operator == (const row_const_iterator &rhs) const {
+
+ return (mptr_ == rhs.mptr_ &&
+ row_ == rhs.row_ &&
+ col_ == rhs.col_);
+ }
+ inline bool operator != (const row_const_iterator &rhs) const {
+
+ return (! (*this == rhs));
+ }
+ inline bool
+ operator > (const row_const_iterator &rhs) const noexcept {
+
+ return (row_ > rhs.row_ || (row_ == rhs.row_ && col_ > rhs.col_));
+ }
+ inline bool
+ operator >= (const row_const_iterator &rhs) const noexcept {
+
+ return (row_ > rhs.row_ || (row_ == rhs.row_ && col_ >= rhs.col_));
+ }
+ inline bool
+ operator < (const row_const_iterator &rhs) const noexcept {
+
+ return (! (*this >= rhs));
+ }
+ inline bool
+ operator <= (const row_const_iterator &rhs) const noexcept {
+
+ return (! (*this > rhs));
+ }
+
+ // Following STL style, this iterator appears as a pointer
+ // to value_type.
+ //
+ inline const_pointer operator -> () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+ inline const_reference operator * () const noexcept {
+
+ return (mptr_->at(row_, col_));
+ }
+ inline operator const_pointer () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+
+ // We are following STL style iterator interface.
+ //
+ inline row_const_iterator &operator ++ () noexcept { // ++Prefix
+
+ col_ += 1;
+ if (col_ >= mptr_->cols()) { col_ = 0; row_ += 1; }
+ return (*this);
+ }
+ inline row_const_iterator operator ++ (int) noexcept { // Postfix++
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ += 1;
+ if (col_ >= mptr_->cols()) { col_ = 0; row_ += 1; }
+ return (row_const_iterator (mptr_, row, col));
+ }
+
+ inline row_const_iterator &operator += (size_type i) noexcept {
+
+ col_ += i;
+ if (col_ >= mptr_->cols()) {
+ row_ += col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (*this);
+ }
+
+ inline row_const_iterator &operator -- () noexcept { // --Prefix
+
+ col_ -= 1;
+ if (col_ < 0) { col_ = mptr_->cols() - 1; row_ -= 1; }
+ return (*this);
+ }
+ inline row_const_iterator operator -- (int) noexcept { // Postfix--
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ -= 1;
+ if (col_ < 0) { col_ = mptr_->cols() - 1; row_ -= 1; }
+ return (row_const_iterator (mptr_, row, col));
+ }
+
+ inline row_const_iterator &operator -= (int i) noexcept {
+
+ col_ -= i;
+ if (col_ < 0) {
+ row_ -= col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (*this);
+ }
+
+ inline row_const_iterator operator + (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ += i;
+ if (col_ >= mptr_->cols()) {
+ row_ += col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (row_const_iterator (mptr_, row, col));
+ }
+
+ inline row_const_iterator operator - (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ -= i;
+ if (col_ < 0) {
+ row_ -= col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (row_const_iterator (mptr_, row, col));
+ }
+
+ inline row_const_iterator operator + (int i) noexcept {
+
+ return (*this + size_type(i));
+ }
+
+ inline row_const_iterator operator - (int i) noexcept {
+
+ return (*this - size_type(i));
+ }
+
+ friend difference_type
+ operator - (row_const_iterator lhs, row_const_iterator rhs) noexcept {
+
+ const size_type row_diff = lhs.row_ - rhs.row_;
+ const size_type col_diff = lhs.col_ - rhs.col_;
+
+ assert(lhs.mptr_ == rhs.mptr);
+ return (difference_type(
+ std::abs(row_diff) * rhs.mptr_->cols() - col_diff));
+ }
+
+ private:
+
+ const self_t *mptr_ { nullptr };
+ size_type row_ { 0 };
+ size_type col_ { 0 };
+ };
+
+ // It goes through the matrix row-by-row starting at [0, 0]
+ //
+ class row_iterator : public std::random_access_iterator_tag {
+
+ public:
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T;
+ using size_type = long;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using difference_type = typename std::vector::difference_type;
+
+ public:
+
+ inline row_iterator () = default;
+
+ inline row_iterator (self_t *m, size_type row = 0, size_type col = 0)
+ : mptr_ (m), row_ (row), col_(col) { }
+
+ inline bool operator == (const row_iterator &rhs) const {
+
+ return (mptr_ == rhs.mptr_ &&
+ row_ == rhs.row_ &&
+ col_ == rhs.col_);
+ }
+ inline bool operator != (const row_iterator &rhs) const {
+
+ return (! (*this == rhs));
+ }
+ inline bool operator > (const row_iterator &rhs) const noexcept {
+
+ return (row_ > rhs.row_ || (row_ == rhs.row_ && col_ > rhs.col_));
+ }
+ inline bool operator >= (const row_iterator &rhs) const noexcept {
+
+ return (row_ > rhs.row_ || (row_ == rhs.row_ && col_ >= rhs.col_));
+ }
+ inline bool operator < (const row_iterator &rhs) const noexcept {
+
+ return (! (*this >= rhs));
+ }
+ inline bool operator <= (const row_iterator &rhs) const noexcept {
+
+ return (! (*this > rhs));
+ }
+
+ // Following STL style, this iterator appears as a pointer
+ // to value_type.
+ //
+ inline pointer operator -> () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+ inline reference operator * () const noexcept {
+
+ return (mptr_->at(row_, col_));
+ }
+ inline operator pointer () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+
+ // We are following STL style iterator interface.
+ //
+ inline row_iterator &operator ++ () noexcept { // ++Prefix
+
+ col_ += 1;
+ if (col_ >= mptr_->cols()) { col_ = 0; row_ += 1; }
+ return (*this);
+ }
+ inline row_iterator operator ++ (int) noexcept { // Postfix++
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ += 1;
+ if (col_ >= mptr_->cols()) { col_ = 0; row_ += 1; }
+ return (row_iterator (mptr_, row, col));
+ }
+
+ inline row_iterator &operator += (size_type i) noexcept {
+
+ col_ += i;
+ if (col_ >= mptr_->cols()) {
+ row_ += col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (*this);
+ }
+
+ inline row_iterator &operator -- () noexcept { // --Prefix
+
+ col_ -= 1;
+ if (col_ < 0) { col_ = mptr_->cols() - 1; row_ -= 1; }
+ return (*this);
+ }
+ inline row_iterator operator -- (int) noexcept { // Postfix--
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ -= 1;
+ if (col_ < 0) { col_ = mptr_->cols() - 1; row_ -= 1; }
+ return (row_iterator (mptr_, row, col));
+ }
+
+ inline row_iterator &operator -= (int i) noexcept {
+
+ col_ -= i;
+ if (col_ < 0) {
+ row_ -= col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (*this);
+ }
+
+ inline row_iterator operator + (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ += i;
+ if (col_ >= mptr_->cols()) {
+ row_ += col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (row_iterator (mptr_, row, col));
+ }
+
+ inline row_iterator operator - (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ col_ -= i;
+ if (col_ < 0) {
+ row_ -= col_ / mptr_->cols();
+ col_ %= mptr_->cols();
+ }
+ return (row_iterator (mptr_, row, col));
+ }
+
+ inline row_iterator operator + (int i) noexcept {
+
+ return (*this + size_type(i));
+ }
+
+ inline row_iterator operator - (int i) noexcept {
+
+ return (*this - size_type(i));
+ }
+
+ friend difference_type
+ operator - (row_iterator lhs, row_iterator rhs) noexcept {
+
+ const size_type row_diff = lhs.row_ - rhs.row_;
+ const size_type col_diff = lhs.col_ - rhs.col_;
+
+ assert(lhs.mptr_ == rhs.mptr);
+ return (difference_type(
+ std::abs(row_diff) * rhs.mptr_->cols() - col_diff));
+ }
+
+ private:
+
+ self_t *mptr_ { nullptr };
+ size_type row_ { 0 };
+ size_type col_ { 0 };
+ };
+
+ class col_iterator;
+ class col_const_iterator : public std::random_access_iterator_tag {
+
+ public:
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T;
+ using size_type = long;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using difference_type = typename std::vector::difference_type;
+
+ public:
+
+ inline col_const_iterator () = default;
+
+ inline col_const_iterator(const self_t *m,
+ size_type row = 0,
+ size_type col = 0)
+ : mptr_ (m), row_ (row), col_(col) { }
+
+ inline bool operator == (const col_const_iterator &rhs) const {
+
+ return (mptr_ == rhs.mptr_ &&
+ row_ == rhs.row_ &&
+ col_ == rhs.col_);
+ }
+ inline bool operator != (const col_const_iterator &rhs) const {
+
+ return (! (*this == rhs));
+ }
+ inline bool
+ operator > (const col_const_iterator &rhs) const noexcept {
+
+ return (col_ > rhs.col_ || (col_ == rhs.col_ && row_ > rhs.row_));
+ }
+ inline bool
+ operator >= (const col_const_iterator &rhs) const noexcept {
+
+ return (col_ > rhs.col_ || (col_ == rhs.col_ && row_ >= rhs.row_));
+ }
+ inline bool
+ operator < (const col_const_iterator &rhs) const noexcept {
+
+ return (! (*this >= rhs));
+ }
+ inline bool
+ operator <= (const col_const_iterator &rhs) const noexcept {
+
+ return (! (*this > rhs));
+ }
+
+ // Following STL style, this iterator appears as a pointer
+ // to value_type.
+ //
+ inline const_pointer operator -> () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+ inline const_reference operator * () const noexcept {
+
+ return (mptr_->at(row_, col_));
+ }
+ inline operator const_pointer () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+
+ // We are following STL style iterator interface.
+ //
+ inline col_const_iterator &operator ++ () noexcept { // ++Prefix
+
+ row_ += 1;
+ if (row_ >= mptr_->rows()) { row_ = 0; col_ += 1; }
+ return (*this);
+ }
+ inline col_const_iterator operator ++ (int) noexcept { // Postfix++
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ += 1;
+ if (row_ >= mptr_->rows()) { row_ = 0; col_ += 1; }
+ return (col_const_iterator (mptr_, row, col));
+ }
+
+ inline col_const_iterator &operator += (size_type i) noexcept {
+
+ row_ += i;
+ if (row_ >= mptr_->rows()) {
+ col_ += row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (*this);
+ }
+
+ inline col_const_iterator &operator -- () noexcept { // --Prefix
+
+ row_ -= 1;
+ if (row_ < 0) { row_ = mptr_->rows() - 1; col_ -= 1; }
+ return (*this);
+ }
+ inline col_const_iterator operator -- (int) noexcept { // Postfix--
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ -= 1;
+ if (row_ < 0) { row_ = mptr_->rows() - 1; col_ -= 1; }
+ return (col_const_iterator (mptr_, row, col));
+ }
+
+ inline col_const_iterator &operator -= (int i) noexcept {
+
+ row_ -= i;
+ if (row_ < 0) {
+ col_ -= row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (*this);
+ }
+
+ inline col_const_iterator operator + (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ += i;
+ if (row_ >= mptr_->rows()) {
+ col_ += row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (col_const_iterator (mptr_, row, col));
+ }
+
+ inline col_const_iterator operator - (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ -= i;
+ if (row_ < 0) {
+ col_ -= row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (col_const_iterator (mptr_, row, col));
+ }
+
+ inline col_const_iterator operator + (int i) noexcept {
+
+ return (*this + size_type(i));
+ }
+
+ inline col_const_iterator operator - (int i) noexcept {
+
+ return (*this - size_type(i));
+ }
+
+ friend difference_type
+ operator - (col_const_iterator lhs, col_const_iterator rhs) noexcept {
+
+ const size_type row_diff = lhs.row_ - rhs.row_;
+ const size_type col_diff = lhs.col_ - rhs.col_;
+
+ assert(lhs.mptr_ == rhs.mptr);
+ return (difference_type(
+ std::abs(row_diff) * rhs.mptr_->cols() - col_diff));
+ }
+
+ private:
+
+ const self_t *mptr_ { nullptr };
+ size_type row_ { 0 };
+ size_type col_ { 0 };
+ };
+
+ // It goes through the matrix row-by-row starting at [0, 0]
+ //
+ class col_iterator : public std::random_access_iterator_tag {
+
+ public:
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = T;
+ using size_type = long;
+ using pointer = value_type *;
+ using const_pointer = const value_type *;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+ using difference_type = typename std::vector::difference_type;
+
+ public:
+
+ inline col_iterator() = default;
+
+ inline col_iterator (self_t *m, size_type row = 0, size_type col = 0)
+ : mptr_ (m), row_ (row), col_(col) { }
+
+ inline bool operator == (const col_iterator &rhs) const {
+
+ return (mptr_ == rhs.mptr_ &&
+ row_ == rhs.row_ &&
+ col_ == rhs.col_);
+ }
+ inline bool operator != (const col_iterator &rhs) const {
+
+ return (! (*this == rhs));
+ }
+ inline bool operator > (const col_iterator &rhs) const noexcept {
+
+ return (col_ > rhs.col_ || (col_ == rhs.col_ && row_ > rhs.row_));
+ }
+ inline bool operator >= (const col_iterator &rhs) const noexcept {
+
+ return (col_ > rhs.col_ || (col_ == rhs.col_ && row_ >= rhs.row_));
+ }
+ inline bool operator < (const col_iterator &rhs) const noexcept {
+
+ return (! (*this >= rhs));
+ }
+ inline bool operator <= (const col_iterator &rhs) const noexcept {
+
+ return (! (*this > rhs));
+ }
+
+ // Following STL style, this iterator appears as a pointer
+ // to value_type.
+ //
+ inline pointer operator -> () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+ inline reference operator * () const noexcept {
+
+ return (mptr_->at(row_, col_));
+ }
+ inline operator pointer () const noexcept {
+
+ return (&(mptr_->at(row_, col_)));
+ }
+
+ // We are following STL style iterator interface.
+ //
+ inline col_iterator &operator ++ () noexcept { // ++Prefix
+
+ row_ += 1;
+ if (row_ >= mptr_->rows()) { row_ = 0; col_ += 1; }
+ return (*this);
+ }
+ inline col_iterator operator ++ (int) noexcept { // Postfix++
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ += 1;
+ if (row_ >= mptr_->rows()) { row_ = 0; col_ += 1; }
+ return (col_iterator (mptr_, row, col));
+ }
+
+ inline col_iterator &operator += (size_type i) noexcept {
+
+ row_ += i;
+ if (row_ >= mptr_->rows()) {
+ col_ += row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (*this);
+ }
+
+ inline col_iterator &operator -- () noexcept { // --Prefix
+
+ row_ -= 1;
+ if (row_ < 0) { row_ = mptr_->rows() - 1; col_ -= 1; }
+ return (*this);
+ }
+ inline col_iterator operator -- (int) noexcept { // Postfix--
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ -= 1;
+ if (row_ < 0) { row_ = mptr_->rows() - 1; col_ -= 1; }
+ return (col_iterator (mptr_, row, col));
+ }
+
+ inline col_iterator &operator -= (int i) noexcept {
+
+ row_ -= i;
+ if (row_ < 0) {
+ col_ -= row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (*this);
+ }
+
+ inline col_iterator operator + (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ += i;
+ if (row_ >= mptr_->rows()) {
+ col_ += row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (col_iterator (mptr_, row, col));
+ }
+
+ inline col_iterator operator - (size_type i) noexcept {
+
+ const size_type row = row_;
+ const size_type col = col_;
+
+ row_ -= i;
+ if (row_ < 0) {
+ col_ -= row_ / mptr_->rows();
+ row_ %= mptr_->rows();
+ }
+ return (col_iterator (mptr_, row, col));
+ }
+
+ inline col_iterator operator + (int i) noexcept {
+
+ return (*this + size_type(i));
+ }
+
+ inline col_iterator operator - (int i) noexcept {
+
+ return (*this - size_type(i));
+ }
+
+ friend difference_type
+ operator - (col_iterator lhs, col_iterator rhs) noexcept {
+
+ const size_type row_diff = lhs.row_ - rhs.row_;
+ const size_type col_diff = lhs.col_ - rhs.col_;
+
+ assert(lhs.mptr_ == rhs.mptr);
+ return (difference_type(
+ std::abs(row_diff) * rhs.mptr_->cols() - col_diff));
+ }
+
+ private:
+
+ self_t *mptr_ { nullptr };
+ size_type row_ { 0 };
+ size_type col_ { 0 };
+ };
+
+public:
+
+ // Forwards
+ //
+ inline row_iterator row_begin() noexcept {
+
+ return (row_iterator(this, 0, 0));
+ }
+ inline row_const_iterator row_cbegin() const noexcept {
+
+ return (row_const_iterator(this, 0, 0));
+ }
+ inline row_iterator row_end() noexcept {
+
+ return (row_iterator(this, rows(), cols()));
+ }
+ inline row_const_iterator row_cend() const noexcept {
+
+ return (row_const_iterator(this, rows(), cols()));
+ }
+
+ inline col_iterator col_begin() noexcept {
+
+ return (col_iterator(this, 0, 0));
+ }
+ inline col_const_iterator col_cbegin() const noexcept {
+
+ return (col_const_iterator(this, 0, 0));
+ }
+ inline col_iterator col_end() noexcept {
+
+ return (col_iterator(this, rows(), cols()));
+ }
+ inline col_const_iterator col_cend() const noexcept {
+
+ return (col_const_iterator(this, rows(), cols()));
+ }
+
+ using reverse_row_iterator = std::reverse_iterator;
+ using reverse_row_const_iterator =
+ std::reverse_iterator;
+ using reverse_col_iterator = std::reverse_iterator;
+ using reverse_col_const_iterator =
+ std::reverse_iterator;
+
+ // Reverses
+ //
+ inline reverse_row_iterator row_rbegin() noexcept {
+
+ return (std::make_reverse_iterator(row_end()));
+ }
+ inline reverse_row_const_iterator row_crbegin() const noexcept {
+
+ return (std::make_reverse_iterator(row_cend()));
+ }
+ inline reverse_row_iterator row_rend() noexcept {
+
+ return (std::make_reverse_iterator(row_begin()));
+ }
+ inline reverse_row_const_iterator row_crend() const noexcept {
+
+ return (std::make_reverse_iterator(row_cbegin()));
+ }
+
+ inline reverse_col_iterator col_rbegin() noexcept {
+
+ return (std::make_reverse_iterator(col_end()));
+ }
+ inline reverse_col_const_iterator col_crbegin() const noexcept {
+
+ return (std::make_reverse_iterator(col_cend()));
+ }
+ inline reverse_col_iterator col_rend() noexcept {
+
+ return (std::make_reverse_iterator(col_begin()));
+ }
+ inline reverse_col_const_iterator col_crend() const noexcept {
+
+ return (std::make_reverse_iterator(col_cbegin()));
+ }
};
} // namespace hmdf
// ----------------------------------------------------------------------------
-#ifdef HMDF_DO_NOT_INCLUDE_TCC_FILES
+#ifndef HMDF_DO_NOT_INCLUDE_TCC_FILES
# include
#endif // HMDF_DO_NOT_INCLUDE_TCC_FILES
diff --git a/include/DataFrame/Utils/Matrix.tcc b/include/DataFrame/Utils/Matrix.tcc
index ce9a6df8..f6c03e2d 100644
--- a/include/DataFrame/Utils/Matrix.tcc
+++ b/include/DataFrame/Utils/Matrix.tcc
@@ -63,7 +63,7 @@ Matrix::swap(Matrix &rhs) noexcept {
template
bool
-Matrix::empty() noexcept {
+Matrix::empty() const noexcept {
return (rows_ == 0 && cols_ == 0);
}
@@ -160,10 +160,16 @@ template
void
Matrix::set_row(I row_data, size_type row) {
- for (size_type c = 0; c < columns(); ++c)
+ for (size_type c = 0; c < cols(); ++c)
at(row, c) = *row_data++;
}
+// ----------------------------------------------------------------------------
+
+template
+constexpr matrix_orient
+Matrix::orientation() { return (MO); }
+
} // namespace hmdf
// ----------------------------------------------------------------------------
diff --git a/src/CommonMakefile.mk b/src/CommonMakefile.mk
index 73ac4bb9..4d808b2f 100644
--- a/src/CommonMakefile.mk
+++ b/src/CommonMakefile.mk
@@ -79,7 +79,9 @@ HEADERS = $(LOCAL_INCLUDE_DIR)/DataFrame/Vectors/HeteroVector.h \
$(LOCAL_INCLUDE_DIR)/DataFrame/Utils/FixedSizePriorityQueue.h \
$(LOCAL_INCLUDE_DIR)/DataFrame/Utils/AlignedAllocator.h \
$(LOCAL_INCLUDE_DIR)/DataFrame/Utils/FixedSizeAllocator.h \
- $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/Endianness.h
+ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/Endianness.h \
+ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/Matrix.h \
+ $(LOCAL_INCLUDE_DIR)/DataFrame/Utils/Matrix.tcc
LIB_NAME = DataFrame
TARGET_LIB = $(LOCAL_LIB_DIR)/lib$(LIB_NAME).a
@@ -101,7 +103,8 @@ TARGETS += $(TARGET_LIB) \
$(LOCAL_BIN_DIR)/vector_ptr_view_tester \
$(LOCAL_BIN_DIR)/meta_prog_tester \
$(LOCAL_BIN_DIR)/date_time_tester \
- $(LOCAL_BIN_DIR)/gen_rand_tester
+ $(LOCAL_BIN_DIR)/gen_rand_tester \
+ $(LOCAL_BIN_DIR)/matrix_tester
# -----------------------------------------------------------------------------
@@ -222,6 +225,10 @@ GEN_RAND_TESTER_OBJ = $(LOCAL_OBJ_DIR)/gen_rand_tester.o
$(LOCAL_BIN_DIR)/gen_rand_tester: $(TARGET_LIB) $(GEN_RAND_TESTER_OBJ)
$(CXX) -o $@ $(GEN_RAND_TESTER_OBJ) $(LIBS)
+MATRIX_TESTER_OBJ = $(LOCAL_OBJ_DIR)/matrix_tester.o
+$(LOCAL_BIN_DIR)/matrix_tester: $(TARGET_LIB) $(MATRIX_TESTER_OBJ)
+ $(CXX) -o $@ $(MATRIX_TESTER_OBJ) $(LIBS)
+
# -----------------------------------------------------------------------------
depend:
@@ -236,7 +243,7 @@ clean:
$(HELLO_WORLD_OBJ) $(DATAFRAME_PERFORMANCE_2_OBJ) \
$(DATAFRAME_THREAD_SAFTY_OBJ) $(DATAFRAME_TESTER_SCHEMA_OBJ) \
$(ALLOCATOR_TESTER_OBJ) $(LINKEDIN_BENCHMARK_OBJ) \
- $(DATAFRAME_READ_LARGE_FILE_OBJ)
+ $(DATAFRAME_READ_LARGE_FILE_OBJ) $(MATRIX_TESTER_OBJ)
clobber:
rm -f $(LIB_OBJS) $(TARGETS) $(DATAFRAME_TESTER_OBJ) $(VECTORS_TESTER_OBJ) \
@@ -248,7 +255,7 @@ clobber:
$(ALLOCATOR_TESTER_OBJ) $(DATAFRAME_PERFORMANCE_OBJ) \
$(DATAFRAME_PERFORMANCE_2_OBJ) \
$(META_PROG_OBJ) $(LINKEDIN_BENCHMARK_OBJ) \
- $(DATAFRAME_READ_LARGE_FILE_OBJ)
+ $(DATAFRAME_READ_LARGE_FILE_OBJ) $(MATRIX_TESTER_OBJ)
install_lib:
cp -pf $(TARGET_LIB) $(PROJECT_LIB_DIR)/.
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f312d6f6..0f6bdd0f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -52,6 +52,13 @@ if(MSVC)
set_tests_properties(vectors_tester PROPERTIES DISABLED TRUE)
endif()
+add_executable(matrix_tester matrix_tester.cc)
+target_link_libraries(matrix_tester PRIVATE DataFrame)
+target_compile_options(matrix_tester
+ PRIVATE $<$:/bigobj>
+)
+add_test(NAME matrix_tester COMMAND matrix_tester)
+
if(NOT MSVC)
# MSVC compiler craps out on immediately executing lambdas
add_executable(allocator_tester allocator_tester.cc)
diff --git a/test/matrix_tester.cc b/test/matrix_tester.cc
new file mode 100644
index 00000000..5ed370e0
--- /dev/null
+++ b/test/matrix_tester.cc
@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2019-2026, Hossein Moein
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of Hossein Moein and/or the DataFrame nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL Hossein Moein BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include
+
+#include
+#include
+
+using namespace hmdf;
+
+// -----------------------------------------------------------------------------
+
+using row_mat_t = Matrix;
+using col_mat_t = Matrix;
+
+static constexpr std::size_t ROWS = 5;
+static constexpr std::size_t COLS = 6;
+
+// -----------------------------------------------------------------------------
+
+int main(int, char *[]) {
+
+ row_mat_t row_mat { ROWS, COLS };
+ col_mat_t col_mat { ROWS, COLS };
+ std::size_t value { 0 };
+
+ for (std::size_t r = 0; r < row_mat.rows(); ++r)
+ for (std::size_t c = 0; c < row_mat.cols(); ++c)
+ row_mat(r, c) = value++;
+
+ value = 0;
+ for (std::size_t c = 0; c < col_mat.cols(); ++c)
+ for (std::size_t r = 0; r < col_mat.rows(); ++r)
+ col_mat(r, c) = value++;
+
+ value = 0;
+ for (std::size_t r = 0; r < row_mat.rows(); ++r)
+ for (std::size_t c = 0; c < row_mat.cols(); ++c)
+ assert(row_mat(r, c) == value++);
+
+ value = 0;
+ for (std::size_t c = 0; c < col_mat.cols(); ++c)
+ for (std::size_t r = 0; r < col_mat.rows(); ++r)
+ assert(col_mat(r, c) == value++);
+
+ return (0);
+}
+
+// -----------------------------------------------------------------------------
+
+// Local Variables:
+// mode:C++
+// tab-width:4
+// c-basic-offset:4
+// End: