diff options
author | Eike Rathke <erack@redhat.com> | 2019-09-06 16:44:28 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2019-09-06 20:02:18 +0200 |
commit | 2b591a40b0f6894531350ccb733abef3c3e1d9bf (patch) | |
tree | 9293e7eeefff6337d85f6716fd9785c936bcb411 /sc | |
parent | 551f757b27ee7e3f6a316afd5ae8966ff40b7e25 (diff) |
Related: tdf#98844 CreateMatrixFromDoubleRef() for bCalcAsShown ScCellIterator
... to cover ForceArray cases like SUMPRODUCT().
Change-Id: I149ef4a9633f3237d48fc4f2b6011b03bccebc49
Reviewed-on: https://gerrit.libreoffice.org/78721
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/core/tool/interpr5.cxx | 103 |
1 files changed, 102 insertions, 1 deletions
diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx index e928b974d110..a2b8dc5a6fac 100644 --- a/sc/source/core/tool/interpr5.cxx +++ b/sc/source/core/tool/interpr5.cxx @@ -350,7 +350,108 @@ ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken if (!pMat || nGlobalError != FormulaError::NONE) return nullptr; - pDok->FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2); + if (!bCalcAsShown) + { + // Use fast array fill. + pDok->FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2); + } + else + { + // Use slower ScCellIterator to round values. + + // TODO: this probably could use CellBucket for faster storage, see + // sc/source/core/data/column2.cxx and FillMatrixHandler, and then be + // moved to a function on its own, and/or squeeze the rounding into a + // similar FillMatrixHandler that would need to keep track of the cell + // position then. + + // Set position where the next entry is expected. + SCROW nNextRow = nRow1; + SCCOL nNextCol = nCol1; + // Set last position as if there was a previous entry. + SCROW nThisRow = nRow2; + SCCOL nThisCol = nCol1 - 1; + + ScCellIterator aCellIter( pDok, ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2)); + for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next()) + { + nThisCol = aCellIter.GetPos().Col(); + nThisRow = aCellIter.GetPos().Row(); + if (nThisCol != nNextCol || nThisRow != nNextRow) + { + // Fill empty between iterator's positions. + for ( ; nNextCol <= nThisCol; ++nNextCol) + { + const SCSIZE nC = nNextCol - nCol1; + const SCSIZE nMatStopRow = ((nNextCol < nThisCol) ? nMatRows : nThisRow - nRow1); + for (SCSIZE nR = nNextRow - nRow1; nR < nMatStopRow; ++nR) + { + pMat->PutEmpty( nC, nR); + } + nNextRow = nRow1; + } + } + if (nThisRow == nRow2) + { + nNextCol = nThisCol + 1; + nNextRow = nRow1; + } + else + { + nNextCol = nThisCol; + nNextRow = nThisRow + 1; + } + + const SCSIZE nMatCol = static_cast<SCSIZE>(nThisCol - nCol1); + const SCSIZE nMatRow = static_cast<SCSIZE>(nThisRow - nRow1); + ScRefCellValue aCell( aCellIter.getRefCellValue()); + if (aCellIter.isEmpty() || aCell.hasEmptyValue()) + { + pMat->PutEmpty( nMatCol, nMatRow); + } + else if (aCell.hasError()) + { + pMat->PutError( aCell.mpFormula->GetErrCode(), nMatCol, nMatRow); + } + else if (aCell.hasNumeric()) + { + double fVal = aCell.getValue(); + // CELLTYPE_FORMULA already stores the rounded value. + if (aCell.meType == CELLTYPE_VALUE) + { + // TODO: this could be moved to ScCellIterator to take + // advantage of the faster ScAttrArray_IterGetNumberFormat. + const ScAddress aAdr( nThisCol, nThisRow, nTab1); + const sal_uInt32 nNumFormat = pDok->GetNumberFormat( mrContext, aAdr); + fVal = pDok->RoundValueAsShown( fVal, nNumFormat, &mrContext); + } + pMat->PutDouble( fVal, nMatCol, nMatRow); + } + else if (aCell.hasString()) + { + pMat->PutString( mrStrPool.intern( aCell.getString( pDok)), nMatCol, nMatRow); + } + else + { + assert(!"aCell.what?"); + pMat->PutEmpty( nMatCol, nMatRow); + } + } + + // Fill empty if iterator's last position wasn't the end. + if (nThisCol != nCol2 || nThisRow != nRow2) + { + for ( ; nNextCol <= nCol2; ++nNextCol) + { + SCSIZE nC = nNextCol - nCol1; + for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR) + { + pMat->PutEmpty( nC, nR); + } + nNextRow = nRow1; + } + } + } if (pToken && pTokenMatrixMap) pTokenMatrixMap->emplace(pToken, new ScMatrixToken( pMat)); |