summaryrefslogtreecommitdiffstats
path: root/src/libixion/formula_calc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libixion/formula_calc.cpp')
-rw-r--r--src/libixion/formula_calc.cpp89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/libixion/formula_calc.cpp b/src/libixion/formula_calc.cpp
new file mode 100644
index 0000000..0e16382
--- /dev/null
+++ b/src/libixion/formula_calc.cpp
@@ -0,0 +1,89 @@
+/* -*- 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/formula.hpp>
+#include <ixion/address.hpp>
+#include <ixion/cell.hpp>
+#include <ixion/formula_name_resolver.hpp>
+#include <ixion/model_context.hpp>
+
+#include "queue_entry.hpp"
+#include "debug.hpp"
+
+#if IXION_THREADS
+#include "cell_queue_manager.hpp"
+#endif
+
+#include <algorithm>
+
+namespace ixion {
+
+namespace {
+
+class calc_scope
+{
+ model_context& m_cxt;
+public:
+ calc_scope(model_context& cxt) : m_cxt(cxt)
+ {
+ m_cxt.notify(formula_event_t::calculation_begins);
+ }
+
+ ~calc_scope()
+ {
+ m_cxt.notify(formula_event_t::calculation_ends);
+ }
+};
+
+}
+
+void calculate_sorted_cells(
+ model_context& cxt, const std::vector<abs_range_t>& formula_cells, size_t thread_count)
+{
+#if IXION_THREADS == 0
+ thread_count = 0; // threads are disabled thus not to be used.
+#endif
+
+ calc_scope cs(cxt);
+
+ std::vector<queue_entry> entries;
+ entries.reserve(formula_cells.size());
+
+ for (const abs_range_t& r : formula_cells)
+ entries.emplace_back(cxt.get_formula_cell(r.first), r.first);
+
+ // Reset cell status.
+ for (queue_entry& e : entries)
+ {
+ e.p->reset();
+ IXION_TRACE("pos=" << e.pos.get_name() << " formula=" << detail::print_formula_expression(cxt, e.pos, *e.p));
+ }
+
+ // First, detect circular dependencies and mark those circular
+ // dependent cells with appropriate error flags.
+ for (queue_entry& e : entries)
+ e.p->check_circular(cxt, e.pos);
+
+ if (!thread_count)
+ {
+ // Interpret cells using just a single thread.
+ for (queue_entry& e : entries)
+ e.p->interpret(cxt, e.pos);
+
+ return;
+ }
+
+#if IXION_THREADS
+ // Interpret cells in topological order using threads.
+ formula_cell_queue queue(cxt, std::move(entries), thread_count);
+ queue.run();
+#endif
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */