tdf#48459 sw inline heading: don't apply inside frames or over 120 chars
[LibreOffice.git] / sc / inc / queryiter.hxx
blob67f0e16fc0b5237f4b4039d9223c62503dd0acbf
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma once
22 #include "queryparam.hxx"
23 #include "mtvelements.hxx"
24 #include "types.hxx"
26 struct ScComplexRefData;
27 class ScSortedRangeCache;
30 Query-related iterators. There is one template class ScQueryCellIteratorBase
31 that implements most of the shared functionality, specific parts are done
32 by specializing the templates and then subclassing as the actual class to use.
33 A template is used for maximum performance, as that allows fast code specializing,
34 inlining, etc.
35 There are two template arguments:
36 * ScQueryCellIteratorAccess specifies how cells are accessed:
37 + Direct - direct access to cells using mdds.
38 + SortedCache - for accessing unsorted cells in a sorted way using ScSortedRangeCache.
39 * ScQueryCellIteratorType specifies the type of the query operation:
40 + Generic - the generic lookup, used e.g. by VLOOKUP.
41 + CountIf - faster implementation for COUNTIF(S).
43 Specific data should be in specific templated base classes, otherwise adding data
44 members would mean specializing the entire ScQueryCellIteratorBase. Some specific
45 functionality may also be implemented in the base classes or depending on the template
46 parameter.
49 // Data and functionality for accessing cells in a specific way.
50 // Needs specialization, see ScQueryCellIteratorAccess::Direct for what is needed.
51 template< ScQueryCellIteratorAccess accessType >
52 class ScQueryCellIteratorAccessSpecific
56 // The implementation using linear direct mdds access.
57 template<>
58 class ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct >
60 protected:
61 ScQueryCellIteratorAccessSpecific( ScDocument& rDocument, ScInterpreterContext& rContext,
62 const ScQueryParam& rParam, bool bReverseSearch );
63 // Initialize position for new column.
64 void InitPos();
65 // Increase position (next row).
66 void IncPos();
67 // Next mdds block. If access is not direct/linear, then
68 // should call IncPos().
69 void IncBlock();
71 // Decrease position (prev row).
72 void DecPos();
73 // Prev mdds block. If access is not direct/linear, then
74 // should call DecPos().
75 void DecBlock();
77 // These members needs to be available already in the base class.
78 typedef sc::CellStoreType::const_position_type PositionType;
79 PositionType maCurPos;
80 ScQueryParam maParam;
81 ScDocument& rDoc;
82 ScInterpreterContext& mrContext;
83 bool mbReverseSearch;
84 SCTAB nTab;
85 SCCOL nCol;
86 SCROW nRow;
88 class NonEmptyCellIndexer;
89 typedef std::pair<ScRefCellValue, SCCOLROW> BinarySearchCellType;
90 static NonEmptyCellIndexer MakeBinarySearchIndexer(const sc::CellStoreType* pCells,
91 SCCOLROW nStartRow, SCCOLROW nEndRow);
94 // The implementation using ScSortedRangeCache, which allows sorted iteration
95 // of unsorted cells.
96 template<>
97 class ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::SortedCache >
99 public:
100 void SetSortedRangeCache( const ScSortedRangeCache& cache );
101 template<bool fast>
102 bool IncPosImpl();
103 protected:
104 ScQueryCellIteratorAccessSpecific( ScDocument& rDocument, ScInterpreterContext& rContext,
105 const ScQueryParam& rParam, bool bReverseSearch );
106 void InitPosStart(bool bNewSearchFunction, sal_uInt8 nSortedBinarySearch = 0x00);
107 void InitPosFinish( SCROW beforeRow, SCROW lastRow, bool bFirstMatch );
108 void InitPosColFinish( SCCOL beforeCol, SCCOL lastCol, bool bFirstMatch );
109 void IncPos() { IncPosImpl<false>(); }
110 bool IncPosFast() { return IncPosImpl<true>(); }
111 void IncBlock() { IncPos(); } // Cannot skip entire block, not linear.
113 // Initialize for backward search. (no need for SortedCache)
114 static void DecPos() {};
115 static void DecBlock() {};
117 // These members needs to be available already in the base class.
118 typedef sc::CellStoreType::const_position_type PositionType;
119 PositionType maCurPos;
120 ScQueryParam maParam;
121 ScDocument& rDoc;
122 ScInterpreterContext& mrContext;
123 bool mbReverseSearch;
124 SCTAB nTab;
125 SCCOL nCol;
126 SCROW nRow;
127 const ScColumn* pColumn; // matching nCol, set by InitPos()
129 const ScSortedRangeCache* sortedCache;
130 size_t sortedCachePos;
131 size_t sortedCachePosLast;
133 class SortedCacheIndexer;
134 typedef std::pair<ScRefCellValue, SCCOLROW> BinarySearchCellType;
135 SortedCacheIndexer MakeBinarySearchIndexer(const sc::CellStoreType* pCells,
136 SCCOLROW nStartRow, SCCOLROW nEndRow);
139 // Data and functionality for specific types of query.
140 template< ScQueryCellIteratorType iteratorType >
141 class ScQueryCellIteratorTypeSpecific
143 protected:
144 bool HandleItemFound(); // not implemented, needs specialization
147 // Shared code for query-based iterators. The main class.
148 template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType >
149 class ScQueryCellIteratorBase
150 : public ScQueryCellIteratorAccessSpecific< accessType >
151 , public ScQueryCellIteratorTypeSpecific< queryType >
153 typedef ScQueryCellIteratorAccessSpecific< accessType > AccessBase;
154 typedef ScQueryCellIteratorTypeSpecific< queryType > TypeBase;
155 protected:
156 enum StopOnMismatchBits
158 nStopOnMismatchDisabled = 0x00,
159 nStopOnMismatchEnabled = 0x01,
160 nStopOnMismatchOccurred = 0x02,
161 nStopOnMismatchExecuted = nStopOnMismatchEnabled | nStopOnMismatchOccurred
164 enum TestEqualConditionBits
166 nTestEqualConditionDisabled = 0x00,
167 nTestEqualConditionEnabled = 0x01,
168 nTestEqualConditionMatched = 0x02,
169 nTestEqualConditionFulfilled = nTestEqualConditionEnabled | nTestEqualConditionMatched
172 enum SortedBinarySearchBits
174 nBinarySearchDisabled = 0x00,
175 nSearchbAscd = 0x01,
176 nSearchbDesc = 0x02,
179 sal_uInt8 nStopOnMismatch;
180 sal_uInt8 nTestEqualCondition;
181 sal_uInt8 nSortedBinarySearch;
182 bool bAdvanceQuery;
183 bool bIgnoreMismatchOnLeadingStrings;
184 sal_uInt16 nSearchOpCode;
185 SCCOL nBestFitCol;
186 SCROW nBestFitRow;
188 // Make base members directly visible here (templated bases need 'this->').
189 using AccessBase::maCurPos;
190 using AccessBase::maParam;
191 using AccessBase::rDoc;
192 using AccessBase::mrContext;
193 using AccessBase::mbReverseSearch;
194 using AccessBase::nTab;
195 using AccessBase::nCol;
196 using AccessBase::nRow;
197 using AccessBase::IncPos;
198 using AccessBase::IncBlock;
199 using AccessBase::DecPos;
200 using AccessBase::DecBlock;
201 using typename AccessBase::BinarySearchCellType;
202 using AccessBase::MakeBinarySearchIndexer;
203 using TypeBase::HandleItemFound;
205 void InitPos();
207 // The actual query function. It will call HandleItemFound() for any matching type
208 // and return if HandleItemFound() returns true.
209 void PerformQuery();
211 /* Only works if no regular expression is involved, only searches for rows in one column or
212 only searches for cols in one row, and only the first query entry is considered with simple
213 conditions SC_LESS,SC_LESS_EQUAL, SC_EQUAL (sorted ascending) or SC_GREATER,SC_GREATER_EQUAL
214 (sorted descending). It delivers a starting point set to nRow/nCol, i.e. the last row/col that
215 either matches the searched for value, or the last row/col that matches the condition.
216 Continue with e.g. GetThis() and GetNext() afterwards. Returns false if the searched for value
217 is not in the search range or if the range is not properly sorted, with nRow/nCol in that case
218 set to the first row or after the last row. In that case use GetFirst().
220 bool BinarySearch( SCCOLROW col_row, bool forEqual = false );
222 /** If set, iterator stops on first non-matching cell
223 content. May be used in SC_LESS_EQUAL queries where a
224 cell range is assumed to be sorted; stops on first
225 value being greater than the queried value and
226 GetFirst()/GetNext() return NULL. StoppedOnMismatch()
227 returns true then.
228 However, the iterator's conditions are not set to end
229 all queries, GetCol() and GetRow() return values for
230 the non-matching cell, further GetNext() calls may be
231 executed. */
232 void SetStopOnMismatch( bool bVal )
234 nStopOnMismatch = sal::static_int_cast<sal_uInt8>(bVal ? nStopOnMismatchEnabled :
235 nStopOnMismatchDisabled);
237 bool StoppedOnMismatch() const
238 { return nStopOnMismatch == nStopOnMismatchExecuted; }
240 /** If set, an additional test for SC_EQUAL condition is
241 executed in ScTable::ValidQuery() if SC_LESS_EQUAL or
242 SC_GREATER_EQUAL conditions are to be tested. May be
243 used where a cell range is assumed to be sorted to stop
244 if an equal match is found. */
245 void SetTestEqualCondition( bool bVal )
247 nTestEqualCondition = sal::static_int_cast<sal_uInt8>(bVal ?
248 nTestEqualConditionEnabled :
249 nTestEqualConditionDisabled);
251 bool IsEqualConditionFulfilled() const
252 { return nTestEqualCondition == nTestEqualConditionFulfilled; }
254 void HandleBestFitItemFound(SCCOL nBFitCol, SCROW nBFitRow)
256 nBestFitCol = nBFitCol;
257 nBestFitRow = nBFitRow;
259 public:
260 ScQueryCellIteratorBase(ScDocument& rDocument, ScInterpreterContext& rContext, SCTAB nTable,
261 const ScQueryParam& aParam, bool bMod, bool bReverse);
262 // when !bMod, the QueryParam has to be filled
263 // (bIsString)
265 // increments all Entry.nField, if column
266 // changes, for ScInterpreter ScHLookup()
267 void SetAdvanceQueryParamEntryField( bool bVal )
268 { bAdvanceQuery = bVal; }
269 void AdvanceQueryParamEntryField();
270 void AdvanceQueryParamEntryFieldForBinarySearch();
272 void SetSortedBinarySearchMode( sal_Int8 nSearchMode )
274 nSortedBinarySearch = sal::static_int_cast<sal_uInt8>(nSearchMode == 2 ?
275 nSearchbAscd : (nSearchMode == -2 ? nSearchbDesc : nBinarySearchDisabled));
278 void SetLookupMode( sal_uInt16 nVal )
279 { nSearchOpCode = nVal; }
283 template<>
284 class ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::Generic >
286 protected:
287 bool HandleItemFound();
288 bool getThisResult;
291 // The generic query iterator, used e.g. by VLOOKUP.
292 template< ScQueryCellIteratorAccess accessType >
293 class ScQueryCellIterator
294 : public ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::Generic >
296 typedef ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::Generic > Base;
297 // Make base members directly visible here (templated bases need 'this->').
298 using Base::maParam;
299 using Base::rDoc;
300 using Base::mrContext;
301 using Base::mbReverseSearch;
302 using Base::nTab;
303 using Base::nCol;
304 using Base::nRow;
305 using Base::InitPos;
306 using Base::IncPos;
307 using Base::DecPos;
308 using Base::bIgnoreMismatchOnLeadingStrings;
309 using Base::SetStopOnMismatch;
310 using Base::SetTestEqualCondition;
311 using Base::BinarySearch;
312 using typename Base::PositionType;
313 using Base::maCurPos;
314 using Base::IsEqualConditionFulfilled;
315 using Base::bAdvanceQuery;
316 using Base::StoppedOnMismatch;
317 using Base::nStopOnMismatch;
318 using Base::nStopOnMismatchEnabled;
319 using Base::nTestEqualCondition;
320 using Base::nTestEqualConditionEnabled;
321 using Base::nSortedBinarySearch;
322 using Base::nBinarySearchDisabled;
323 using Base::PerformQuery;
324 using Base::getThisResult;
325 using Base::nBestFitCol;
326 using Base::nBestFitRow;
327 using Base::nSearchOpCode;
329 bool GetThis();
331 public:
332 ScQueryCellIterator(ScDocument& rDocument, ScInterpreterContext& rContext, SCTAB nTable,
333 const ScQueryParam& aParam, bool bMod, bool bReverse)
334 : Base( rDocument, rContext, nTable, aParam, bMod, bReverse ) {}
335 bool GetFirst();
336 bool GetNext();
337 SCCOL GetCol() const { return nCol; }
338 SCROW GetRow() const { return nRow; }
340 /** In a range assumed to be sorted find either the last of
341 a sequence of equal entries or the last being less than
342 (or greater than) the queried value. Used by the
343 interpreter for [HV]?LOOKUP() and MATCH(). Column and
344 row position of the found entry are returned, otherwise
345 invalid.
347 The search does not stop when encountering a string and does not
348 assume that no values follow anymore.
349 If querying for a string a mismatch on the first
350 entry, e.g. column header, is ignored.
352 @ATTENTION! StopOnMismatch, TestEqualCondition and
353 the internal IgnoreMismatchOnLeadingStrings and query
354 params are in an undefined state upon return! The
355 iterator is not usable anymore except for obtaining the
356 number format!
358 bool FindEqualOrSortedLastInRange( SCCOL& nFoundCol, SCROW& nFoundRow );
361 typedef ScQueryCellIterator< ScQueryCellIteratorAccess::Direct > ScQueryCellIteratorDirect;
363 class ScQueryCellIteratorSortedCache
364 : public ScQueryCellIterator< ScQueryCellIteratorAccess::SortedCache >
366 typedef ScQueryCellIterator< ScQueryCellIteratorAccess::SortedCache > Base;
367 public:
368 ScQueryCellIteratorSortedCache(ScDocument& rDocument, ScInterpreterContext& rContext,
369 SCTAB nTable, const ScQueryParam& aParam, bool bMod, bool bReverse )
370 : Base( rDocument, rContext, nTable, aParam, bMod, bReverse ) {}
371 // Returns true if this iterator can be used for the given query.
372 static bool CanBeUsed(ScDocument& rDoc, const ScQueryParam& aParam,
373 SCTAB nTab, const ScFormulaCell* cell, const ScComplexRefData* refData,
374 ScInterpreterContext& context);
378 template<>
379 class ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::CountIf >
381 protected:
382 bool HandleItemFound();
383 sal_uInt64 countIfCount;
386 // Used by ScInterpreter::ScCountIf.
387 template< ScQueryCellIteratorAccess accessType >
388 class ScCountIfCellIterator
389 : public ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::CountIf >
391 protected:
392 typedef ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::CountIf > Base;
393 // Make base members directly visible here (templated bases need 'this->').
394 using Base::maParam;
395 using Base::rDoc;
396 using Base::nTab;
397 using Base::nCol;
398 using Base::nRow;
399 using Base::InitPos;
400 using Base::PerformQuery;
401 using Base::SetAdvanceQueryParamEntryField;
402 using Base::countIfCount;
404 public:
405 ScCountIfCellIterator(ScDocument& rDocument, ScInterpreterContext& rContext, SCTAB nTable,
406 const ScQueryParam& aParam, bool bMod, bool bReverse)
407 : Base( rDocument, rContext, nTable, aParam, bMod, bReverse ) {}
408 sal_uInt64 GetCount();
411 typedef ScCountIfCellIterator< ScQueryCellIteratorAccess::Direct > ScCountIfCellIteratorDirect;
413 class ScCountIfCellIteratorSortedCache
414 : public ScCountIfCellIterator< ScQueryCellIteratorAccess::SortedCache >
416 typedef ScCountIfCellIterator< ScQueryCellIteratorAccess::SortedCache > Base;
417 public:
418 ScCountIfCellIteratorSortedCache(ScDocument& rDocument, ScInterpreterContext& rContext,
419 SCTAB nTable, const ScQueryParam& aParam, bool bMod, bool bReverse)
420 : Base( rDocument, rContext, nTable, aParam, bMod, bReverse ) {}
421 // Returns true if this iterator can be used for the given query.
422 static bool CanBeUsed(ScDocument& rDoc, const ScQueryParam& aParam,
423 SCTAB nTab, const ScFormulaCell* cell, const ScComplexRefData* refData,
424 ScInterpreterContext& context);
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */