summaryrefslogtreecommitdiffstats
path: root/sc/source/core/tool/recursionhelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/tool/recursionhelper.cxx')
-rw-r--r--sc/source/core/tool/recursionhelper.cxx304
1 files changed, 304 insertions, 0 deletions
diff --git a/sc/source/core/tool/recursionhelper.cxx b/sc/source/core/tool/recursionhelper.cxx
new file mode 100644
index 000000000..59601f37a
--- /dev/null
+++ b/sc/source/core/tool/recursionhelper.cxx
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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 <recursionhelper.hxx>
+#include <formulacell.hxx>
+
+void ScRecursionHelper::Init()
+{
+ nRecursionCount = 0;
+ nDependencyComputationLevel = 0;
+ bInRecursionReturn = bDoingRecursion = bInIterationReturn = false;
+ bAbortingDependencyComputation = false;
+ aInsertPos = GetIterationEnd();
+ ResetIteration();
+ // Must not force clear aFGList ever.
+}
+
+void ScRecursionHelper::ResetIteration()
+{
+ aLastIterationStart = GetIterationEnd();
+ nIteration = 0;
+ bConverging = false;
+}
+
+ScRecursionHelper::ScRecursionHelper()
+{
+ pFGSet = nullptr;
+ bGroupsIndependent = true;
+ Init();
+}
+
+void ScRecursionHelper::SetInRecursionReturn( bool b )
+{
+ // Do not use IsInRecursionReturn() here, it decouples iteration.
+ if (b && !bInRecursionReturn)
+ aInsertPos = aRecursionFormulas.begin();
+ bInRecursionReturn = b;
+}
+
+void ScRecursionHelper::Insert(
+ ScFormulaCell* p, bool bOldRunning, const ScFormulaResult & rRes )
+{
+ aRecursionFormulas.insert( aInsertPos, ScFormulaRecursionEntry( p,
+ bOldRunning, rRes));
+}
+
+void ScRecursionHelper::SetInIterationReturn( bool b )
+{
+ // An iteration return is always coupled to a recursion return.
+ SetInRecursionReturn( b);
+ bInIterationReturn = b;
+}
+
+void ScRecursionHelper::StartIteration()
+{
+ SetInIterationReturn( false);
+ nIteration = 1;
+ bConverging = false;
+ aLastIterationStart = GetIterationStart();
+}
+
+void ScRecursionHelper::ResumeIteration()
+{
+ SetInIterationReturn( false);
+ aLastIterationStart = GetIterationStart();
+}
+
+void ScRecursionHelper::IncIteration()
+{
+ ++nIteration;
+}
+
+void ScRecursionHelper::EndIteration()
+{
+ aRecursionFormulas.erase( GetIterationStart(), GetIterationEnd());
+ ResetIteration();
+}
+
+ScFormulaRecursionList::iterator ScRecursionHelper::GetIterationStart()
+{
+ return aRecursionFormulas.begin();
+}
+
+ScFormulaRecursionList::iterator ScRecursionHelper::GetIterationEnd()
+{
+ return aRecursionFormulas.end();
+}
+
+void ScRecursionHelper::Clear()
+{
+ aRecursionFormulas.clear();
+ while (!aRecursionInIterationStack.empty())
+ aRecursionInIterationStack.pop();
+ Init();
+}
+
+static ScFormulaCell* lcl_GetTopCell(ScFormulaCell* pCell)
+{
+ if (!pCell)
+ return nullptr;
+
+ const ScFormulaCellGroupRef& mxGroup = pCell->GetCellGroup();
+ if (!mxGroup)
+ return pCell;
+ return mxGroup->mpTopCell;
+}
+
+bool ScRecursionHelper::PushFormulaGroup(ScFormulaCell* pCell)
+{
+ assert(pCell);
+
+ if (pCell->GetSeenInPath())
+ {
+ // Found a simple cycle of formula-groups.
+ // Disable group calc for all elements of this cycle.
+ sal_Int32 nIdx = aFGList.size();
+ assert(nIdx > 0);
+ do
+ {
+ --nIdx;
+ assert(nIdx >= 0);
+ const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
+ if (mxGroup)
+ mxGroup->mbPartOfCycle = true;
+ } while (aFGList[nIdx] != pCell);
+
+ return false;
+ }
+
+ pCell->SetSeenInPath(true);
+ aFGList.push_back(pCell);
+ aInDependencyEvalMode.push_back(false);
+ return true;
+}
+
+void ScRecursionHelper::PopFormulaGroup()
+{
+ assert(aFGList.size() == aInDependencyEvalMode.size());
+ if (aFGList.empty())
+ return;
+ ScFormulaCell* pCell = aFGList.back();
+ pCell->SetSeenInPath(false);
+ aFGList.pop_back();
+ aInDependencyEvalMode.pop_back();
+}
+
+bool ScRecursionHelper::AnyCycleMemberInDependencyEvalMode(const ScFormulaCell* pCell)
+{
+ assert(pCell);
+
+ if (pCell->GetSeenInPath())
+ {
+ // Found a simple cycle of formula-groups.
+ sal_Int32 nIdx = aFGList.size();
+ assert(nIdx > 0);
+ do
+ {
+ --nIdx;
+ assert(nIdx >= 0);
+ const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
+ // Found a cycle member FG that is in dependency evaluation mode.
+ if (mxGroup && aInDependencyEvalMode[nIdx])
+ return true;
+ } while (aFGList[nIdx] != pCell);
+
+ return false;
+ }
+
+ return false;
+}
+
+bool ScRecursionHelper::AnyParentFGInCycle()
+{
+ sal_Int32 nIdx = aFGList.size() - 1;
+ while (nIdx >= 0)
+ {
+ const ScFormulaCellGroupRef& mxGroup = aFGList[nIdx]->GetCellGroup();
+ if (mxGroup)
+ return mxGroup->mbPartOfCycle;
+ --nIdx;
+ };
+ return false;
+}
+
+void ScRecursionHelper::SetFormulaGroupDepEvalMode(bool bSet)
+{
+ assert(aFGList.size());
+ assert(aFGList.size() == aInDependencyEvalMode.size());
+ assert(aFGList.back()->GetCellGroup());
+ aInDependencyEvalMode.back() = bSet;
+}
+
+void ScRecursionHelper::AbortDependencyComputation()
+{
+ assert( nDependencyComputationLevel > 0 );
+ bAbortingDependencyComputation = true;
+}
+
+void ScRecursionHelper::IncDepComputeLevel()
+{
+ ++nDependencyComputationLevel;
+}
+
+void ScRecursionHelper::DecDepComputeLevel()
+{
+ --nDependencyComputationLevel;
+ bAbortingDependencyComputation = false;
+}
+
+void ScRecursionHelper::AddTemporaryGroupCell(ScFormulaCell* cell)
+{
+ aTemporaryGroupCells.push_back( cell );
+}
+
+void ScRecursionHelper::CleanTemporaryGroupCells()
+{
+ if( GetRecursionCount() == 0 )
+ {
+ for( ScFormulaCell* cell : aTemporaryGroupCells )
+ cell->SetCellGroup( nullptr );
+ aTemporaryGroupCells.clear();
+ }
+}
+
+bool ScRecursionHelper::CheckFGIndependence(ScFormulaCellGroup* pFG)
+{
+ if (pFGSet && pFGSet->count(pFG))
+ {
+ bGroupsIndependent = false;
+ return false;
+ }
+
+ return true;
+}
+
+ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper& rRecursionHelper, ScFormulaCell* pCell) :
+ mrRecHelper(rRecursionHelper)
+{
+ if (pCell)
+ {
+ pCell = lcl_GetTopCell(pCell);
+ mbShouldPop = mrRecHelper.PushFormulaGroup(pCell);
+ }
+ else
+ mbShouldPop = false;
+}
+
+ScFormulaGroupCycleCheckGuard::~ScFormulaGroupCycleCheckGuard()
+{
+ if (mbShouldPop)
+ mrRecHelper.PopFormulaGroup();
+}
+
+ScFormulaGroupDependencyComputeGuard::ScFormulaGroupDependencyComputeGuard(ScRecursionHelper& rRecursionHelper) :
+ mrRecHelper(rRecursionHelper)
+{
+ mrRecHelper.IncDepComputeLevel();
+ mrRecHelper.SetFormulaGroupDepEvalMode(true);
+}
+
+ScFormulaGroupDependencyComputeGuard::~ScFormulaGroupDependencyComputeGuard()
+{
+ mrRecHelper.SetFormulaGroupDepEvalMode(false);
+ mrRecHelper.DecDepComputeLevel();
+}
+
+ScCheckIndependentFGGuard::ScCheckIndependentFGGuard(ScRecursionHelper& rRecursionHelper,
+ o3tl::sorted_vector<ScFormulaCellGroup*>* pSet) :
+ mrRecHelper(rRecursionHelper),
+ mbUsedFGSet(false)
+{
+ if (!mrRecHelper.HasFormulaGroupSet())
+ {
+ mrRecHelper.SetFormulaGroupSet(pSet);
+ mrRecHelper.SetGroupsIndependent(true);
+ mbUsedFGSet = true;
+ }
+}
+
+ScCheckIndependentFGGuard::~ScCheckIndependentFGGuard()
+{
+ if (mbUsedFGSet)
+ {
+ // Reset to defaults.
+ mrRecHelper.SetFormulaGroupSet(nullptr);
+ mrRecHelper.SetGroupsIndependent(true);
+ }
+}
+
+bool ScCheckIndependentFGGuard::AreGroupsIndependent()
+{
+ if (!mbUsedFGSet)
+ return false;
+
+ return mrRecHelper.AreGroupsIndependent();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */