#include <array>
#include <cassert>
#include <iostream>
#include <map>
#include <stdexcept>
template <typename T>
class SparseMatrix;
template <typename T>
class SparseMatrixProxy {
SparseMatrix<T> &matrix;
const std::array<int, 2> indices;
public:
SparseMatrixProxy(SparseMatrix<T> &matrix, const std::array<int, 2> indices)
: matrix{matrix}
, indices{indices} {}
//for reading an element:
operator T() const {
// Check if given indices are within the size of the matrix
if (indices[0] >= matrix.size[0] || indices[1] >= matrix.size[1])
throw std::invalid_argument("Indices out of bounds");
auto map_it = matrix.data.find(indices);
if (map_it == matrix.data.end()) {
return T{};
}
return map_it->second;
}
//for writing an element:
auto operator=(const T &t) {
//optional: when setting a value to 0 erase it from the map
if (t == T{}) {
matrix.data.erase(indices);
} else {
matrix.data[indices] = t;
}
return *this;
}
};
template <typename T>
class SparseMatrix {
std::map<std::array<int, 2>, T> data;
const std::array<int, 2> size;
public:
SparseMatrix(const int rows, const int cols)
: size({{rows, cols}}) {}
// []-operator to set and get values from matrix
SparseMatrixProxy<T> operator[](const std::array<int, 2> indices) {
return {*this, indices};
}
auto mapsize() const {
return data.size();
}
friend class SparseMatrixProxy<T>;
};
int main() {
SparseMatrix<double> M(2, 2); // Create a new sparse matrix with 2 rows and 2 columns
M[{{1, 1}}] = 3.1; // Sets element {1,1} to 3.1
std::cout << M[{{1, 1}}] << '\n';
assert(M.mapsize() == 1); //1 element for index {1,1}
std::cout << M[{{0, 0}}] << '\n';
assert(M.mapsize() == 1); //still 1 element because reading doesn't insert an element
M[{{1, 1}}] = 0;
assert(M.mapsize() == 0); //0 elements because we set the only non-0 element to 0
}
I2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y2Fzc2VydD4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bWFwPgojaW5jbHVkZSA8c3RkZXhjZXB0PgoKdGVtcGxhdGUgPHR5cGVuYW1lIFQ+CmNsYXNzIFNwYXJzZU1hdHJpeDsKCnRlbXBsYXRlIDx0eXBlbmFtZSBUPgpjbGFzcyBTcGFyc2VNYXRyaXhQcm94eSB7CglTcGFyc2VNYXRyaXg8VD4gJm1hdHJpeDsKCWNvbnN0IHN0ZDo6YXJyYXk8aW50LCAyPiBpbmRpY2VzOwoKCXB1YmxpYzoKCVNwYXJzZU1hdHJpeFByb3h5KFNwYXJzZU1hdHJpeDxUPiAmbWF0cml4LCBjb25zdCBzdGQ6OmFycmF5PGludCwgMj4gaW5kaWNlcykKCQk6IG1hdHJpeHttYXRyaXh9CgkJLCBpbmRpY2Vze2luZGljZXN9IHt9CgkvL2ZvciByZWFkaW5nIGFuIGVsZW1lbnQ6CglvcGVyYXRvciBUKCkgY29uc3QgewoJCS8vIENoZWNrIGlmIGdpdmVuIGluZGljZXMgYXJlIHdpdGhpbiB0aGUgc2l6ZSBvZiB0aGUgbWF0cml4CgkJaWYgKGluZGljZXNbMF0gPj0gbWF0cml4LnNpemVbMF0gfHwgaW5kaWNlc1sxXSA+PSBtYXRyaXguc2l6ZVsxXSkKCQkJdGhyb3cgc3RkOjppbnZhbGlkX2FyZ3VtZW50KCJJbmRpY2VzIG91dCBvZiBib3VuZHMiKTsKCQlhdXRvIG1hcF9pdCA9IG1hdHJpeC5kYXRhLmZpbmQoaW5kaWNlcyk7CgkJaWYgKG1hcF9pdCA9PSBtYXRyaXguZGF0YS5lbmQoKSkgewoJCQlyZXR1cm4gVHt9OwoJCX0KCQlyZXR1cm4gbWFwX2l0LT5zZWNvbmQ7Cgl9CgkvL2ZvciB3cml0aW5nIGFuIGVsZW1lbnQ6CglhdXRvIG9wZXJhdG9yPShjb25zdCBUICZ0KSB7CgkJLy9vcHRpb25hbDogd2hlbiBzZXR0aW5nIGEgdmFsdWUgdG8gMCBlcmFzZSBpdCBmcm9tIHRoZSBtYXAKCQlpZiAodCA9PSBUe30pIHsKCQkJbWF0cml4LmRhdGEuZXJhc2UoaW5kaWNlcyk7CgkJfSBlbHNlIHsKCQkJbWF0cml4LmRhdGFbaW5kaWNlc10gPSB0OwoJCX0KCQlyZXR1cm4gKnRoaXM7Cgl9Cn07Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4KY2xhc3MgU3BhcnNlTWF0cml4IHsKCXN0ZDo6bWFwPHN0ZDo6YXJyYXk8aW50LCAyPiwgVD4gZGF0YTsKCWNvbnN0IHN0ZDo6YXJyYXk8aW50LCAyPiBzaXplOwoKCXB1YmxpYzoKCVNwYXJzZU1hdHJpeChjb25zdCBpbnQgcm93cywgY29uc3QgaW50IGNvbHMpCgkJOiBzaXplKHt7cm93cywgY29sc319KSB7fQoKCS8vIFtdLW9wZXJhdG9yIHRvIHNldCBhbmQgZ2V0IHZhbHVlcyBmcm9tIG1hdHJpeAoJU3BhcnNlTWF0cml4UHJveHk8VD4gb3BlcmF0b3JbXShjb25zdCBzdGQ6OmFycmF5PGludCwgMj4gaW5kaWNlcykgewoJCXJldHVybiB7KnRoaXMsIGluZGljZXN9OwoJfQoJYXV0byBtYXBzaXplKCkgY29uc3QgewoJCXJldHVybiBkYXRhLnNpemUoKTsKCX0KCWZyaWVuZCBjbGFzcyBTcGFyc2VNYXRyaXhQcm94eTxUPjsKfTsKCmludCBtYWluKCkgewoJU3BhcnNlTWF0cml4PGRvdWJsZT4gTSgyLCAyKTsgLy8gQ3JlYXRlIGEgbmV3IHNwYXJzZSBtYXRyaXggd2l0aCAyIHJvd3MgYW5kIDIgY29sdW1ucwoJTVt7ezEsIDF9fV0gPSAzLjE7ICAgICAgICAgICAgLy8gU2V0cyBlbGVtZW50IHsxLDF9IHRvIDMuMQoJc3RkOjpjb3V0IDw8IE1be3sxLCAxfX1dIDw8ICdcbic7Cglhc3NlcnQoTS5tYXBzaXplKCkgPT0gMSk7IC8vMSBlbGVtZW50IGZvciBpbmRleCB7MSwxfQoJc3RkOjpjb3V0IDw8IE1be3swLCAwfX1dIDw8ICdcbic7Cglhc3NlcnQoTS5tYXBzaXplKCkgPT0gMSk7IC8vc3RpbGwgMSBlbGVtZW50IGJlY2F1c2UgcmVhZGluZyBkb2Vzbid0IGluc2VydCBhbiBlbGVtZW50CglNW3t7MSwgMX19XSA9IDA7Cglhc3NlcnQoTS5tYXBzaXplKCkgPT0gMCk7IC8vMCBlbGVtZW50cyBiZWNhdXNlIHdlIHNldCB0aGUgb25seSBub24tMCBlbGVtZW50IHRvIDAKfQo=