Implement method for caching values within expression contexts

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.
This commit is contained in:
Nyall Dawson 2016-05-16 15:23:42 +10:00
parent 821134ca91
commit 84fc3c3b3d
4 changed files with 139 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"