1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <recursionhelper.hxx>
11 #include <formulacell.hxx>
13 void ScRecursionHelper::Init()
16 nDependencyComputationLevel
= 0;
17 bInRecursionReturn
= bDoingRecursion
= bInIterationReturn
= false;
18 bAbortingDependencyComputation
= false;
19 aInsertPos
= GetIterationEnd();
21 // Must not force clear aFGList ever.
24 void ScRecursionHelper::ResetIteration()
26 aLastIterationStart
= GetIterationEnd();
31 ScRecursionHelper::ScRecursionHelper()
34 bGroupsIndependent
= true;
38 void ScRecursionHelper::SetInRecursionReturn( bool b
)
40 // Do not use IsInRecursionReturn() here, it decouples iteration.
41 if (b
&& !bInRecursionReturn
)
42 aInsertPos
= aRecursionFormulas
.begin();
43 bInRecursionReturn
= b
;
46 void ScRecursionHelper::Insert(
47 ScFormulaCell
* p
, bool bOldRunning
, const ScFormulaResult
& rRes
)
49 aRecursionFormulas
.insert( aInsertPos
, ScFormulaRecursionEntry( p
,
53 void ScRecursionHelper::SetInIterationReturn( bool b
)
55 // An iteration return is always coupled to a recursion return.
56 SetInRecursionReturn( b
);
57 bInIterationReturn
= b
;
60 void ScRecursionHelper::StartIteration()
62 SetInIterationReturn( false);
65 aLastIterationStart
= GetIterationStart();
68 void ScRecursionHelper::ResumeIteration()
70 SetInIterationReturn( false);
71 aLastIterationStart
= GetIterationStart();
74 void ScRecursionHelper::IncIteration()
79 void ScRecursionHelper::EndIteration()
81 aRecursionFormulas
.erase( GetIterationStart(), GetIterationEnd());
85 ScFormulaRecursionList::iterator
ScRecursionHelper::GetIterationStart()
87 return aRecursionFormulas
.begin();
90 ScFormulaRecursionList::iterator
ScRecursionHelper::GetIterationEnd()
92 return aRecursionFormulas
.end();
95 void ScRecursionHelper::Clear()
97 aRecursionFormulas
.clear();
98 while (!aRecursionInIterationStack
.empty())
99 aRecursionInIterationStack
.pop();
103 static ScFormulaCell
* lcl_GetTopCell(ScFormulaCell
* pCell
)
108 const ScFormulaCellGroupRef
& mxGroup
= pCell
->GetCellGroup();
111 return mxGroup
->mpTopCell
;
114 bool ScRecursionHelper::PushFormulaGroup(ScFormulaCell
* pCell
)
118 if (pCell
->GetSeenInPath())
120 // Found a simple cycle of formula-groups.
121 // Disable group calc for all elements of this cycle.
122 sal_Int32 nIdx
= aFGList
.size();
128 const ScFormulaCellGroupRef
& mxGroup
= aFGList
[nIdx
]->GetCellGroup();
130 mxGroup
->mbPartOfCycle
= true;
131 } while (aFGList
[nIdx
] != pCell
);
136 pCell
->SetSeenInPath(true);
137 aFGList
.push_back(pCell
);
138 aInDependencyEvalMode
.push_back(false);
142 void ScRecursionHelper::PopFormulaGroup()
144 assert(aFGList
.size() == aInDependencyEvalMode
.size());
147 ScFormulaCell
* pCell
= aFGList
.back();
148 pCell
->SetSeenInPath(false);
150 aInDependencyEvalMode
.pop_back();
153 bool ScRecursionHelper::AnyCycleMemberInDependencyEvalMode(const ScFormulaCell
* pCell
)
157 if (pCell
->GetSeenInPath())
159 // Found a simple cycle of formula-groups.
160 sal_Int32 nIdx
= aFGList
.size();
166 const ScFormulaCellGroupRef
& mxGroup
= aFGList
[nIdx
]->GetCellGroup();
167 // Found a cycle member FG that is in dependency evaluation mode.
168 if (mxGroup
&& aInDependencyEvalMode
[nIdx
])
170 } while (aFGList
[nIdx
] != pCell
);
178 bool ScRecursionHelper::AnyParentFGInCycle()
180 sal_Int32 nIdx
= aFGList
.size() - 1;
183 const ScFormulaCellGroupRef
& mxGroup
= aFGList
[nIdx
]->GetCellGroup();
185 return mxGroup
->mbPartOfCycle
;
191 void ScRecursionHelper::SetFormulaGroupDepEvalMode(bool bSet
)
193 assert(aFGList
.size());
194 assert(aFGList
.size() == aInDependencyEvalMode
.size());
195 assert(aFGList
.back()->GetCellGroup());
196 aInDependencyEvalMode
.back() = bSet
;
199 void ScRecursionHelper::AbortDependencyComputation()
201 assert( nDependencyComputationLevel
> 0 );
202 bAbortingDependencyComputation
= true;
205 void ScRecursionHelper::IncDepComputeLevel()
207 ++nDependencyComputationLevel
;
210 void ScRecursionHelper::DecDepComputeLevel()
212 --nDependencyComputationLevel
;
213 bAbortingDependencyComputation
= false;
216 void ScRecursionHelper::AddTemporaryGroupCell(ScFormulaCell
* cell
)
218 aTemporaryGroupCells
.push_back( cell
);
221 void ScRecursionHelper::CleanTemporaryGroupCells()
223 if( GetRecursionCount() == 0 )
225 for( ScFormulaCell
* cell
: aTemporaryGroupCells
)
226 cell
->SetCellGroup( nullptr );
227 aTemporaryGroupCells
.clear();
231 bool ScRecursionHelper::CheckFGIndependence(ScFormulaCellGroup
* pFG
)
233 if (pFGSet
&& pFGSet
->count(pFG
))
235 bGroupsIndependent
= false;
242 ScFormulaGroupCycleCheckGuard::ScFormulaGroupCycleCheckGuard(ScRecursionHelper
& rRecursionHelper
, ScFormulaCell
* pCell
) :
243 mrRecHelper(rRecursionHelper
)
247 pCell
= lcl_GetTopCell(pCell
);
248 mbShouldPop
= mrRecHelper
.PushFormulaGroup(pCell
);
254 ScFormulaGroupCycleCheckGuard::~ScFormulaGroupCycleCheckGuard()
257 mrRecHelper
.PopFormulaGroup();
260 ScFormulaGroupDependencyComputeGuard::ScFormulaGroupDependencyComputeGuard(ScRecursionHelper
& rRecursionHelper
) :
261 mrRecHelper(rRecursionHelper
)
263 mrRecHelper
.IncDepComputeLevel();
264 mrRecHelper
.SetFormulaGroupDepEvalMode(true);
267 ScFormulaGroupDependencyComputeGuard::~ScFormulaGroupDependencyComputeGuard()
269 mrRecHelper
.SetFormulaGroupDepEvalMode(false);
270 mrRecHelper
.DecDepComputeLevel();
273 ScCheckIndependentFGGuard::ScCheckIndependentFGGuard(ScRecursionHelper
& rRecursionHelper
,
274 o3tl::sorted_vector
<ScFormulaCellGroup
*>* pSet
) :
275 mrRecHelper(rRecursionHelper
),
278 if (!mrRecHelper
.HasFormulaGroupSet())
280 mrRecHelper
.SetFormulaGroupSet(pSet
);
281 mrRecHelper
.SetGroupsIndependent(true);
286 ScCheckIndependentFGGuard::~ScCheckIndependentFGGuard()
290 // Reset to defaults.
291 mrRecHelper
.SetFormulaGroupSet(nullptr);
292 mrRecHelper
.SetGroupsIndependent(true);
296 bool ScCheckIndependentFGGuard::AreGroupsIndependent()
301 return mrRecHelper
.AreGroupsIndependent();
304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */