1
0
Fork 0
libreoffice/sc/source/core/tool/recursionhelper.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

304 lines
7.4 KiB
C++

/* -*- 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: */