29#include <document.hxx>
38#include <progress.hxx>
54#include <osl/diagnose.h>
61template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
65 , nStopOnMismatch( nStopOnMismatchDisabled )
66 , nTestEqualCondition( nTestEqualConditionDisabled )
67 , bAdvanceQuery( false )
68 , bIgnoreMismatchOnLeadingStrings( false )
78 for (
i = 0; (
i <
nCount) && (maParam.GetEntry(
i).bDoQuery); ++
i)
83 bool bNumber =
mrContext.GetFormatTable()->IsNumberFormat(
89template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
92 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
96 const bool bSingleQueryItem = rEntry.
GetQueryItems().size() == 1;
98 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
100 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
102 ((maParam.bByRow && nRow == maParam.nRow1) ||
103 (!maParam.bByRow && nCol == maParam.nCol1));
104 bool bTestEqualCondition =
false;
106 (nTestEqualCondition ? &bTestEqualCondition :
nullptr));
111 assert( !bAllStringIgnore );
112 assert( !bIgnoreMismatchOnLeadingStrings );
113 assert( nStopOnMismatch == nStopOnMismatchDisabled );
114 assert( nTestEqualCondition == nTestEqualConditionDisabled );
115 bAllStringIgnore =
false;
116 bIgnoreMismatchOnLeadingStrings =
false;
117 nStopOnMismatch = nStopOnMismatchDisabled;
118 nTestEqualCondition = nTestEqualConditionDisabled;
120 assert( bAdvanceQuery );
121 bAdvanceQuery =
true;
124 const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
127 bool bNextColumn = maCurPos.first == pCol->
maCells.end();
130 if (nRow > maParam.nRow2)
139 if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
143 AdvanceQueryParamEntryField();
144 nFirstQueryField = rEntry.
nField;
146 pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
152 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
170 if(HandleItemFound())
184 if (bAllStringIgnore && aCell.
hasString())
189 (nCol ==
static_cast<SCCOL>(nFirstQueryField) ? &aCell :
nullptr)))
191 if ( nTestEqualCondition && bTestEqualCondition )
192 nTestEqualCondition |= nTestEqualConditionMatched;
193 if ( aCell.isEmpty())
195 if( HandleItemFound())
200 else if ( nStopOnMismatch )
205 if ( nTestEqualCondition && bTestEqualCondition )
207 nTestEqualCondition |= nTestEqualConditionMatched;
208 nStopOnMismatch |= nStopOnMismatchOccurred;
212 if (bFirstStringIgnore)
214 if (aCell.hasString())
226 nStopOnMismatch |= nStopOnMismatchOccurred;
233 bFirstStringIgnore =
false;
237template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
241 AccessBase::InitPos();
246 AccessBase::InitPosStart();
248 SCROW beforeRow = -1;
252 if( BinarySearch( nCol ))
261 if( BinarySearch( nCol,
true ))
268 else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
269 && rDoc.IsEmptyData(nCol, maParam.nRow1, nCol, maParam.nRow2, nTab))
274 lastRow = maParam.nRow2;
279 if( BinarySearch( nCol ))
282 AccessBase::InitPosFinish( beforeRow, lastRow );
286template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
289 SCSIZE nEntries = maParam.GetEntryCount();
295 if ( rEntry.
nField < rDoc.MaxCol() )
299 assert(!
"AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL");
309template<
typename Iter>
310void incBlock(std::pair<Iter, size_t>& rPos)
317template<
typename Iter>
318void decBlock(std::pair<Iter, size_t>& rPos)
322 rPos.second = rPos.first->size - 1;
327template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
330 assert(maParam.GetEntry(0).bDoQuery && !maParam.GetEntry(1).bDoQuery
331 && maParam.GetEntry(0).GetQueryItems().size() == 1 );
335 assert(maParam.bByRow);
338 || maParam.GetEntry(0).eOp ==
SC_EQUAL);
342 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
344 nRow = maParam.nRow1;
346 if (nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
349 const ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
359 bool bForceStr = bByString && ( rEntry.
eOp ==
SC_EQUAL || forEqual );
360 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
361 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
362 !maParam.bHasHeader && bByString;
364 if (maParam.bHasHeader)
367 if (bFirstStringIgnore)
369 sc::CellStoreType::const_position_type aPos = pCol->
maCells.position(nRow);
386 sc::CellStoreType::const_position_type startPos = pCol->
maCells.position(nRow);
392 while (startPos.first != pCol->
maCells.end()
400 if(startPos.first == pCol->
maCells.end())
402 nRow = startPos.first->position + startPos.second;
403 if (nRow > maParam.nRow2)
406 auto aIndexer = MakeBinarySearchIndexer(pCol->
maCells, nRow, maParam.nRow2);
407 if (!aIndexer.isValid())
410 size_t nLo = aIndexer.getLowIndex();
411 size_t nHi = aIndexer.getHighIndex();
412 BinarySearchCellType aCellData;
416 size_t nLastInRange = nLo;
417 double fLastInRangeValue = bAscending ?
418 -(::std::numeric_limits<double>::max()) :
419 ::std::numeric_limits<double>::max();
420 OUString aLastInRangeString;
422 aLastInRangeString = OUString(u
'\xFFFF');
424 aCellData = aIndexer.getCell(nLastInRange);
428 sal_uInt32 nFormat = pCol->
GetNumberFormat(mrContext, aCellData.second);
430 aLastInRangeString =
aStr;
450 std::optional<size_t> found;
452 bool orderBroken =
false;
453 while (nLo <= nHi && !bDone)
455 size_t nMid = (nLo+nHi)/2;
458 aCellData = aIndexer.getCell(i);
459 aCell = aCellData.first;
460 bool bStr = bForceStr || aCell.
hasString();
465 if (!bStr && !bByString)
477 if ((nCellVal < rItem.
mfVal) && !::rtl::math::approxEqual(
478 nCellVal, rItem.
mfVal))
483 if (fLastInRangeValue <= nCellVal)
485 fLastInRangeValue = nCellVal;
488 else if (fLastInRangeValue >= nCellVal)
496 else if ((nCellVal > rItem.
mfVal) && !::rtl::math::approxEqual(
497 nCellVal, rItem.
mfVal))
502 if (fLastInRangeValue >= nCellVal)
504 fLastInRangeValue = nCellVal;
507 else if (fLastInRangeValue <= nCellVal)
516 else if (bStr && bByString)
518 sal_uInt32 nFormat = pCol->
GetNumberFormat(mrContext, aCellData.second);
522 if (nRes < 0 && bAscending)
524 sal_Int32 nTmp = rCollator.
compareString( aLastInRangeString,
528 aLastInRangeString = aCellStr;
538 else if (nRes > 0 && !bAscending)
540 sal_Int32 nTmp = rCollator.
compareString( aLastInRangeString,
544 aLastInRangeString = aCellStr;
555 else if (!bStr && bByString)
622 nLo = aIndexer.getLowIndex();
636 isInRange = nLo != aIndexer.getLowIndex();
646 aCellData = aIndexer.getCell(nLo);
647 if (nLo <= nHi && aCellData.second <= maParam.nRow2)
649 nRow = aCellData.second;
650 maCurPos = aIndexer.getPosition(nLo);
655 nRow = maParam.nRow2 + 1;
657 maCurPos.first = pCol->
maCells.end();
659 maCurPos.second = maCurPos.first->size - 1;
665template< ScQueryCellIteratorAccess accessType >
672 nFoundCol = rDoc.MaxCol()+1;
673 nFoundRow = rDoc.MaxRow()+1;
674 SetStopOnMismatch(
true );
675 SetTestEqualCondition(
true );
676 bIgnoreMismatchOnLeadingStrings =
true;
679 bool bBinary = maParam.bByRow &&
685 if (BinarySearch( maParam.nCol1 ))
689 maParam.mbRangeLookup =
false;
702 PositionType aPosSave;
704 SCSIZE nEntries = maParam.GetEntryCount();
705 std::vector<SCCOL> aFoundFieldPositions(nEntries);
708 nFoundCol = GetCol();
709 nFoundRow = GetRow();
715 if (maParam.mbRangeLookup && bAdvanceQuery)
717 for (
SCSIZE j=0; j < nEntries; ++j)
721 aFoundFieldPositions[j] = maParam.GetEntry(j).
nField;
726 if (IsEqualConditionFulfilled())
734 if (!bNext && !IsEqualConditionFulfilled())
738 bool bColDiff = nCol != nFoundCol;
742 if (maParam.mbRangeLookup)
747 maParam.mbRangeLookup =
false;
749 if (bAdvanceQuery && bColDiff)
751 for (
SCSIZE j=0; j < nEntries; ++j)
756 rEntry.
nField = aFoundFieldPositions[j];
757 assert(rEntry.
nField >= 0);
766 nFoundCol = rDoc.MaxCol()+1;
767 nFoundRow = rDoc.MaxRow()+1;
772 if ( IsEqualConditionFulfilled() )
775 SCSIZE nEntries = maParam.GetEntryCount();
776 for (
SCSIZE j = 0; j < nEntries; j++ )
781 switch ( rEntry.
eOp )
796 PositionType aPosSave;
797 bIgnoreMismatchOnLeadingStrings =
false;
798 SetTestEqualCondition(
false );
801 nFoundCol = GetCol();
802 nFoundRow = GetRow();
813 StoppedOnMismatch() )
817 SCSIZE nEntries = maParam.GetEntryCount();
818 for (
SCSIZE j = 0; j < nEntries; j++ )
823 switch ( rEntry.
eOp )
838 SetStopOnMismatch(
false );
839 SetTestEqualCondition(
false );
845 PositionType aPosSave;
848 nFoundCol = GetCol();
849 nFoundRow = GetRow();
851 SetStopOnMismatch(
true );
858 return (nFoundCol <= rDoc.MaxCol()) && (nFoundRow <= rDoc.MaxRow());
875 nRow = maParam.nRow1;
876 if (maParam.bHasHeader && maParam.bByRow)
878 const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
879 maCurPos = rCol.
maCells.position(nRow);
884 if (maCurPos.second + 1 < maCurPos.first->size)
900 nRow = maCurPos.first->position;
914 typedef std::map<size_t, sc::CellStoreType::const_iterator>
BlockMapType;
937 sc::CellStoreType::const_position_type aLoPos =
mrCells.position(nStartRow);
939 assert(aLoPos.first != rCells.end());
941 SCROW nFirstRow = aLoPos.first->position;
942 SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
944 if (nFirstRow > nEndRow)
953 if (nFirstRow < nStartRow)
962 if (nEndRow < nLastRow)
964 assert(nEndRow >= nFirstRow);
967 maBlockMap.emplace(aLoPos.first->size, aLoPos.first);
973 sc::CellStoreType::const_position_type aHiPos =
mrCells.position(aLoPos.first, nEndRow);
980 SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
981 if (nBlockEndRow < nStartRow)
992 sc::CellStoreType::const_iterator itBlk = aLoPos.first;
993 while (itBlk != aHiPos.first)
1001 nPos += itBlk->size;
1008 assert(itBlk !=
mrCells.end());
1011 assert(itBlk == aHiPos.first);
1012 nPos += itBlk->size;
1016 BlockMapType::const_reverse_iterator ri =
maBlockMap.rbegin();
1022 sc::CellStoreType::const_position_type getPosition(
size_t nIndex )
const
1028 sc::CellStoreType::const_position_type aRet(
mrCells.end(), 0);
1030 BlockMapType::const_iterator it =
maBlockMap.upper_bound(nIndex);
1034 sc::CellStoreType::const_iterator itBlk = it->second;
1035 size_t nBlkIndex = it->first - itBlk->size;
1036 assert(nBlkIndex <= nIndex);
1037 assert(nIndex < it->first);
1039 size_t nOffset =
nIndex - nBlkIndex;
1041 aRet.second = nOffset;
1045 BinarySearchCellType getCell(
size_t nIndex )
const
1047 BinarySearchCellType aRet;
1050 sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
1051 if (aPos.first ==
mrCells.end())
1055 aRet.second = aPos.first->position + aPos.second;
1059 size_t getLowIndex()
const {
return mnLowIndex; }
1061 size_t getHighIndex()
const {
return mnHighIndex; }
1063 bool isValid()
const {
return mbValid; }
1070 return NonEmptyCellIndexer(rCells, nStartRow, nEndRow);
1088 sortedCache = &cache;
1097 ScRange aSortedRangeRange( nCol, maParam.nRow1, nTab, nCol, maParam.nRow2, nTab );
1099 SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &
mrContext ));
1107 pColumn = &rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
1110 sortedCachePos = beforeRow >= 0 ? sortedCache->indexForRow(beforeRow) + 1 : 0;
1111 sortedCachePosLast = sortedCache->indexForRow(lastRow);
1112 if(sortedCachePos <= sortedCachePosLast)
1114 nRow = sortedCache->rowForIndex(sortedCachePos);
1115 maCurPos = pColumn->maCells.position(nRow);
1120 sortedCachePos = sortedCachePosLast = 0;
1121 maCurPos.first = pColumn->maCells.end();
1122 maCurPos.second = 0;
1128 if(sortedCachePos < sortedCachePosLast)
1131 nRow = sortedCache->rowForIndex(sortedCachePos);
1133 if constexpr (!fast)
1137 if(maCurPos.first != pColumn->maCells.end() &&
o3tl::make_unsigned(nRow) >= maCurPos.first->position
1139 maCurPos.second = nRow - maCurPos.first->position;
1141 maCurPos = pColumn->maCells.position(nRow);
1149 maCurPos.first = pColumn->maCells.end();
1150 maCurPos.second = 0;
1175 if( row >= startRow && row <= endRow )
1184 :
mSortedRows( makeSortedRows( cache, startRow, endRow ))
1198 sc::CellStoreType::const_position_type getPosition(
size_t nIndex )
const
1202 return mCells.position(row);
1205 BinarySearchCellType getCell(
size_t nIndex )
const
1207 BinarySearchCellType aRet;
1210 sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
1211 if (aPos.first ==
mCells.end())
1215 aRet.second = aPos.first->position + aPos.second;
1219 size_t getLowIndex()
const {
return mLowIndex; }
1221 size_t getHighIndex()
const {
return mHighIndex; }
1223 bool isValid()
const {
return mValid; }
1230 return SortedCacheIndexer(rCells, nStartRow, nEndRow, sortedCache);
1248 if(!rParam.GetEntry(0).bDoQuery || rParam.GetEntry(1).bDoQuery
1249 || rParam.GetEntry(0).GetQueryItems().size() != 1 )
1258 if(rParam.bHasHeader)
1260 if(rParam.mbRangeLookup)
1267 && rParam.GetEntry(0).eOp !=
SC_EQUAL)
1270 static bool inUnitTest = getenv(
"LO_TESTNAME") !=
nullptr;
1271 if(refData ==
nullptr || refData->Ref1.IsRowRel() || refData->Ref2.IsRowRel())
1279 if(rParam.nRow2 - rParam.nRow1 < 10)
1286 if( !cell->GetCellGroup() || cell->GetCellGroup()->mnLength < 10 )
1293 for(
SCCOL col : rDoc.GetAllocatedColumnsRange(nTab, rParam.nCol1, rParam.nCol2))
1295 ScRange aSortedRangeRange(
col, rParam.nRow1, nTab,
col, rParam.nRow2, nTab);
1296 if( aSortedRangeRange.
Contains( cell->aPos ))
1298 ScSortedRangeCache& cache = rDoc.GetSortedRangeCache( aSortedRangeRange, rParam, &context );
1310 getThisResult =
true;
1314template< ScQueryCellIteratorAccess accessType >
1317 getThisResult =
false;
1319 return getThisResult;
1322template< ScQueryCellIteratorAccess accessType >
1325 assert(nTab < rDoc.GetTableCount() &&
"index out of bounds, FIX IT");
1326 nCol = maParam.nCol1;
1331template< ScQueryCellIteratorAccess accessType >
1335 if ( nStopOnMismatch )
1336 nStopOnMismatch = nStopOnMismatchEnabled;
1337 if ( nTestEqualCondition )
1338 nTestEqualCondition = nTestEqualConditionEnabled;
1377template< ScQueryCellIteratorAccess accessType >
1381 SetAdvanceQueryParamEntryField(
true );
1382 assert(nTab < rDoc.GetTableCount() &&
"try to access index out of bounds, FIX IT");
1383 maParam.nCol1 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol1);
1384 maParam.nCol2 = rDoc.ClampToAllocatedColumns(nTab, maParam.nCol2);
1385 nCol = maParam.nCol1;
1389 return countIfCount;
1405 assert(nTab < rDoc.GetTableCount() &&
"try to access index out of bounds, FIX IT");
1406 sal_uInt64
count = 0;
1408 for(
SCCOL col : rDoc.GetAllocatedColumnsRange(nTab, maParam.nCol1, maParam.nCol2))
1411 nRow = maParam.nRow1;
1412 ScRange aSortedRangeRange( col, maParam.nRow1, nTab, col, maParam.nRow2, nTab);
1413 ScQueryOp& op = maParam.GetEntry(0).eOp;
1414 SetSortedRangeCache( rDoc.GetSortedRangeCache( aSortedRangeRange, maParam, &mrContext ));
1425 size_t lastNonMatching = sortedCache->indexForRow(nRow);
1428 size_t lastMatching = sortedCache->indexForRow(nRow);
1429 assert(lastMatching >= lastNonMatching);
1430 count += lastMatching - lastNonMatching;
1447 size_t lastMatching = sortedCache->indexForRow(nRow) + 1;
1448 count += lastMatching;
1450 else if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
1451 && rDoc.IsEmptyData(col, maParam.nRow1, col, maParam.nRow2, nTab))
1455 count += maParam.nRow2 - maParam.nRow1 + 1;
1464 count += sortedCache->indexForRow(nRow) + 1;
1467 if( maParam.GetEntry(0).GetQueryItem().mbMatchEmpty
1468 && maParam.nCol2 >= rDoc.GetAllocatedColumnsCount( nTab ))
1470 const sal_uInt64 nRows = maParam.nRow2 - maParam.nRow1 + 1;
1471 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)
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
static bool CanBeUsedForSorterCache(ScDocument &, const ScQueryParam &, SCTAB, const ScFormulaCell *, const ScComplexRefData *, ScInterpreterContext &)
const sc::CellStoreType & mCells
const sc::CellStoreType & mrCells
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()
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