Skip to content

Commit

Permalink
[feature] Expression performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed May 2, 2017
2 parents fbd62be + c30d7b9 commit 8d8fa94
Show file tree
Hide file tree
Showing 12 changed files with 576 additions and 95 deletions.
57 changes: 54 additions & 3 deletions python/core/qgsexpression.sip
Expand Up @@ -570,7 +570,31 @@ Does this function use a geometry object.
%Docstring
True if this function should use lazy evaluation. Lazy evaluation functions take QgsExpression.Node objects
rather than the node results when called. You can use node->eval(parent, feature) to evaluate the node and return the result
Functions are non lazy default and will be given the node return value when called **
Functions are non lazy default and will be given the node return value when called.
:rtype: bool
%End

virtual bool isStatic( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const;
%Docstring
Will be called during prepare to determine if the function is static.
A function is static if it will return the same value for every feature with different
attributes and/or geometry.

By default this will return true, if all arguments that have been passed to the function
are also static.

.. versionadded:: 3.0
:rtype: bool
%End

virtual bool prepare( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context ) const;
%Docstring
This will be called during the prepare step() of an expression if it is not static.

This can be used by functions to do any preparation steps that might help to speedup the upcoming
evaluation.

.. versionadded:: 3.0
:rtype: bool
%End

Expand Down Expand Up @@ -643,6 +667,22 @@ The help text for the function.
:rtype: bool
%End

protected:

static bool allParamsStatic( const QgsExpression::NodeFunction *node, QgsExpression *parent, const QgsExpressionContext *context );
%Docstring
This will return true if all the params for the provided function ``node`` are static within the
constraints imposed by the ``context`` within the given ``parent``.

This can be used as callback for custom implementations of subclasses. It is the default for implementation
for StaticFunction.isStatic.

.. note::

Added in QGIS 3.0
:rtype: bool
%End

};


Expand Down Expand Up @@ -823,8 +863,6 @@ return index of the function in Functions array
virtual QgsExpression::Node *clone() const = 0;
%Docstring
Generate a clone of this node.
Make sure that the clone does not contain any information which is
generated in prepare and context related.
Ownership is transferred to the caller.

:return: a deep copy of this node.
Expand Down Expand Up @@ -883,6 +921,19 @@ return index of the function in Functions array
:rtype: bool
%End


protected:

void cloneTo( QgsExpression::Node *target ) const;
%Docstring
Needs to be called by all subclasses as part of their clone() implementation.

.. note::

Not available in python bindings
.. versionadded:: 3.0
%End

private:
virtual bool prepareNode( QgsExpression *parent, const QgsExpressionContext *context ) = 0 ;
%Docstring
Expand Down
15 changes: 13 additions & 2 deletions python/core/qgsexpressioncontext.sip
Expand Up @@ -76,7 +76,7 @@ class QgsExpressionContextScope
* @param value initial variable value
* @param readOnly true if variable should not be editable by users
*/
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false );
StaticVariable( const QString &name = QString(), const QVariant &value = QVariant(), bool readOnly = false, bool isStatic = false );

/** Variable name */
QString name;
Expand All @@ -86,6 +86,9 @@ class QgsExpressionContextScope

/** True if variable should not be editable by users */
bool readOnly;

//! A static variable can be cached for the lifetime of a context
bool isStatic;
};

/** Constructor for QgsExpressionContextScope
Expand All @@ -109,7 +112,7 @@ class QgsExpressionContextScope
* @param value variable value
* @see addVariable()
*/
void setVariable( const QString &name, const QVariant &value );
void setVariable( const QString &name, const QVariant &value, bool isStatic = false );

/** Adds a variable into the context scope. If a variable with the same name is already set then its
* value is overwritten, otherwise a new variable is added to the scope.
Expand Down Expand Up @@ -162,6 +165,14 @@ class QgsExpressionContextScope
*/
bool isReadOnly( const QString &name ) const;

/**
* Tests whether the variable with the specified \a name is static and can
* be cached.
*
* \note Added in QGIS 3.0
*/
bool isStatic( const QString &name ) const;

/** Returns the count of variables contained within the scope.
*/
int variableCount() const;
Expand Down
9 changes: 9 additions & 0 deletions python/core/qgsfeaturerequest.sip
Expand Up @@ -83,6 +83,15 @@ class QgsFeatureRequest
*/
QgsExpression expression() const;

/**
* Prepare the expression with the given context.
*
* \see QgsExpression::prepare
*
* \since QGIS 3.0
*/
bool prepare( QgsExpressionContext *context );

/**
* Order ascending
* @return If ascending order is requested
Expand Down

1 comment on commit 8d8fa94

@NathanW2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of timings did you get adding something like this?

Please sign in to comment.