GEOS 3.15.0dev
Matrix.h
1/**********************************************************************
2 *
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
5 *
6 * Copyright (C) 2018-2025 ISciences, LLC
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU Lesser General Public Licence as published
10 * by the Free Software Foundation.
11 * See the COPYING file for more information.
12 *
13 **********************************************************************/
14
15#pragma once
16
17#include <cstring>
18#include <iomanip>
19#include <memory>
20#include <string>
21#include <vector>
22
23namespace geos::operation::grid {
24
25template<typename T>
26class Matrix
27{
28
29 public:
30 using value_type = T;
31
32 Matrix(size_t rows, size_t cols, std::shared_ptr<T[]> data)
33 : m_data{ data }
34 , m_rows{ rows }
35 , m_cols{ cols }
36 {}
37
38 Matrix(size_t rows, size_t cols)
39 : m_rows{ rows }
40 , m_cols{ cols }
41 {
42 if (m_rows > 0 && m_cols > 0) {
43 // new T[]() initializes to zero
44 m_data = std::shared_ptr<T[]>(new T[m_rows * m_cols]());
45 }
46 }
47
48 Matrix(size_t rows, size_t cols, T value)
49 : m_rows{ rows }
50 , m_cols{ cols }
51 {
52 if (m_rows > 0 && m_cols > 0) {
53 // new T[] does not initialize
54 m_data = std::shared_ptr<T[]>(new T[m_rows * m_cols]);
55 }
56
57 std::fill(m_data.get(), m_data.get() + m_rows * m_cols, value);
58 }
59
60 explicit Matrix(const std::vector<std::vector<T>>& data)
61 : m_rows{ data.size() }
62 , m_cols{ data[0].size() }
63 {
64 m_data = std::shared_ptr<T[]>(new T[m_rows * m_cols]());
65
66 auto lastpos = m_data.get();
67 for (auto& row : data) {
68 lastpos = std::copy(row.begin(), row.end(), lastpos);
69 }
70 }
71
72 Matrix(Matrix<T>&& m) noexcept
73 : m_rows{ m.getNumRows() }
74 , m_cols{ m.getNumCols() }
75 {
76 m_data = std::move(m.m_data);
77 }
78
79 T& operator()(size_t row, size_t col)
80 {
81 check(row, col);
82 return m_data.get()[row * m_cols + col];
83 }
84
85 const T& operator()(size_t row, size_t col) const
86 {
87 check(row, col);
88 return m_data.get()[row * m_cols + col];
89 }
90
91 bool operator!=(const Matrix<T>& other) const {
92 return !(*this == other);
93 }
94
95 bool operator==(const Matrix<T>& other) const
96 {
97 if (m_rows != other.m_rows) {
98 return false;
99 }
100 if (m_cols != other.m_cols) {
101 return false;
102 }
103
104 return 0 == memcmp(m_data.get(), other.m_data.get(), m_rows * m_cols * sizeof(T));
105 }
106
107 void increment(size_t row, size_t col, const T& val)
108 {
109 check(row, col);
110 m_data.get()[row * m_cols + col] += val;
111 }
112
113 size_t getNumRows() const { return m_rows; }
114 size_t getNumCols() const { return m_cols; }
115
116 T* row(size_t row)
117 {
118 return &(m_data[row * m_cols]);
119 }
120
121 T* data()
122 {
123 return m_data.get();
124 }
125
126 const T* data() const
127 {
128 return m_data.get();
129 }
130
131 T* release()
132 {
133 return m_data.release();
134 }
135
136 const T* begin() const {
137 return m_data.get();
138 }
139
140 const T* end() const {
141 return m_data.get() + m_rows * m_cols;
142 }
143
144#ifdef MATRIX_CHECK_BOUNDS
145 void check(size_t row, size_t col) const
146 {
147 if (row + 1 > m_rows) {
148 throw std::out_of_range("Row " + std::to_string(row) + " is out of range.");
149 }
150 if (col + 1 > m_cols) {
151 throw std::out_of_range("Col " + std::to_string(col) + " is out of range.");
152 }
153 }
154#else
155 void check(size_t, size_t) const
156 {
157 }
158#endif
159
160 private:
161 std::shared_ptr<T[]> m_data;
162
163 size_t m_rows;
164 size_t m_cols;
165};
166
167template<typename T>
168std::ostream&
169operator<<(std::ostream& os, const Matrix<T>& m)
170{
171 for (size_t i = 0; i < m.getNumRows(); i++) {
172 for (size_t j = 0; j < m.getNumCols(); j++) {
173 if (m(i, j) != 0) {
174 os << std::right << std::fixed << std::setw(10) << std::setprecision(6) << m(i, j) << " ";
175 } else {
176 os << " ";
177 }
178 }
179 os << std::endl;
180 }
181
182 return os;
183}
184
185}