29#include <document.hxx>
38#include <progress.hxx>
55#include <osl/diagnose.h>
62template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
66 , nStopOnMismatch( nStopOnMismatchDisabled )
67 , nTestEqualCondition( nTestEqualConditionDisabled )
68 , bAdvanceQuery( false )
69 , bIgnoreMismatchOnLeadingStrings( false )
79 for (
i = 0; (
i <
nCount) && (maParam.GetEntry(
i).bDoQuery); ++
i)
84 bool bNumber =
mrContext.GetFormatTable()->IsNumberFormat(
90template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
93 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
97 const bool bSingleQueryItem = rEntry.
GetQueryItems().size() == 1;
99 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
101 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
103 ((maParam.bByRow && nRow == maParam.nRow1) ||
104 (!maParam.bByRow && nCol == maParam.nCol1));
105 bool bTestEqualCondition =
false;
107 (nTestEqualCondition ? &bTestEqualCondition :
nullptr));
112 assert( !bAllStringIgnore );
113 assert( !bIgnoreMismatchOnLeadingStrings );
114 assert( nStopOnMismatch == nStopOnMismatchDisabled );
115 assert( nTestEqualCondition == nTestEqualConditionDisabled );
116 bAllStringIgnore =
false;
117 bIgnoreMismatchOnLeadingStrings =
false;
118 nStopOnMismatch = nStopOnMismatchDisabled;
119 nTestEqualCondition = nTestEqualConditionDisabled;
121 assert( bAdvanceQuery );
122 bAdvanceQuery =
true;
125 const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
128 bool bNextColumn = maCurPos.first == pCol->
maCells.end();
131 if (nRow > maParam.nRow2)
140 if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
144 AdvanceQueryParamEntryField();
145 nFirstQueryField = rEntry.
nField;
147 pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
153 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
171 if(HandleItemFound())
190 (nCol ==
static_cast<SCCOL>(nFirstQueryField) ? &aCell :
nullptr)))
192 if ( nTestEqualCondition && bTestEqualCondition )
193 nTestEqualCondition |= nTestEqualConditionMatched;
194 if ( aCell.isEmpty())
196 if( HandleItemFound())
201 else if ( nStopOnMismatch )
206 if ( nTestEqualCondition && bTestEqualCondition )
208 nTestEqualCondition |= nTestEqualConditionMatched;
209 nStopOnMismatch |= nStopOnMismatchOccurred;
213 if (bFirstStringIgnore)
215 if (aCell.hasString())
227 nStopOnMismatch |= nStopOnMismatchOccurred;
234 bFirstStringIgnore =
false;
238template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
242 AccessBase::InitPos();
247 AccessBase::InitPosStart();
249 SCROW beforeRow = -1;
253 if( BinarySearch( nCol ))
262 if( BinarySearch( nCol,
true ))
269 else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
270 && rDoc.IsEmptyData(nCol, maParam.nRow1, nCol, maParam.nRow2, nTab))
275 lastRow = maParam.nRow2;
280 if( BinarySearch( nCol ))
283 AccessBase::InitPosFinish( beforeRow, lastRow );
287template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
290 SCSIZE nEntries = maParam.GetEntryCount();
291 for (
SCSIZE j = 0; j < nEntries; j++ )
296 if ( rEntry.
nField < rDoc.MaxCol() )
300 assert(!
"AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL");
310template<
typename Iter>
311void incBlock(std::pair<Iter, size_t>& rPos)
318template<
typename Iter>
319void decBlock(std::pair<Iter, size_t>& rPos)
323 rPos.second = rPos.first->size - 1;
328template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
331 assert(maParam.GetEntry(0).bDoQuery && !maParam.GetEntry(1).bDoQuery
332 && maParam.GetEntry(0).GetQueryItems().size() == 1 );
336 assert(maParam.bByRow);
339 || maParam.GetEntry(0).eOp ==
SC_EQUAL);
343 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
345 nRow = maParam.nRow1;
347 if (nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
350 const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
360 bool bForceStr = bByString && ( rEntry.
eOp ==
SC_EQUAL || forEqual );
361 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
362 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
363 !maParam.bHasHeader && bByString;
365 if (maParam.bHasHeader)
368 if (bFirstStringIgnore)
370 sc::CellStoreType::const_position_type aPos = pCol->
maCells.position(nRow);
387 sc::CellStoreType::const_position_type startPos = pCol->
maCells.position(nRow);
393 while (startPos.first != pCol->
maCells.end()
401 if(startPos.first == pCol->
maCells.end())
403 nRow = startPos.first->position + startPos.second;
404 if (nRow > maParam.nRow2)
407 auto aIndexer = MakeBinarySearchIndexer(pCol->
maCells, nRow, maParam.nRow2);
408 if (!aIndexer.isValid())
411 size_t nLo = aIndexer.getLowIndex();
412 size_t nHi = aIndexer.getHighIndex();
413 BinarySearchCellType aCellData;
417 size_t nLastInRange = nLo;
418 double fLastInRangeValue = bAscending ?
419 -(::std::numeric_limits<double>::max()) :
420 ::std::numeric_limits<double>::max();
421 OUString aLastInRangeString;
423 aLastInRangeString = OUString(u
'\xFFFF');
425 aCellData = aIndexer.getCell(nLastInRange);
429 sal_uInt32 nFormat = pCol->
GetNumberFormat(mrContext, aCellData.second);
431 aLastInRangeString =
aStr;
451 std::optional<size_t> found;
453 bool orderBroken =
false;
454 while (nLo <= nHi && !bDone)
456 size_t nMid = (nLo+nHi)/2;
459 aCellData = aIndexer.getCell(i);
460 aCell = aCellData.first;
461 bool bStr = bForceStr || aCell.
hasString();
466 if (!bStr && !bByString)
478 if ((nCellVal < rItem.
mfVal) && !::rtl::math::approxEqual(
479 nCellVal, rItem.
mfVal))
484 if (fLastInRangeValue <= nCellVal)
486 fLastInRangeValue = nCellVal;
489 else if (fLastInRangeValue >= nCellVal)
497 else if ((nCellVal > rItem.
mfVal) && !::rtl::math::approxEqual(
498 nCellVal, rItem.
mfVal))
503 if (fLastInRangeValue >= nCellVal)
505 fLastInRangeValue = nCellVal;
508 else if (fLastInRangeValue <= nCellVal)
517 else if (bStr && bByString)
519 sal_uInt32 nFormat = pCol->
GetNumberFormat(mrContext, aCellData.second);
523 if (nRes < 0 && bAscending)
525 sal_Int32 nTmp = rCollator.
compareString( aLastInRangeString,
529 aLastInRangeString = aCellStr;
539 else if (nRes > 0 && !bAscending)
541 sal_Int32 nTmp = rCollator.
compareString( aLastInRangeString,
545 aLastInRangeString = aCellStr;
556 else if (!bStr && bByString)
623 nLo = aIndexer.getLowIndex();
637 isInRange = nLo != aIndexer.getLowIndex();
647 aCellData = aIndexer.getCell(nLo);
648 if (nLo <= nHi && aCellData.second <= maParam.nRow2)
650 nRow = aCellData.second;
651 maCurPos = aIndexer.getPosition(nLo);
656 nRow = maParam.nRow2 + 1;
658 maCurPos.first = pCol->
maCells.end();
660 maCurPos.second = maCurPos.first->size - 1;
666template< ScQueryCellIteratorAccess accessType >
673 nFoundCol = rDoc.MaxCol()+1;
674 nFoundRow = rDoc.MaxRow()+1;
675 SetStopOnMismatch(
true );
676 SetTestEqualCondition(
true );
677 bIgnoreMismatchOnLeadingStrings =
true;
680 bool bBinary = maParam.bByRow &&
686 if (BinarySearch( maParam.nCol1 ))
690 maParam.mbRangeLookup =
false;
703 PositionType aPosSave;
705 SCSIZE nEntries = maParam.GetEntryCount();
706 std::vector<SCCOL> aFoundFieldPositions(nEntries);
709 nFoundCol = GetCol();
710 nFoundRow = GetRow();
716 if (maParam.mbRangeLookup && bAdvanceQuery)
718 for (
SCSIZE j=0; j < nEntries; ++j)
722 aFoundFieldPositions[j] = maParam.GetEntry(j).
nField;
727 if (IsEqualConditionFulfilled())
735 if (!bNext && !IsEqualConditionFulfilled())
739 bool bColDiff = nCol != nFoundCol;
743 if (maParam.mbRangeLookup)
748 maParam.mbRangeLookup =
false;
750 if (bAdvanceQuery && bColDiff)
752 for (
SCSIZE j=0; j < nEntries; ++j)
757 rEntry.
nField = aFoundFieldPositions[j];
758 assert(rEntry.
nField >= 0);
767 nFoundCol = rDoc.MaxCol()+1;
768 nFoundRow = rDoc.MaxRow()+1;
773 if ( IsEqualConditionFulfilled() )
776 SCSIZE nEntries = maParam.GetEntryCount();
777 for (
SCSIZE j = 0; j < nEntries; j++ )
782 switch ( rEntry.
eOp )
797 PositionType aPosSave;
798 bIgnoreMismatchOnLeadingStrings =
false;
799 SetTestEqualCondition(
false );
802 nFoundCol = GetCol();
803 nFoundRow = GetRow();
814 StoppedOnMismatch() )
818 SCSIZE nEntries = maParam.GetEntryCount();
819 for (
SCSIZE j = 0; j < nEntries; j++ )
824 switch ( rEntry.
eOp )
839 SetStopOnMismatch(
false );
840 SetTestEqualCondition(
false );
846 PositionType aPosSave;
849 nFoundCol = GetCol();
850 nFoundRow = GetRow();
852 SetStopOnMismatch(
true );
859 return (nFoundCol <= rDoc.MaxCol()) && (nFoundRow <= rDoc.MaxRow());
876 nRow = maParam.nRow1;
877 if (maParam.bHasHeader && maParam.bByRow)
879 const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
880 maCurPos = rCol.
maCells.position(nRow);
885 if (maCurPos.second + 1 < maCurPos.first->size)
901 nRow = maCurPos.first->position;
915 typedef std::map<size_t, sc::CellStoreType::const_iterator>
BlockMapType;
938 sc::CellStoreType::const_position_type aLoPos =
mrCells.position(nStartRow);
940 assert(aLoPos.first != rCells.end());
942 SCROW nFirstRow = aLoPos.first->position;
943 SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
945 if (nFirstRow > nEndRow)
954 if (nFirstRow < nStartRow)
963 if (nEndRow < nLastRow)
965 assert(nEndRow >= nFirstRow);
968 maBlockMap.emplace(aLoPos.first->size, aLoPos.first);
974 sc::CellStoreType::const_position_type aHiPos =
mrCells.position(aLoPos.first, nEndRow);
981 SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
982 if (nBlockEndRow < nStartRow)
993 sc::CellStoreType::const_iterator itBlk = aLoPos.first;
994 while (itBlk != aHiPos.first)
1002 nPos += itBlk->size;
1009 assert(itBlk !=
mrCells.end());
1012 assert(itBlk == aHiPos.first);
1013 nPos += itBlk->size;
1017 BlockMapType::const_reverse_iterator ri =
maBlockMap.rbegin();
1023 sc::CellStoreType::const_position_type getPosition(
size_t nIndex )
const
1029 sc::CellStoreType::const_position_type aRet(
mrCells.end(), 0);
1031 BlockMapType::const_iterator it =
maBlockMap.upper_bound(nIndex);
1035 sc::CellStoreType::const_iterator itBlk = it->second;
1036 size_t nBlkIndex = it->first - itBlk->size;
1037 assert(nBlkIndex <= nIndex);
1038 assert(nIndex < it->first);
1040 size_t nOffset =
nIndex - nBlkIndex;
1042 aRet.second = nOffset;
1046 BinarySearchCellType getCell(
size_t nIndex )
const
1048 BinarySearchCellType aRet;
1051 sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
1052 if (aPos.first ==
mrCells.end())
1056 aRet.second = aPos.first->position + aPos.second;
1060 size_t getLowIndex()
const {
return mnLowIndex; }
1062 size_t getHighIndex()
const {
return mnHighIndex; }
1064 bool isValid()
const {
return mbValid; }
1071 return NonEmptyCellIndexer(rCells, nStartRow, nEndRow);
1089 sortedCache = &cache;
1098 ScRange aSortedRangeRange( nCol, maParam.nRow1, nTab, nCol, maParam.nRow2, nTab );
1100 SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &
mrContext ));
1108 pColumn = &rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
1111 sortedCachePos = beforeRow >= 0 ? sortedCache->indexForRow(beforeRow) + 1 : 0;
1112 sortedCachePosLast = sortedCache->indexForRow(lastRow);
1113 if(sortedCachePos <= sortedCachePosLast)
1115 nRow = sortedCache->rowForIndex(sortedCachePos);
1116 maCurPos = pColumn->maCells.position(nRow);
1121 sortedCachePos = sortedCachePosLast = 0;
1122 maCurPos.first = pColumn->maCells.end();
1123 maCurPos.second = 0;
1129 if(sortedCachePos < sortedCachePosLast)
1132 nRow = sortedCache->rowForIndex(sortedCachePos);
1134 if constexpr (!fast)
1138 if(maCurPos.first != pColumn->maCells.end() &&
o3tl::make_unsigned(nRow) >= maCurPos.first->position
1140 maCurPos.second = nRow - maCurPos.first->position;
1142 maCurPos = pColumn->maCells.position(nRow);
1150 maCurPos.first = pColumn->maCells.end();
1151 maCurPos.second = 0;
1176 if( row >= startRow && row <= endRow )
1185 :
mSortedRows( makeSortedRows( cache, startRow, endRow ))
1199 sc::CellStoreType::const_position_type getPosition(
size_t nIndex )
const
1203 return mCells.position(row);
1206 BinarySearchCellType getCell(
size_t nIndex )
const
1208 BinarySearchCellType aRet;
1211 sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
1212 if (aPos.first ==
mCells.end())
1216 aRet.second = aPos.first->position + aPos.second;
1220 size_t getLowIndex()
const {
return mLowIndex; }
1222 size_t getHighIndex()
const {
return mHighIndex; }
1224 bool isValid()
const {
return mValid; }
1231 return SortedCacheIndexer(rCells, nStartRow, nEndRow, sortedCache);
1260 static bool inUnitTest = getenv(
"LO_TESTNAME") !=
nullptr;
1299 getThisResult =
true;
1303template< ScQueryCellIteratorAccess accessType >
1306 getThisResult =
false;
1308 return getThisResult;
1311template< ScQueryCellIteratorAccess accessType >
1314 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
1315 nCol = maParam.nCol1;
1320template< ScQueryCellIteratorAccess accessType >
1324 if ( nStopOnMismatch )
1325 nStopOnMismatch = nStopOnMismatchEnabled;
1326 if ( nTestEqualCondition )
1327 nTestEqualCondition = nTestEqualConditionEnabled;
1366template< ScQueryCellIteratorAccess accessType >
1370 SetAdvanceQueryParamEntryField(
true );
1371 assert(nTab < rDoc.GetTableCount() &&
"try to access index out of bounds, FIX IT");
1372 maParam.nCol1 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol1);
1373 maParam.nCol2 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol2);
1374 nCol = maParam.nCol1;
1378 return countIfCount;
1394 assert(nTab < rDoc.GetTableCount() &&
"try to access index out of bounds, FIX IT");
1395 sal_uInt64
count = 0;
1397 for(
SCCOL col : rDoc.GetAllocatedColumnsRange(nTab, maParam.nCol1, maParam.nCol2))
1400 nRow = maParam.nRow1;
1401 ScRange aSortedRangeRange( col, maParam.nRow1, nTab, col, maParam.nRow2, nTab);
1402 ScQueryOp& op = maParam.GetEntry(0).eOp;
1403 SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &mrContext ));
1414 size_t lastNonMatching = sortedCache->indexForRow(nRow);
1417 size_t lastMatching = sortedCache->indexForRow(nRow);
1418 assert(lastMatching >= lastNonMatching);
1419 count += lastMatching - lastNonMatching;
1436 size_t lastMatching = sortedCache->indexForRow(nRow) + 1;
1437 count += lastMatching;
1439 else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
1440 && rDoc.IsEmptyData(col, maParam.nRow1, col, maParam.nRow2, nTab))
1444 count += maParam.nRow2 - maParam.nRow1 + 1;
1453 count += sortedCache->indexForRow(nRow) + 1;
1456 if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
1457 && maParam.nCol2 >= rDoc.GetAllocatedColumnsCount( nTab ))
1459 const sal_uInt64 nRows = maParam.nRow2 - maParam.nRow1 + 1;
1460 count += (maParam.nCol2 - rDoc.GetAllocatedColumnsCount(nTab)) * nRows;
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
const NodeContext & mrContext
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
sc::CellStoreType maCells
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
static bool CanBeUsed(ScDocument &rDoc, const ScQueryParam &aParam, SCTAB nTab, const ScFormulaCell *cell, const ScComplexRefData *refData, ScInterpreterContext &context)
SC_DLLPUBLIC ScColumnsRange GetAllocatedColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const
ScSortedRangeCache & GetSortedRangeCache(const ScRange &rRange, const ScQueryParam ¶m, ScInterpreterContext *pContext)
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
sal_uInt8 nStopOnMismatch
bool BinarySearch(SCCOL col, bool forEqual=false)
sal_uInt8 nTestEqualCondition
ScQueryCellIteratorBase(ScDocument &rDocument, ScInterpreterContext &rContext, SCTAB nTable, const ScQueryParam &aParam, bool bMod)
void SetAdvanceQueryParamEntryField(bool bVal)
void AdvanceQueryParamEntryField()
static bool CanBeUsed(ScDocument &rDoc, const ScQueryParam &aParam, SCTAB nTab, const ScFormulaCell *cell, const ScComplexRefData *refData, ScInterpreterContext &context)
bool FindEqualOrSortedLastInRange(SCCOL &nFoundCol, SCROW &nFoundRow)
In a range assumed to be sorted find either the last of a sequence of equal entries or the last being...
bool isMatchWholeCell(ScQueryOp eOp) const
bool ValidQuery(SCROW nRow, const ScRefCellValue *pCell=nullptr, sc::TableColumnBlockPositionSet *pBlockPos=nullptr)
bool Contains(const ScAddress &) const
is Address& fully in Range?
Sorted cache for one range used with interpreter functions such as VLOOKUP and MATCH.
bool isValid() const
Returns if the cache is usable.
const std::vector< SCROW > & sortedRows() const
const ScRange & getRange() const
const OUString & getString() const
RttiCompleteObjectLocator col
constexpr std::enable_if< std::is_signed< T1 >::value &&std::is_signed< T2 >::value, bool >::type isInRange(T2 value)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
const mdds::mtv::element_t element_type_edittext
mdds::mtv::soa::multi_type_vector< CellStoreTraits > CellStoreType
Cell container.
ScRefCellValue toRefCell(const sc::CellStoreType::const_iterator &itPos, size_t nOffset)
const mdds::mtv::element_t element_type_string
const mdds::mtv::element_t element_type_empty
std::vector< SCROW > mSortedRowsCopy
const std::vector< SCROW > & mSortedRows
std::map< size_t, sc::CellStoreType::const_iterator > BlockMapType
const sc::CellStoreType & mCells
const sc::CellStoreType & mrCells
static bool CanBeUsedForSorterCache(ScDocument &rDoc, const ScQueryParam &rParam, SCTAB nTab, const ScFormulaCell *cell, const ScComplexRefData *refData, ScInterpreterContext &context)
Complex reference (a range) into the sheet.
svl::SharedString maString
Each instance of this struct represents a single filtering criteria.
const Item & GetQueryItem() const
QueryItemsType & GetQueryItems()
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
utl::SearchParam::SearchType eSearchType
bool mbRangeLookup
for spreadsheet functions like MATCH, LOOKUP, HLOOKUP, VLOOKUP
This is very similar to ScCellValue, except that it references the original value instead of copying ...
ScFormulaCell * getFormula() const
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
ScQueryCellIteratorAccess