/* -*- 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/.
*/
SCROW ScGroupTokenConverter::trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
{
SCROW nLastRow = nRow + nRowLen - 1; // current last row.
nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow); if (nLastRow < (nRow + nRowLen - 1))
{ // This can end up negative! Was that the original intent, or // is it accidental? Was it not like that originally but the // surrounding conditions changed? constbool bFail = o3tl::checked_sub(nLastRow + 1, nRow, nRowLen); // Anyway, let's assume it doesn't make sense to return a // negative value here. But should we then return 0 or 1? In // the "Column is empty" case below, we return 1, why!? And, // at the callsites there are tests for a zero value returned // from this function (but not for a negative one). if (bFail || nRowLen < 0)
nRowLen = 0;
} elseif (nLastRow == 0) // Column is empty.
nRowLen = 1;
const SCROW nLen = mrCell.GetCellGroup()->mnLength;
formula::FormulaTokenArrayPlainIterator aIter(rCode); for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
{ // A reference can be either absolute or relative. If it's absolute, // convert it to a static value token. If relative, convert it to a // vector reference token. Note: we only care about relative vs // absolute reference state for row directions.
switch (p->GetType())
{ case svSingleRef:
{
ScSingleRefData aRef = *p->GetSingleRef(); if( aRef.IsDeleted()) returnfalse;
ScAddress aRefPos = aRef.toAbs(mrDoc, mrPos); if (aRef.IsRowRel())
{ if (isSelfReferenceRelative(aRefPos, aRef.Row())) returnfalse;
// Trim data array length to actual data range.
SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen); // Fetch double array guarantees that the length of the // returned array equals or greater than the requested // length.
formula::VectorRefArray aArray; if (nTrimLen)
{ #ifdef DBG_UTIL // All the necessary Interpret() calls for all the cells // should have been already handled by ScDependantsCalculator // calling HandleRefArrayForParallelism(), and that handling also checks // for cycles etc. Recursively calling Interpret() from here (which shouldn't // happen) could lead to unhandled problems. // Also, because of caching FetchVectorRefArray() fetches values for all rows // up to the maximum one, so check those too.
mrDoc.AssertNoInterpretNeeded(
ScAddress(aRefPos.Col(), 0, aRefPos.Tab()), nTrimLen + aRefPos.Row()); #endif
aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
}
if (nTrimLen && !mxFormulaGroupContext)
{ //tdf#98880 if the SingleVectorRefToken relies on the //underlying storage provided by the Document //FormulaGroupContext, take a reference to it here to //ensure that backing storage exists for our lifetime
mxFormulaGroupContext = mrDoc.GetFormulaGroupContext();
}
} else
{ // Absolute row reference. if (isSelfReferenceAbsolute(aRefPos)) returnfalse;
formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos); if (!pNewToken) returnfalse;
mrGroupTokens.AddToken(*pNewToken);
rScope.addRefMessage(mrPos, aRefPos, *pNewToken);
}
} break; case svDoubleRef:
{ // This code may break in case of implicit intersection, leading to unnecessarily large // matrix operations and possibly incorrect results (=C:C/D:D). That is handled by // having ScCompiler check that there are no possible implicit intersections. // Additionally some functions such as INDEX() and OFFSET() require a reference, // that is handled by denylisting those opcodes in ScTokenArray::CheckToken().
// Multiple sheets not handled by vector/matrix. if (aAbs.aStart.Tab() != aAbs.aEnd.Tab()) returnfalse;
// Check for self reference. if (aRef.Ref1.IsRowRel())
{ if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row())) returnfalse;
} elseif (isSelfReferenceAbsolute(aAbs.aStart)) returnfalse;
if (aRef.Ref2.IsRowRel())
{ if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row())) returnfalse;
} elseif (isSelfReferenceAbsolute(aAbs.aEnd)) returnfalse;
if (nArrayLength && !aArrays.empty() && !mxFormulaGroupContext)
{ //tdf#98880 if the DoubleVectorRefToken relies on the //underlying storage provided by the Document //FormulaGroupContext, take a reference to it here to //ensure that backing storage exists for our lifetime
mxFormulaGroupContext = mrDoc.GetFormulaGroupContext();
}
} break; case svIndex:
{ if (p->GetOpCode() != ocName)
{ // May be DB-range or TableRef
mrGroupTokens.AddToken(*p); break;
}
// Named range.
ScRangeName* pNames = mrDoc.GetRangeName(); if (!pNames) // This should never fail. returnfalse;
ScRangeData* pRange = pNames->findByIndex(p->GetIndex()); if (!pRange) // No named range exists by that index. returnfalse;
ScTokenArray* pNamedTokens = pRange->GetCode(); if (!pNamedTokens) // This named range is empty. returnfalse;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.