From 1d2bb41752c51e6c9b84124a1ce1599d3d42b41c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 12 Oct 2020 08:22:13 +1000 Subject: [PATCH] Lazy construct expression context for memory provider feature sources It's not free to calculate, and is only used when iterating over a memory layer with a subset string set Results in a big speed up to scripts which fire off many individual feature requests to a memory provider layer --- .../memory/qgsmemoryfeatureiterator.cpp | 30 +++++++++++++------ .../memory/qgsmemoryfeatureiterator.h | 4 ++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/core/providers/memory/qgsmemoryfeatureiterator.cpp b/src/core/providers/memory/qgsmemoryfeatureiterator.cpp index 20b041e866ee..4a0a8a5ec9cf 100644 --- a/src/core/providers/memory/qgsmemoryfeatureiterator.cpp +++ b/src/core/providers/memory/qgsmemoryfeatureiterator.cpp @@ -47,7 +47,7 @@ QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource *sour if ( !mSource->mSubsetString.isEmpty() ) { mSubsetExpression = qgis::make_unique< QgsExpression >( mSource->mSubsetString ); - mSubsetExpression->prepare( &mSource->mExpressionContext ); + mSubsetExpression->prepare( mSource->expressionContext() ); } if ( !mFilterRect.isNull() && mRequest.flags() & QgsFeatureRequest::ExactIntersect ) @@ -63,7 +63,7 @@ QgsMemoryFeatureIterator::QgsMemoryFeatureIterator( QgsMemoryFeatureSource *sour { mUsingFeatureIdList = true; mFeatureIdList = mSource->mSpatialIndex->intersects( mFilterRect ); - QgsDebugMsg( "Features returned by spatial index: " + QString::number( mFeatureIdList.count() ) ); + QgsDebugMsgLevel( "Features returned by spatial index: " + QString::number( mFeatureIdList.count() ), 2 ); } else if ( mRequest.filterType() == QgsFeatureRequest::FilterFid ) { @@ -138,8 +138,8 @@ bool QgsMemoryFeatureIterator::nextFeatureUsingList( QgsFeature &feature ) if ( hasFeature && mSubsetExpression ) { - mSource->mExpressionContext.setFeature( candidate ); - if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) + mSource->expressionContext()->setFeature( candidate ); + if ( !mSubsetExpression->evaluate( mSource->expressionContext() ).toBool() ) hasFeature = false; } @@ -198,8 +198,8 @@ bool QgsMemoryFeatureIterator::nextFeatureTraverseAll( QgsFeature &feature ) if ( mSubsetExpression ) { - mSource->mExpressionContext.setFeature( *mSelectIterator ); - if ( !mSubsetExpression->evaluate( &mSource->mExpressionContext ).toBool() ) + mSource->expressionContext()->setFeature( *mSelectIterator ); + if ( !mSubsetExpression->evaluate( mSource->expressionContext() ).toBool() ) hasFeature = false; } @@ -257,9 +257,6 @@ QgsMemoryFeatureSource::QgsMemoryFeatureSource( const QgsMemoryProvider *p ) , mSubsetString( p->mSubsetString ) , mCrs( p->mCrs ) { - mExpressionContext << QgsExpressionContextUtils::globalScope() - << QgsExpressionContextUtils::projectScope( QgsProject::instance() ); - mExpressionContext.setFields( mFields ); } QgsFeatureIterator QgsMemoryFeatureSource::getFeatures( const QgsFeatureRequest &request ) @@ -267,4 +264,19 @@ QgsFeatureIterator QgsMemoryFeatureSource::getFeatures( const QgsFeatureRequest return QgsFeatureIterator( new QgsMemoryFeatureIterator( this, false, request ) ); } +QgsExpressionContext *QgsMemoryFeatureSource::expressionContext() +{ + // lazy construct expression context -- it's not free to calculate, and is only used when + // iterating over a memory layer with a subset string set + if ( !mExpressionContext ) + { + mExpressionContext = qgis::make_unique< QgsExpressionContext >( + QList() + << QgsExpressionContextUtils::globalScope() + << QgsExpressionContextUtils::projectScope( QgsProject::instance() ) ); + mExpressionContext->setFields( mFields ); + } + return mExpressionContext.get(); +} + ///@endcond PRIVATE diff --git a/src/core/providers/memory/qgsmemoryfeatureiterator.h b/src/core/providers/memory/qgsmemoryfeatureiterator.h index 1c771dab6edd..404fccec17b4 100644 --- a/src/core/providers/memory/qgsmemoryfeatureiterator.h +++ b/src/core/providers/memory/qgsmemoryfeatureiterator.h @@ -38,12 +38,14 @@ class QgsMemoryFeatureSource final: public QgsAbstractFeatureSource QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) override; + QgsExpressionContext *expressionContext(); + private: QgsFields mFields; QgsFeatureMap mFeatures; std::unique_ptr< QgsSpatialIndex > mSpatialIndex; QString mSubsetString; - QgsExpressionContext mExpressionContext; + std::unique_ptr< QgsExpressionContext > mExpressionContext; QgsCoordinateReferenceSystem mCrs; friend class QgsMemoryFeatureIterator;