Skip to content

Commit

Permalink
Implement method for caching values within expression contexts
Browse files Browse the repository at this point in the history
Can be used to store the results of expensive sub-expression
calculations (eg layer aggregates), so that future expression
evaluation using the same context does not have to recalculate
the cached values.
  • Loading branch information
nyalldawson committed May 17, 2016
1 parent 821134c commit 84fc3c3
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
40 changes: 40 additions & 0 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions src/core/qgsexpressioncontext.cpp
Expand Up @@ -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 )
Expand All @@ -224,6 +225,7 @@ QgsExpressionContext& QgsExpressionContext::operator=( const QgsExpressionContex
mStack << new QgsExpressionContextScope( *scope );
}
mHighlightedVariables = other.mHighlightedVariables;
mCachedValues = other.mCachedValues;
return *this;
}

Expand Down Expand Up @@ -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
Expand Down
43 changes: 43 additions & 0 deletions src/core/qgsexpressioncontext.h
Expand Up @@ -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
Expand All @@ -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
Expand Down
34 changes: 34 additions & 0 deletions tests/src/core/testqgsexpressioncontext.cpp
Expand Up @@ -48,6 +48,8 @@ class TestQgsExpressionContext : public QObject
void layerScope();
void featureBasedContext();

void cache();

private:

class GetTestValueFunction : public QgsScopedExpressionFunction
Expand Down Expand Up @@ -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"

0 comments on commit 84fc3c3

Please sign in to comment.