diff --git a/python/core/qgsexpressioncontext.sip b/python/core/qgsexpressioncontext.sip index a88e5851661..0b1a242b633 100644 --- a/python/core/qgsexpressioncontext.sip +++ b/python/core/qgsexpressioncontext.sip @@ -396,6 +396,46 @@ class QgsExpressionContext */ void setOriginalValueVariable( const QVariant& value ); + /** Sets a value to cache within the expression context. This can be used to cache the results + * of expensive expression sub-calculations, to speed up future evaluations using the same + * expression context. + * @param key unique key for retrieving cached value + * @param value value to cache + * @see hasCachedValue() + * @see cachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + void setCachedValue( const QString& key, const QVariant& value ) const; + + /** Returns true if the expression context contains a cached value with a matching key. + * @param key unique key used to store cached value + * @see setCachedValue() + * @see cachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + bool hasCachedValue( const QString& key ) const; + + /** Returns the matching cached value, if set. This can be used to retrieve the previously stored results + * of an expensive expression sub-calculation. + * @param key unique key used to store cached value + * @returns matching cached value, or invalid QVariant if not set + * @see setCachedValue() + * @see hasCachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + QVariant cachedValue( const QString& key ) const; + + /** Clears all cached values from the context. + * @see setCachedValue() + * @see hasCachedValue() + * @see cachedValue() + * @note added in QGIS 2.16 + */ + void clearCachedValues() const; + //! Inbuilt variable name for fields storage static const QString EXPR_FIELDS; //! Inbuilt variable name for feature storage diff --git a/src/core/qgsexpressioncontext.cpp b/src/core/qgsexpressioncontext.cpp index 4f3f06964d7..1a3a5cfc82f 100644 --- a/src/core/qgsexpressioncontext.cpp +++ b/src/core/qgsexpressioncontext.cpp @@ -213,6 +213,7 @@ QgsExpressionContext::QgsExpressionContext( const QgsExpressionContext& other ) mStack << new QgsExpressionContextScope( *scope ); } mHighlightedVariables = other.mHighlightedVariables; + mCachedValues = other.mCachedValues; } QgsExpressionContext& QgsExpressionContext::operator=( const QgsExpressionContext & other ) @@ -224,6 +225,7 @@ QgsExpressionContext& QgsExpressionContext::operator=( const QgsExpressionContex mStack << new QgsExpressionContextScope( *scope ); } mHighlightedVariables = other.mHighlightedVariables; + mCachedValues = other.mCachedValues; return *this; } @@ -439,6 +441,26 @@ void QgsExpressionContext::setOriginalValueVariable( const QVariant &value ) value, true ) ); } +void QgsExpressionContext::setCachedValue( const QString& key, const QVariant& value ) const +{ + mCachedValues.insert( key, value ); +} + +bool QgsExpressionContext::hasCachedValue( const QString& key ) const +{ + return mCachedValues.contains( key ); +} + +QVariant QgsExpressionContext::cachedValue( const QString& key ) const +{ + return mCachedValues.value( key, QVariant() ); +} + +void QgsExpressionContext::clearCachedValues() const +{ + mCachedValues.clear(); +} + // // QgsExpressionContextUtils diff --git a/src/core/qgsexpressioncontext.h b/src/core/qgsexpressioncontext.h index bc2e719719a..56e845fa2f4 100644 --- a/src/core/qgsexpressioncontext.h +++ b/src/core/qgsexpressioncontext.h @@ -434,6 +434,46 @@ class CORE_EXPORT QgsExpressionContext */ void setOriginalValueVariable( const QVariant& value ); + /** Sets a value to cache within the expression context. This can be used to cache the results + * of expensive expression sub-calculations, to speed up future evaluations using the same + * expression context. + * @param key unique key for retrieving cached value + * @param value value to cache + * @see hasCachedValue() + * @see cachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + void setCachedValue( const QString& key, const QVariant& value ) const; + + /** Returns true if the expression context contains a cached value with a matching key. + * @param key unique key used to store cached value + * @see setCachedValue() + * @see cachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + bool hasCachedValue( const QString& key ) const; + + /** Returns the matching cached value, if set. This can be used to retrieve the previously stored results + * of an expensive expression sub-calculation. + * @param key unique key used to store cached value + * @returns matching cached value, or invalid QVariant if not set + * @see setCachedValue() + * @see hasCachedValue() + * @see clearCachedValues() + * @note added in QGIS 2.16 + */ + QVariant cachedValue( const QString& key ) const; + + /** Clears all cached values from the context. + * @see setCachedValue() + * @see hasCachedValue() + * @see cachedValue() + * @note added in QGIS 2.16 + */ + void clearCachedValues() const; + //! Inbuilt variable name for fields storage static const QString EXPR_FIELDS; //! Inbuilt variable name for feature storage @@ -458,6 +498,9 @@ class CORE_EXPORT QgsExpressionContext QList< QgsExpressionContextScope* > mStack; QStringList mHighlightedVariables; + // Cache is mutable because we want to be able to add cached values to const contexts + mutable QMap< QString, QVariant > mCachedValues; + }; /** \ingroup core diff --git a/tests/src/core/testqgsexpressioncontext.cpp b/tests/src/core/testqgsexpressioncontext.cpp index 9bcc6663ae9..4d825729ce7 100644 --- a/tests/src/core/testqgsexpressioncontext.cpp +++ b/tests/src/core/testqgsexpressioncontext.cpp @@ -48,6 +48,8 @@ class TestQgsExpressionContext : public QObject void layerScope(); void featureBasedContext(); + void cache(); + private: class GetTestValueFunction : public QgsScopedExpressionFunction @@ -641,5 +643,37 @@ void TestQgsExpressionContext::featureBasedContext() QCOMPARE( evalFields, fields ); } +void TestQgsExpressionContext::cache() +{ + //test setting and retrieving cached values + QgsExpressionContext context; + + //use a const reference to ensure that cache is usable from const QgsExpressionContexts + const QgsExpressionContext& c = context; + + QVERIFY( !c.hasCachedValue( "test" ) ); + QVERIFY( !c.cachedValue( "test" ).isValid() ); + + c.setCachedValue( "test", "my value" ); + QVERIFY( c.hasCachedValue( "test" ) ); + QCOMPARE( c.cachedValue( "test" ), QVariant( "my value" ) ); + + // copy should copy cache + QgsExpressionContext context2( c ); + QVERIFY( context2.hasCachedValue( "test" ) ); + QCOMPARE( context2.cachedValue( "test" ), QVariant( "my value" ) ); + + // assignment should copy cache + QgsExpressionContext context3; + context3 = c; + QVERIFY( context3.hasCachedValue( "test" ) ); + QCOMPARE( context3.cachedValue( "test" ), QVariant( "my value" ) ); + + // clear cache + c.clearCachedValues(); + QVERIFY( !c.hasCachedValue( "test" ) ); + QVERIFY( !c.cachedValue( "test" ).isValid() ); +} + QTEST_MAIN( TestQgsExpressionContext ) #include "testqgsexpressioncontext.moc"