diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2017-05-22 21:08:56 -0400 |
---|---|---|
committer | Kohei Yoshida <libreoffice@kohei.us> | 2017-05-24 05:19:40 +0200 |
commit | d4cd8677889ec3807c194ef5b462f8e031807e5b (patch) | |
tree | 4b53429527d6358d145feef9912d0460924cbde0 /sc | |
parent | 7948e84091f37fbda75f524f20138d1171918e64 (diff) |
tdf#107945: properly iterate over mtv during pivot cache loading.
This reduces the total time required for populating the pivot cache
by ~60%.
Change-Id: I6a8511959c20231a8a5dbd0b0a9a3d0930a1fa0c
Reviewed-on: https://gerrit.libreoffice.org/37971
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Kohei Yoshida <libreoffice@kohei.us>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/Library_sc.mk | 1 | ||||
-rw-r--r-- | sc/inc/cellvalue.hxx | 33 | ||||
-rw-r--r-- | sc/inc/column.hxx | 5 | ||||
-rw-r--r-- | sc/inc/columniterator.hxx | 29 | ||||
-rw-r--r-- | sc/inc/document.hxx | 13 | ||||
-rw-r--r-- | sc/inc/formulacell.hxx | 10 | ||||
-rw-r--r-- | sc/inc/mtvcellfunc.hxx | 12 | ||||
-rw-r--r-- | sc/inc/table.hxx | 5 | ||||
-rw-r--r-- | sc/source/core/data/cellvalue.cxx | 46 | ||||
-rw-r--r-- | sc/source/core/data/column4.cxx | 26 | ||||
-rw-r--r-- | sc/source/core/data/columniterator.cxx | 37 | ||||
-rw-r--r-- | sc/source/core/data/document10.cxx | 23 | ||||
-rw-r--r-- | sc/source/core/data/dpcache.cxx | 47 | ||||
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 14 | ||||
-rw-r--r-- | sc/source/core/data/mtvcellfunc.cxx | 31 | ||||
-rw-r--r-- | sc/source/core/data/table7.cxx | 18 |
16 files changed, 324 insertions, 26 deletions
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk index 3b2e88529977..e72c61546f05 100644 --- a/sc/Library_sc.mk +++ b/sc/Library_sc.mk @@ -157,6 +157,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ sc/source/core/data/markarr \ sc/source/core/data/markdata \ sc/source/core/data/markmulti \ + sc/source/core/data/mtvcellfunc \ sc/source/core/data/mtvelements \ sc/source/core/data/olinetab \ sc/source/core/data/pagepar \ diff --git a/sc/inc/cellvalue.hxx b/sc/inc/cellvalue.hxx index 4ebd29889fee..430212245870 100644 --- a/sc/inc/cellvalue.hxx +++ b/sc/inc/cellvalue.hxx @@ -132,19 +132,38 @@ struct SC_DLLPUBLIC ScRefCellValue bool hasNumeric() const; + bool hasError() const; + double getValue(); - /** Retrieve string value. + /** + * Retrieve a numeric value without modifying the states of any objects in + * the referenced document store. + */ + double getRawValue() const; - @param pDoc - Needed to resolve EditCells' field contents, obtain a - ScFieldEditEngine from that document. May be NULL if there is - no ScDocument in the calling context but then the document - specific fields can not be resolved. See - ScEditUtil::GetString(). + /** + * Retrieve string value. + * + * Note that this method is NOT thread-safe. + * + * @param pDoc + * Needed to resolve EditCells' field contents, obtain a + * ScFieldEditEngine from that document. May be NULL if there is + * no ScDocument in the calling context but then the document + * specific fields can not be resolved. See + * ScEditUtil::GetString(). */ OUString getString( const ScDocument* pDoc ); + /** + * Retrieve a string value without modifying the states of any objects in + * the referenced document store. + * + * This method is thread-safe. + */ + OUString getRawString( const ScDocument* pDoc ) const; + bool isEmpty() const; bool hasEmptyValue(); diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index d406a21ac784..69caa12e648a 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -67,6 +67,7 @@ class CompileFormulaContext; struct SetFormulaDirtyContext; class RefMovedHint; enum class MatrixEdge; +class ColumnIterator; } @@ -666,6 +667,10 @@ public: void SwapNonEmpty( sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ); + std::unique_ptr<sc::ColumnIterator> GetColumnIterator( SCROW nRow1, SCROW nRow2 ) const; + + void EnsureFormulaCellResults( SCROW nRow1, SCROW nRow2 ); + #if DUMP_COLUMN_STORAGE void DumpColumnStorage() const; #endif diff --git a/sc/inc/columniterator.hxx b/sc/inc/columniterator.hxx index b36df3df6dbd..c6a87b4e6b39 100644 --- a/sc/inc/columniterator.hxx +++ b/sc/inc/columniterator.hxx @@ -49,6 +49,35 @@ private: void checkEndRow(); }; +namespace sc { + +/** + * This iterator lets you iterate over cells over specified range in a + * single column. It does not modify the state of the cells, and therefore + * is thread safe. + */ +class ColumnIterator +{ + CellStoreType::const_position_type maPos; + CellStoreType::const_position_type maPosEnd; + +public: + ColumnIterator( const CellStoreType& rCells, SCROW nRow1, SCROW nRow2 ); + ~ColumnIterator(); + + void next(); + + SCROW getRow() const; + + bool hasCell() const; + + mdds::mtv::element_t getType() const; + + ScRefCellValue getCell() const; +}; + +} + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index da3f6feb2d66..ca8a02769af4 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -85,6 +85,7 @@ class FormulaGroupAreaListener; class ColumnSet; class UpdatedRangeNames; class TableColumnBlockPositionSet; +class ColumnIterator; } @@ -2281,10 +2282,22 @@ public: */ void PrepareFormulaCalc(); + /** + * Make sure all of the formula cells in the specified range have been + * fully calculated. This method only re-calculates those formula cells + * that have been flagged dirty. + * + * @param rRange range in which to potentially calculate the formula + * cells. + */ + void EnsureFormulaCellResults( const ScRange& rRange ); + SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ); const SvtBroadcaster* GetBroadcaster( const ScAddress& rPos ) const; void DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, const ScAddress& rTopPos, SCROW nLength ); + std::unique_ptr<sc::ColumnIterator> GetColumnIterator( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const; + #if DUMP_COLUMN_STORAGE SC_DLLPUBLIC void DumpColumnStorage( SCTAB nTab, SCCOL nCol ) const; #endif diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index fce0227805e1..d4cc6949aa48 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -298,6 +298,16 @@ public: bool IsValueNoError() const; double GetValue(); svl::SharedString GetString(); + + /** + * Get a numeric value without potentially triggering re-calculation. + */ + double GetRawValue() const; + + /** + * Get a string value without potentially triggering re-calculation. + */ + svl::SharedString GetRawString() const; const ScMatrix* GetMatrix(); bool GetMatrixOrigin( ScAddress& rPos ) const; void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows ); diff --git a/sc/inc/mtvcellfunc.hxx b/sc/inc/mtvcellfunc.hxx index db72fd4a3278..195e6449007a 100644 --- a/sc/inc/mtvcellfunc.hxx +++ b/sc/inc/mtvcellfunc.hxx @@ -13,6 +13,10 @@ #include "mtvelements.hxx" #include "mtvfunctions.hxx" +#include <functional> + +class ScFormulaCell; + namespace sc { template<typename Func> @@ -32,6 +36,14 @@ ProcessFormula( CellStoreType, formula_block, FuncElem, FuncElseNoOp<size_t> >(it, rStore, nRow1, nRow2, rFuncElem, aElse); } +/** + * Process formula cells found within specified row range. This function + * allows modifications of the states of the formula function objects. + */ +CellStoreType::iterator ProcessFormula( + const CellStoreType::iterator& it, CellStoreType& rStore, SCROW nRow1, SCROW nRow2, + std::function<void(size_t,ScFormulaCell*)> aFuncElem ); + template<typename FuncElem, typename FuncElse> typename CellStoreType::iterator ProcessFormula( diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index ef94249026b4..1227847fea2e 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -78,6 +78,7 @@ class CompileFormulaContext; struct SetFormulaDirtyContext; class RefMovedHint; struct ReorderParam; +class ColumnIterator; } @@ -992,6 +993,10 @@ public: void TransferCellValuesTo( SCCOL nCol, SCROW nRow, size_t nLen, sc::CellValues& rDest ); void CopyCellValuesFrom( SCCOL nCol, SCROW nRow, const sc::CellValues& rSrc ); + std::unique_ptr<sc::ColumnIterator> GetColumnIterator( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const; + + void EnsureFormulaCellResults( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + void ConvertFormulaToValue( sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sc::TableValues* pUndo ); diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx index efe66f789596..75b7c5bbb12f 100644 --- a/sc/source/core/data/cellvalue.cxx +++ b/sc/source/core/data/cellvalue.cxx @@ -17,6 +17,7 @@ #include "editutil.hxx" #include "tokenarray.hxx" #include <formula/token.hxx> +#include <formula/errorcodes.hxx> #include <svl/sharedstring.hxx> namespace { @@ -178,6 +179,27 @@ OUString getStringImpl( const CellT& rCell, const ScDocument* pDoc ) return EMPTY_OUSTRING; } +template<typename CellT> +OUString getRawStringImpl( const CellT& rCell, const ScDocument* pDoc ) +{ + switch (rCell.meType) + { + case CELLTYPE_VALUE: + return OUString::number(rCell.mfValue); + case CELLTYPE_STRING: + return rCell.mpString->getString(); + case CELLTYPE_EDIT: + if (rCell.mpEditText) + return ScEditUtil::GetString(*rCell.mpEditText, pDoc); + break; + case CELLTYPE_FORMULA: + return rCell.mpFormula->GetRawString().getString(); + default: + ; + } + return EMPTY_OUSTRING; +} + } ScCellValue::ScCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {} @@ -544,6 +566,11 @@ bool ScRefCellValue::hasNumeric() const return hasNumericImpl(meType, mpFormula); } +bool ScRefCellValue::hasError() const +{ + return meType == CELLTYPE_FORMULA && mpFormula->GetErrCode() != FormulaError::NONE; +} + double ScRefCellValue::getValue() { switch (meType) @@ -558,11 +585,30 @@ double ScRefCellValue::getValue() return 0.0; } +double ScRefCellValue::getRawValue() const +{ + switch (meType) + { + case CELLTYPE_VALUE: + return mfValue; + case CELLTYPE_FORMULA: + return mpFormula->GetRawValue(); + default: + ; + } + return 0.0; +} + OUString ScRefCellValue::getString( const ScDocument* pDoc ) { return getStringImpl(*this, pDoc); } +OUString ScRefCellValue::getRawString( const ScDocument* pDoc ) const +{ + return getRawStringImpl(*this, pDoc); +} + bool ScRefCellValue::isEmpty() const { return meType == CELLTYPE_NONE; diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 16dd00574ee1..bdecb552bbc4 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -14,6 +14,7 @@ #include <document.hxx> #include <cellvalues.hxx> #include <columnspanset.hxx> +#include <columniterator.hxx> #include <listenercontext.hxx> #include <tokenstringcontext.hxx> #include <mtvcellfunc.hxx> @@ -30,6 +31,7 @@ #include <sharedformula.hxx> #include <svl/sharedstringpool.hxx> +#include <o3tl/make_unique.hxx> #include <vector> #include <cassert> @@ -1577,4 +1579,28 @@ void ScColumn::SetNeedsListeningGroup( SCROW nRow ) (*pp)->SetNeedsListening(true); } +std::unique_ptr<sc::ColumnIterator> ScColumn::GetColumnIterator( SCROW nRow1, SCROW nRow2 ) const +{ + if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2) + return std::unique_ptr<sc::ColumnIterator>(); + + return o3tl::make_unique<sc::ColumnIterator>(maCells, nRow1, nRow2); +} + +void ScColumn::EnsureFormulaCellResults( SCROW nRow1, SCROW nRow2 ) +{ + if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2) + return; + + if (!HasFormulaCell(nRow1, nRow2)) + return; + + sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, + []( size_t /*nRow*/, ScFormulaCell* pCell ) + { + pCell->MaybeInterpret(); + } + ); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/columniterator.cxx b/sc/source/core/data/columniterator.cxx index bff9aa1e9033..6c26da24775d 100644 --- a/sc/source/core/data/columniterator.cxx +++ b/sc/source/core/data/columniterator.cxx @@ -168,4 +168,41 @@ void ScColumnTextWidthIterator::checkEndRow() miBlockCur = miBlockEnd; } +namespace sc { + +ColumnIterator::ColumnIterator( const CellStoreType& rCells, SCROW nRow1, SCROW nRow2 ) : + maPos(rCells.position(nRow1)), + maPosEnd(rCells.position(maPos.first, nRow2+1)) +{ +} + +ColumnIterator::~ColumnIterator() {} + +void ColumnIterator::next() +{ + maPos = CellStoreType::next_position(maPos); +} + +SCROW ColumnIterator::getRow() const +{ + return CellStoreType::logical_position(maPos); +} + +bool ColumnIterator::hasCell() const +{ + return maPos != maPosEnd; +} + +mdds::mtv::element_t ColumnIterator::getType() const +{ + return maPos.first->type; +} + +ScRefCellValue ColumnIterator::getCell() const +{ + return toRefCell(maPos.first, maPos.second); +} + +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index 1273a17bc87f..2dc37a90c937 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -21,6 +21,7 @@ #include <bcaslot.hxx> #include <cellvalues.hxx> #include <docpool.hxx> +#include <columniterator.hxx> #include "dociter.hxx" #include "patattr.hxx" @@ -904,4 +905,26 @@ bool ScDocument::IsEditActionAllowed( return true; } +std::unique_ptr<sc::ColumnIterator> ScDocument::GetColumnIterator( SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const +{ + const ScTable* pTab = FetchTable(nTab); + if (!pTab) + return std::unique_ptr<sc::ColumnIterator>(); + + return pTab->GetColumnIterator(nCol, nRow1, nRow2); +} + +void ScDocument::EnsureFormulaCellResults( const ScRange& rRange ) +{ + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + pTab->EnsureFormulaCellResults( + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/dpcache.cxx b/sc/source/core/data/dpcache.cxx index 0afeedfe3580..461ffdc14bc6 100644 --- a/sc/source/core/data/dpcache.cxx +++ b/sc/source/core/data/dpcache.cxx @@ -17,7 +17,6 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <memory> #include "dpcache.hxx" #include "document.hxx" @@ -30,6 +29,8 @@ #include "dpitemdata.hxx" #include "dputil.hxx" #include "dpnumgroupinfo.hxx" +#include <columniterator.hxx> +#include <cellvalue.hxx> #include <rtl/math.hxx> #include <unotools/textsearch.hxx> @@ -105,9 +106,10 @@ private: ScDocument* mpDoc; }; -OUString createLabelString(ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab) +OUString createLabelString( const ScDocument* pDoc, SCCOL nCol, const ScRefCellValue& rCell ) { - OUString aDocStr = pDoc->GetString(nCol, nRow, nTab); + OUString aDocStr = rCell.getRawString(pDoc); + if (aDocStr.isEmpty()) { // Replace an empty label string with column name. @@ -123,25 +125,24 @@ OUString createLabelString(ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab) } void initFromCell( - ScDPCache& rCache, ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, + ScDPCache& rCache, ScDocument* pDoc, const ScAddress& rPos, + const ScRefCellValue& rCell, ScDPItemData& rData, sal_uInt32& rNumFormat) { - OUString aDocStr = pDoc->GetString(nCol, nRow, nTab); + OUString aDocStr = rCell.getRawString(pDoc); rNumFormat = 0; - ScAddress aPos(nCol, nRow, nTab); - - if (pDoc->GetErrCode(aPos) != FormulaError::NONE) + if (rCell.hasError()) { rData.SetErrorString(rCache.InternString(aDocStr)); } - else if (pDoc->HasValueData(nCol, nRow, nTab)) + else if (rCell.hasNumeric()) { - double fVal = pDoc->GetValue(aPos); - rNumFormat = pDoc->GetNumberFormat(aPos); + double fVal = rCell.getRawValue(); + rNumFormat = pDoc->GetNumberFormat(rPos); rData.SetValue(fVal); } - else if (pDoc->HasData(nCol, nRow, nTab)) + else if (!rCell.isEmpty()) { rData.SetString(rCache.InternString(aDocStr)); } @@ -322,21 +323,33 @@ void ScDPCache::InitFromDoc(ScDocument* pDoc, const ScRange& rRange) maLabelNames.reserve(mnColumnCount+1); + // Ensure that none of the formula cells in the data range are dirty. + pDoc->EnsureFormulaCellResults(rRange); + ScDPItemData aData; for (sal_uInt16 nCol = nStartCol; nCol <= nEndCol; ++nCol) { - AddLabel(createLabelString(pDoc, nCol, nStartRow, nDocTab)); + std::unique_ptr<sc::ColumnIterator> pIter = + pDoc->GetColumnIterator(nDocTab, nCol, nStartRow, nEndRow); + assert(pIter); + assert(pIter->hasCell()); + + AddLabel(createLabelString(pDoc, nCol, pIter->getCell())); + pIter->next(); + Field& rField = *maFields[nCol-nStartCol].get(); std::vector<Bucket> aBuckets; aBuckets.reserve(nEndRow-nStartRow); // skip the topmost label cell. // Push back all original values. - SCROW nOffset = nStartRow + 1; - for (SCROW i = 0, n = nEndRow-nStartRow; i < n; ++i) + for (SCROW i = 0, n = nEndRow-nStartRow; i < n; ++i, pIter->next()) { - SCROW nRow = i + nOffset; + assert(pIter->hasCell()); + sal_uInt32 nNumFormat = 0; - initFromCell(*this, pDoc, nCol, nRow, nDocTab, aData, nNumFormat); + ScAddress aPos(nCol, pIter->getRow(), nDocTab); + initFromCell(*this, pDoc, aPos, pIter->getCell(), aData, nNumFormat); + aBuckets.push_back(Bucket(aData, i)); if (!aData.IsEmpty()) diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index b23814f77047..0fe70dbcafeb 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -2597,15 +2597,25 @@ bool ScFormulaCell::IsValueNoError() const double ScFormulaCell::GetValue() { MaybeInterpret(); + return GetRawValue(); +} + +svl::SharedString ScFormulaCell::GetString() +{ + MaybeInterpret(); + return GetRawString(); +} + +double ScFormulaCell::GetRawValue() const +{ if ((pCode->GetCodeError() == FormulaError::NONE) && aResult.GetResultError() == FormulaError::NONE) return aResult.GetDouble(); return 0.0; } -svl::SharedString ScFormulaCell::GetString() +svl::SharedString ScFormulaCell::GetRawString() const { - MaybeInterpret(); if ((pCode->GetCodeError() == FormulaError::NONE) && aResult.GetResultError() == FormulaError::NONE) return aResult.GetString(); diff --git a/sc/source/core/data/mtvcellfunc.cxx b/sc/source/core/data/mtvcellfunc.cxx new file mode 100644 index 000000000000..98f6998cc120 --- /dev/null +++ b/sc/source/core/data/mtvcellfunc.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <mtvcellfunc.hxx> + +namespace sc { + +CellStoreType::iterator ProcessFormula( + const CellStoreType::iterator& it, CellStoreType& rStore, SCROW nRow1, SCROW nRow2, + std::function<void(size_t,ScFormulaCell*)> aFuncElem ) +{ + using FuncType = std::function<void(size_t,ScFormulaCell*)>; + using ElseFuncType = std::function<void(mdds::mtv::element_t, size_t, size_t)>; + + // empty function for handling the 'else' part. + static ElseFuncType aFuncElse = + [](mdds::mtv::element_t,size_t,size_t) {}; + + return ProcessElements1< + CellStoreType, formula_block, + FuncType, ElseFuncType>( + it, rStore, nRow1, nRow2, aFuncElem, aFuncElse); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index 723a3d64c3fb..acd21d415493 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -17,6 +17,7 @@ #include <cellvalues.hxx> #include "olinetab.hxx" #include <tabprotection.hxx> +#include <columniterator.hxx> bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const { @@ -392,6 +393,23 @@ bool ScTable::IsEditActionAllowed( return false; } +std::unique_ptr<sc::ColumnIterator> ScTable::GetColumnIterator( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const +{ + if (!ValidCol(nCol) || nCol >= aCol.size()) + return std::unique_ptr<sc::ColumnIterator>(); + + return aCol[nCol].GetColumnIterator(nRow1, nRow2); +} + +void ScTable::EnsureFormulaCellResults( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) +{ + if (nCol2 < nCol1 || !ValidCol(nCol1) || !ValidCol(nCol2)) + return; + + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + aCol[nCol].EnsureFormulaCellResults(nRow1, nRow2); +} + void ScTable::finalizeOutlineImport() { if (pOutlineTable && pRowFlags) |