summaryrefslogtreecommitdiffstats
path: root/src/libixion/matrix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libixion/matrix.cpp')
-rw-r--r--src/libixion/matrix.cpp331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/libixion/matrix.cpp b/src/libixion/matrix.cpp
new file mode 100644
index 0000000..14d1769
--- /dev/null
+++ b/src/libixion/matrix.cpp
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/matrix.hpp"
+#include "ixion/global.hpp"
+#include "column_store_type.hpp"
+
+#include <limits>
+#include <cstring>
+#include <functional>
+
+namespace ixion {
+
+const double nan = std::numeric_limits<double>::quiet_NaN();
+
+struct matrix::impl
+{
+ matrix_store_t m_data;
+
+ impl() {}
+
+ impl(size_t rows, size_t cols) : m_data(rows, cols) {}
+
+ impl(size_t rows, size_t cols, double numeric) :
+ m_data(rows, cols, numeric) {}
+
+ impl(size_t rows, size_t cols, bool boolean) :
+ m_data(rows, cols, boolean) {}
+
+ impl(size_t rows, size_t cols, const std::string& str) :
+ m_data(rows, cols, str) {}
+
+ impl(size_t rows, size_t cols, formula_error_t error) :
+ m_data(rows, cols, -static_cast<int64_t>(error)) {}
+
+ impl(const std::vector<double>& array, size_t rows, size_t cols) :
+ m_data(rows, cols, array.begin(), array.end()) {}
+
+ impl(const impl& other) : m_data(other.m_data) {}
+};
+
+struct numeric_matrix::impl
+{
+ std::vector<double> m_array;
+ size_t m_rows;
+ size_t m_cols;
+
+ impl() : m_rows(0), m_cols(0) {}
+
+ impl(size_t rows, size_t cols) :
+ m_array(rows * cols, 0.0), m_rows(rows), m_cols(cols) {}
+
+ impl(std::vector<double> array, size_t rows, size_t cols) :
+ m_array(std::move(array)), m_rows(rows), m_cols(cols) {}
+
+ size_t to_array_pos(size_t row, size_t col) const
+ {
+ return m_rows * col + row;
+ }
+};
+
+matrix::matrix() :
+ mp_impl(std::make_unique<impl>()) {}
+
+matrix::matrix(size_t rows, size_t cols) :
+ mp_impl(std::make_unique<impl>(rows, cols)) {}
+
+matrix::matrix(size_t rows, size_t cols, double numeric) :
+ mp_impl(std::make_unique<impl>(rows, cols, numeric)) {}
+
+matrix::matrix(size_t rows, size_t cols, bool boolean) :
+ mp_impl(std::make_unique<impl>(rows, cols, boolean)) {}
+
+matrix::matrix(size_t rows, size_t cols, const std::string& str) :
+ mp_impl(std::make_unique<impl>(rows, cols, str)) {}
+
+matrix::matrix(size_t rows, size_t cols, formula_error_t error) :
+ mp_impl(std::make_unique<impl>(rows, cols, error)) {}
+
+matrix::matrix(const matrix& other) :
+ mp_impl(std::make_unique<impl>(*other.mp_impl))
+{
+}
+
+matrix::matrix(matrix&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+}
+
+matrix::matrix(const numeric_matrix& other) :
+ mp_impl(std::make_unique<impl>(
+ other.mp_impl->m_array, other.row_size(), other.col_size()))
+{
+}
+
+matrix::~matrix() = default;
+
+matrix& matrix::operator= (matrix other)
+{
+ matrix t(std::move(other));
+ swap(t);
+ return *this;
+}
+
+bool matrix::is_numeric() const
+{
+ return mp_impl->m_data.numeric();
+}
+
+bool matrix::get_boolean(size_t row, size_t col) const
+{
+ return mp_impl->m_data.get_boolean(row, col);
+}
+
+bool matrix::is_numeric(size_t row, size_t col) const
+{
+ switch (mp_impl->m_data.get_type(row, col))
+ {
+ case mdds::mtm::element_numeric:
+ case mdds::mtm::element_boolean:
+ return true;
+ default:
+ ;
+ }
+
+ return false;
+}
+
+double matrix::get_numeric(size_t row, size_t col) const
+{
+ return mp_impl->m_data.get_numeric(row, col);
+}
+
+void matrix::set(size_t row, size_t col, double val)
+{
+ mp_impl->m_data.set(row, col, val);
+}
+
+void matrix::set(size_t row, size_t col, bool val)
+{
+ mp_impl->m_data.set(row, col, val);
+}
+
+void matrix::set(size_t row, size_t col, const std::string& str)
+{
+ mp_impl->m_data.set(row, col, str);
+}
+
+void matrix::set(size_t row, size_t col, formula_error_t val)
+{
+ int64_t encoded = -static_cast<uint8_t>(val);
+ mp_impl->m_data.set(row, col, encoded);
+}
+
+matrix::element matrix::get(size_t row, size_t col) const
+{
+ element me;
+ me.type = element_type::empty;
+
+ switch (mp_impl->m_data.get_type(row, col))
+ {
+ case mdds::mtm::element_numeric:
+ me.type = element_type::numeric;
+ me.value = mp_impl->m_data.get_numeric(row, col);
+ break;
+ case mdds::mtm::element_integer:
+ {
+ // This is an error value, which must be negative.
+ auto v = mp_impl->m_data.get_integer(row, col);
+ if (v >= 0)
+ break;
+
+ me.type = element_type::error;
+ me.value = static_cast<formula_error_t>(-v);
+ break;
+ }
+ case mdds::mtm::element_string:
+ {
+ me.type = element_type::string;
+ me.value = mp_impl->m_data.get_string(row, col);
+ break;
+ }
+ case mdds::mtm::element_boolean:
+ {
+ me.type = element_type::boolean;
+ me.value = mp_impl->m_data.get_boolean(row, col);
+ break;
+ }
+ default:
+ ;
+ }
+
+ return me;
+}
+
+size_t matrix::row_size() const
+{
+ return mp_impl->m_data.size().row;
+}
+
+size_t matrix::col_size() const
+{
+ return mp_impl->m_data.size().column;
+}
+
+void matrix::swap(matrix& r)
+{
+ mp_impl.swap(r.mp_impl);
+}
+
+numeric_matrix matrix::as_numeric() const
+{
+ matrix_store_t::size_pair_type mtx_size = mp_impl->m_data.size();
+
+ std::vector<double> num_array(mtx_size.row*mtx_size.column, nan);
+ double* dest = num_array.data();
+
+ std::function<void(const matrix_store_t::element_block_node_type&)> f =
+ [&](const matrix_store_t::element_block_node_type& node)
+ {
+ assert(node.offset == 0);
+
+ switch (node.type)
+ {
+ case mdds::mtm::element_integer:
+ {
+ // String and error values will be handled as numeric values of 0.0.
+#ifndef __STDC_IEC_559__
+ throw std::runtime_error("IEEE 754 is not fully supported.");
+#endif
+ std::memset(dest, 0, sizeof(double)*node.size); // IEEE 754 defines 0.0 to be 8 zero bytes.
+ std::advance(dest, node.size);
+ break;
+ }
+ case mdds::mtm::element_boolean:
+ {
+ using block_type = matrix_store_t::boolean_block_type;
+ auto it = block_type::begin(*node.data);
+ auto ite = block_type::end(*node.data);
+
+ for (; it != ite; ++it)
+ *dest++ = *it ? 1.0 : 0.0;
+ break;
+ }
+ case mdds::mtm::element_numeric:
+ {
+ using block_type = matrix_store_t::numeric_block_type;
+ const double* src = &block_type::at(*node.data, 0);
+ std::memcpy(dest, src, sizeof(double)*node.size);
+ std::advance(dest, node.size);
+ break;
+ }
+ case mdds::mtm::element_string:
+ {
+ // Skip string blocks.
+ std::advance(dest, node.size);
+ break;
+ }
+ default:
+ ;
+ }
+ };
+
+ mp_impl->m_data.walk(f);
+
+ return numeric_matrix(std::move(num_array), mtx_size.row, mtx_size.column);
+}
+
+bool matrix::operator== (const matrix& r) const
+{
+ return mp_impl->m_data == r.mp_impl->m_data;
+}
+
+bool matrix::operator!= (const matrix& r) const
+{
+ return !operator==(r);
+}
+
+numeric_matrix::numeric_matrix() : mp_impl(std::make_unique<impl>()) {}
+numeric_matrix::numeric_matrix(size_t rows, size_t cols) :
+ mp_impl(std::make_unique<impl>(rows, cols)) {}
+numeric_matrix::numeric_matrix(std::vector<double> array, size_t rows, size_t cols) :
+ mp_impl(std::make_unique<impl>(std::move(array), rows, cols)) {}
+
+numeric_matrix::numeric_matrix(numeric_matrix&& r) : mp_impl(std::move(r.mp_impl)) {}
+
+numeric_matrix::~numeric_matrix() {}
+
+numeric_matrix& numeric_matrix::operator= (numeric_matrix other)
+{
+ numeric_matrix t(std::move(other));
+ swap(t);
+
+ return *this;
+}
+
+double& numeric_matrix::operator() (size_t row, size_t col)
+{
+ size_t pos = mp_impl->to_array_pos(row, col);
+ return mp_impl->m_array[pos];
+}
+
+const double& numeric_matrix::operator() (size_t row, size_t col) const
+{
+ size_t pos = mp_impl->to_array_pos(row, col);
+ return mp_impl->m_array[pos];
+}
+
+void numeric_matrix::swap(numeric_matrix& r)
+{
+ mp_impl.swap(r.mp_impl);
+}
+
+size_t numeric_matrix::row_size() const
+{
+ return mp_impl->m_rows;
+}
+
+size_t numeric_matrix::col_size() const
+{
+ return mp_impl->m_cols;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+