diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2022-05-04 19:46:57 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2022-05-10 16:23:32 +0200 |
commit | 80606b89bbd38f63423eccfac4d1b8e6732b9560 (patch) | |
tree | a8e78c0e7a81a43cae7ffec3e928760040848edc /sc/inc/queryiter.hxx | |
parent | 02c5ec92e3dfa8dee51e606ff8e929168948a8a7 (diff) |
extend ScQueryCellIteratorBase for custom cell access
This moves code related to accessing cells to query to a template
base class. Creating more specialization of that class will allow
queries that use a cache of sort order for the cells.
Change-Id: I47d1bc2d038717ff64f1d11fa6c7dba2359fec11
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134096
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'sc/inc/queryiter.hxx')
-rw-r--r-- | sc/inc/queryiter.hxx | 172 |
1 files changed, 139 insertions, 33 deletions
diff --git a/sc/inc/queryiter.hxx b/sc/inc/queryiter.hxx index f5cba350bff2..e247a471db65 100644 --- a/sc/inc/queryiter.hxx +++ b/sc/inc/queryiter.hxx @@ -26,22 +26,79 @@ #include "mtvelements.hxx" #include "types.hxx" -// Query-related iterators. There is one template class ScQueryCellIteratorBase -// that implements most of the shared functionality, specific parts are done -// by specializing the templates and then subclassing as the actual class to use. +/* +Query-related iterators. There is one template class ScQueryCellIteratorBase +that implements most of the shared functionality, specific parts are done +by specializing the templates and then subclassing as the actual class to use. +A template is used for maximum performance, as that allows fast code specializing, +inlining, etc. +There are two template arguments: +* ScQueryCellIteratorAccess specifies how cells are accessed: + + Direct - direct access to cells using mdds. + + SortedCache - for accessing unsorted cells in a sorted way using ScSortedRangeCache. +* ScQueryCellIteratorType specifies the type of the query operation: + + Generic - the generic lookup, used e.g. by VLOOKUP. + + CountIf - faster implementation for COUNTIF(S). -// Specific data should be in ScQueryCellIteratorSpecific (otherwise adding data -// members here would mean specializing the entire ScQueryCellIteratorBase). -template< ScQueryCellIteratorType iteratorType > -class ScQueryCellIteratorSpecific +Specific data should be in specific templated base classes, otherwise adding data +members would mean specializing the entire ScQueryCellIteratorBase. Some specific +functionality may also be implemented in the base classes or depending on the template +parameter. +*/ + +// Data and functionality for accessing cells in a specific way. +// Needs specialization, see ScQueryCellIteratorAccess::Direct for what is needed. +template< ScQueryCellIteratorAccess accessType > +class ScQueryCellIteratorAccessSpecific { }; -// Shared code for query-based iterators. +// The implementation using linear direct mdds access. +template<> +class ScQueryCellIteratorAccessSpecific< ScQueryCellIteratorAccess::Direct > +{ +protected: + ScQueryCellIteratorAccessSpecific( ScDocument& rDocument, const ScQueryParam& rParam ); + // Initialize position for new column. + void InitPos(); + // Increase position (next row). + void IncPos(); + // Next mdds block. If access is not direct/linear, then + // should call IncPos(). + void IncBlock(); + + // These members needs to be available already in the base class. + typedef sc::CellStoreType::const_position_type PositionType; + PositionType maCurPos; + ScQueryParam maParam; + ScDocument& rDoc; + SCTAB nTab; + SCCOL nCol; + SCROW nRow; + + class NonEmptyCellIndexer; + typedef std::pair<ScRefCellValue, SCROW> BinarySearchCellType; + static NonEmptyCellIndexer MakeBinarySearchIndexer(const sc::CellStoreType& rCells, + SCROW nStartRow, SCROW nEndRow); +}; + +// Data and functionality for specific types of query. template< ScQueryCellIteratorType iteratorType > -class ScQueryCellIteratorBase : public ScQueryCellIteratorSpecific< iteratorType > +class ScQueryCellIteratorTypeSpecific { protected: + bool HandleItemFound(); // not implemented, needs specialization +}; + +// Shared code for query-based iterators. The main class. +template< ScQueryCellIteratorAccess accessType, ScQueryCellIteratorType queryType > +class ScQueryCellIteratorBase + : public ScQueryCellIteratorAccessSpecific< accessType > + , public ScQueryCellIteratorTypeSpecific< queryType > +{ + typedef ScQueryCellIteratorAccessSpecific< accessType > AccessBase; + typedef ScQueryCellIteratorTypeSpecific< queryType > TypeBase; +protected: enum StopOnMismatchBits { nStopOnMismatchDisabled = 0x00, @@ -58,32 +115,29 @@ protected: nTestEqualConditionFulfilled = nTestEqualConditionEnabled | nTestEqualConditionMatched }; - typedef sc::CellStoreType::const_position_type PositionType; - PositionType maCurPos; - - ScQueryParam maParam; - ScDocument& rDoc; const ScInterpreterContext& mrContext; - SCTAB nTab; - SCCOL nCol; - SCROW nRow; sal_uInt8 nStopOnMismatch; sal_uInt8 nTestEqualCondition; bool bAdvanceQuery; bool bIgnoreMismatchOnLeadingStrings; - /** Initialize position for new column. */ - void InitPos(); - void IncPos(); - void IncBlock(); + // Make base members directly visible here (templated bases need 'this->'). + using AccessBase::maCurPos; + using AccessBase::maParam; + using AccessBase::rDoc; + using AccessBase::nTab; + using AccessBase::nCol; + using AccessBase::nRow; + using AccessBase::InitPos; + using AccessBase::IncPos; + using AccessBase::IncBlock; + using typename AccessBase::BinarySearchCellType; + using AccessBase::MakeBinarySearchIndexer; + using TypeBase::HandleItemFound; // The actual query function. It will call HandleItemFound() for any matching type // and return if HandleItemFound() returns true. void PerformQuery(); - bool HandleItemFound(); // not implemented, needs specialization - - SCCOL GetCol() const { return nCol; } - SCROW GetRow() const { return nRow; } /* Only works if no regular expression is involved, only searches for rows in one column, and only the first query entry is considered with simple conditions SC_LESS_EQUAL @@ -137,24 +191,55 @@ public: { return nTestEqualCondition == nTestEqualConditionFulfilled; } }; + template<> -class ScQueryCellIteratorSpecific< ScQueryCellIteratorType::Generic > +class ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::Generic > { protected: + bool HandleItemFound(); bool getThisResult; }; // The generic query iterator, used e.g. by VLOOKUP. -class ScQueryCellIterator : public ScQueryCellIteratorBase< ScQueryCellIteratorType::Generic > +template< ScQueryCellIteratorAccess accessType > +class ScQueryCellIterator + : public ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::Generic > { + typedef ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::Generic > Base; + // Make base members directly visible here (templated bases need 'this->'). + using Base::maParam; + using Base::rDoc; + using Base::nTab; + using Base::nCol; + using Base::nRow; + using Base::InitPos; + using Base::IncPos; + using Base::bIgnoreMismatchOnLeadingStrings; + using Base::SetStopOnMismatch; + using Base::SetTestEqualCondition; + using Base::BinarySearch; + using typename Base::PositionType; + using Base::maCurPos; + using Base::IsEqualConditionFulfilled; + using Base::bAdvanceQuery; + using Base::StoppedOnMismatch; + using Base::nStopOnMismatch; + using Base::nStopOnMismatchEnabled; + using Base::nTestEqualCondition; + using Base::nTestEqualConditionEnabled; + using Base::PerformQuery; + using Base::getThisResult; + bool GetThis(); public: - using ScQueryCellIteratorBase::ScQueryCellIteratorBase; + ScQueryCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable, + const ScQueryParam& aParam, bool bMod) + : Base( rDocument, rContext, nTable, aParam, bMod ) {} bool GetFirst(); bool GetNext(); - using ScQueryCellIteratorBase::GetCol; - using ScQueryCellIteratorBase::GetRow; + SCCOL GetCol() const { return nCol; } + SCROW GetRow() const { return nRow; } /** In a range assumed to be sorted find either the last of a sequence of equal entries or the last being less than @@ -177,20 +262,41 @@ public: bool FindEqualOrSortedLastInRange( SCCOL& nFoundCol, SCROW& nFoundRow ); }; +typedef ScQueryCellIterator< ScQueryCellIteratorAccess::Direct > ScQueryCellIteratorDirect; + template<> -class ScQueryCellIteratorSpecific< ScQueryCellIteratorType::CountIf > +class ScQueryCellIteratorTypeSpecific< ScQueryCellIteratorType::CountIf > { protected: + bool HandleItemFound(); sal_uInt64 countIfCount; }; // Used by ScInterpreter::ScCountIf. -class ScCountIfCellIterator : public ScQueryCellIteratorBase< ScQueryCellIteratorType::CountIf > +template< ScQueryCellIteratorAccess accessType > +class ScCountIfCellIterator + : public ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::CountIf > { + typedef ScQueryCellIteratorBase< accessType, ScQueryCellIteratorType::CountIf > Base; + // Make base members directly visible here (templated bases need 'this->'). + using Base::maParam; + using Base::rDoc; + using Base::nTab; + using Base::nCol; + using Base::nRow; + using Base::InitPos; + using Base::PerformQuery; + using Base::SetAdvanceQueryParamEntryField; + using Base::countIfCount; + public: - using ScQueryCellIteratorBase::ScQueryCellIteratorBase; + ScCountIfCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable, + const ScQueryParam& aParam, bool bMod) + : Base( rDocument, rContext, nTable, aParam, bMod ) {} sal_uInt64 GetCount(); }; +typedef ScCountIfCellIterator< ScQueryCellIteratorAccess::Direct > ScCountIfCellIteratorDirect; + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |