Track expression dependencies (#2113)
This commit is contained in:
@@ -24,8 +24,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
ColorRampPropertyValue()
|
||||
: value(nullptr) {}
|
||||
ColorRampPropertyValue() noexcept = default;
|
||||
ColorRampPropertyValue(std::shared_ptr<expression::Expression> value_)
|
||||
: value(std::move(value_)) {}
|
||||
|
||||
@@ -46,6 +45,9 @@ public:
|
||||
bool hasDataDrivenPropertyDifference(const ColorRampPropertyValue&) const { return false; }
|
||||
|
||||
const expression::Expression& getExpression() const { return *value; }
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
Dependency getDependencies() const noexcept { return value ? value->dependencies : Dependency::None; }
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace expression {
|
||||
class At : public Expression {
|
||||
public:
|
||||
At(std::unique_ptr<Expression> index_, std::unique_ptr<Expression> input_)
|
||||
: Expression(Kind::At, input_->getType().get<type::Array>().itemType),
|
||||
: Expression(Kind::At, input_->getType().get<type::Array>().itemType, depsOf(index_) | depsOf(input_)),
|
||||
index(std::move(index_)),
|
||||
input(std::move(input_)) {}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace expression {
|
||||
class Any : public Expression {
|
||||
public:
|
||||
Any(std::vector<std::unique_ptr<Expression>> inputs_)
|
||||
: Expression(Kind::Any, type::Boolean),
|
||||
: Expression(Kind::Any, type::Boolean, collectDependencies(inputs_)),
|
||||
inputs(std::move(inputs_)) {}
|
||||
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
class All : public Expression {
|
||||
public:
|
||||
All(std::vector<std::unique_ptr<Expression>> inputs_)
|
||||
: Expression(Kind::All, type::Boolean),
|
||||
: Expression(Kind::All, type::Boolean, collectDependencies(inputs_)),
|
||||
inputs(std::move(inputs_)) {}
|
||||
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
using Branch = std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>;
|
||||
|
||||
Case(type::Type type_, std::vector<Branch> branches_, std::unique_ptr<Expression> otherwise_)
|
||||
: Expression(Kind::Case, std::move(type_)),
|
||||
: Expression(Kind::Case, std::move(type_), collectDependencies(branches_) | depsOf(otherwise_)),
|
||||
branches(std::move(branches_)),
|
||||
otherwise(std::move(otherwise_)) {}
|
||||
|
||||
@@ -32,6 +32,12 @@ public:
|
||||
|
||||
std::string getOperator() const override { return "case"; }
|
||||
|
||||
protected:
|
||||
using Expression::collectDependencies;
|
||||
static Dependency collectDependencies(const std::vector<Branch>& branches) {
|
||||
return collectDependencies(branches, [](const Branch& v) { return depsOf(v.first) | depsOf(v.second); });
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Branch> branches;
|
||||
std::unique_ptr<Expression> otherwise;
|
||||
|
||||
@@ -15,7 +15,7 @@ class Coalesce : public Expression {
|
||||
public:
|
||||
using Args = std::vector<std::unique_ptr<Expression>>;
|
||||
Coalesce(const type::Type& type_, Args args_)
|
||||
: Expression(Kind::Coalesce, type_),
|
||||
: Expression(Kind::Coalesce, type_, collectDependencies(args_)),
|
||||
args(std::move(args_)) {}
|
||||
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace expression {
|
||||
|
||||
class Coercion : public Expression {
|
||||
public:
|
||||
Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_);
|
||||
Coercion(const type::Type& type_, std::vector<std::unique_ptr<Expression>> inputs_);
|
||||
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
|
||||
void eachChild(const std::function<void(const Expression&)>&) const override;
|
||||
|
||||
bool operator==(const Expression& e) const override;
|
||||
bool operator==(const Expression&) const override;
|
||||
|
||||
std::vector<std::optional<Value>> possibleOutputs() const override {
|
||||
// Technically the set of possible outputs is the combinatoric set of
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace expression {
|
||||
class Error : public Expression {
|
||||
public:
|
||||
Error(std::string message_)
|
||||
: Expression(Kind::Error, type::Error),
|
||||
: Expression(Kind::Error, type::Error, Dependency::None),
|
||||
message(std::move(message_)) {}
|
||||
|
||||
void eachChild(const std::function<void(const Expression&)>&) const override {}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <mbgl/style/expression/value.hpp>
|
||||
#include <mbgl/tile/tile_id.hpp>
|
||||
#include <mbgl/util/color.hpp>
|
||||
#include <mbgl/util/traits.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -135,23 +137,23 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
Expression is an abstract class that serves as an interface and base class
|
||||
for particular expression implementations.
|
||||
Expression is an abstract class that serves as an interface and base class
|
||||
for particular expression implementations.
|
||||
|
||||
CompoundExpression implements the majority of expressions in the spec by
|
||||
inferring the argument and output from a simple function (const T0& arg0,
|
||||
const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are member types of
|
||||
mbgl::style::expression::Value.
|
||||
CompoundExpression implements the majority of expressions in the spec by
|
||||
inferring the argument and output from a simple function (const T0& arg0,
|
||||
const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are member types of
|
||||
mbgl::style::expression::Value.
|
||||
|
||||
The other Expression subclasses (Let, Curve, Match, etc.) exist in order to
|
||||
implement expressions that need specialized parsing, type checking, or
|
||||
evaluation logic that can't be handled by CompoundExpression's inference
|
||||
mechanism.
|
||||
The other Expression subclasses (Let, Curve, Match, etc.) exist in order to
|
||||
implement expressions that need specialized parsing, type checking, or
|
||||
evaluation logic that can't be handled by CompoundExpression's inference
|
||||
mechanism.
|
||||
|
||||
Each Expression subclass also provides a static
|
||||
ParseResult ExpressionClass::parse(const V&, ParsingContext),
|
||||
which handles parsing a style-spec JSON representation of the expression.
|
||||
*/
|
||||
Each Expression subclass also provides a static
|
||||
ParseResult ExpressionClass::parse(const V&, ParsingContext),
|
||||
which handles parsing a style-spec JSON representation of the expression.
|
||||
*/
|
||||
|
||||
enum class Kind : int32_t {
|
||||
Coalesce,
|
||||
@@ -183,10 +185,33 @@ enum class Kind : int32_t {
|
||||
Slice
|
||||
};
|
||||
|
||||
enum class Dependency : uint32_t {
|
||||
None = 0,
|
||||
Feature = 1 << 0, // Data reference
|
||||
Image = 1 << 1, // Image reference (equivalent to not "runtime constant")
|
||||
Zoom = 1 << 2, // Zoom level
|
||||
Location = 1 << 3, // Not used yet, "distance-from-center" not supported
|
||||
Bind = 1 << 4, // Create variable binding ("let")
|
||||
Var = 1 << 5, // Use variable binding
|
||||
Override = 1 << 6, // Property override
|
||||
MaskCount = 7,
|
||||
};
|
||||
inline constexpr static Dependency operator|(Dependency x, Dependency y) noexcept {
|
||||
return Dependency{mbgl::underlying_type(x) | mbgl::underlying_type(y)};
|
||||
}
|
||||
inline constexpr static Dependency operator&(Dependency x, Dependency y) noexcept {
|
||||
return Dependency{mbgl::underlying_type(x) & mbgl::underlying_type(y)};
|
||||
}
|
||||
inline static Dependency& operator|=(Dependency& target, Dependency source) noexcept {
|
||||
target = target | source;
|
||||
return target;
|
||||
}
|
||||
|
||||
class Expression {
|
||||
public:
|
||||
Expression(Kind kind_, type::Type type_)
|
||||
: kind(kind_),
|
||||
Expression(Kind kind_, type::Type type_, Dependency dependencies_)
|
||||
: dependencies(dependencies_),
|
||||
kind(kind_),
|
||||
type(std::move(type_)) {}
|
||||
virtual ~Expression() = default;
|
||||
|
||||
@@ -195,8 +220,8 @@ public:
|
||||
virtual bool operator==(const Expression&) const = 0;
|
||||
bool operator!=(const Expression& rhs) const { return !operator==(rhs); }
|
||||
|
||||
Kind getKind() const { return kind; };
|
||||
type::Type getType() const { return type; };
|
||||
Kind getKind() const { return kind; }
|
||||
const type::Type& getType() const { return type; }
|
||||
|
||||
EvaluationResult evaluate(std::optional<float> zoom,
|
||||
const Feature& feature,
|
||||
@@ -229,6 +254,8 @@ public:
|
||||
|
||||
virtual std::string getOperator() const = 0;
|
||||
|
||||
const Dependency dependencies;
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
static bool childrenEqual(const T& lhs, const T& rhs) {
|
||||
@@ -261,6 +288,43 @@ protected:
|
||||
return *(lhs.first) == *(rhs.first) && *(lhs.second) == *(rhs.second);
|
||||
}
|
||||
|
||||
static Dependency depsOf(const std::shared_ptr<Expression>& ex) { return ex ? ex->dependencies : Dependency::None; }
|
||||
static Dependency depsOf(const std::unique_ptr<Expression>& ex) { return ex ? ex->dependencies : Dependency::None; }
|
||||
|
||||
template <typename T>
|
||||
static Dependency depsOf(const std::optional<T>& ex) {
|
||||
return ex ? depsOf(*ex) : Dependency::None;
|
||||
}
|
||||
|
||||
/// Combine the dependencies of all the expressions in a container of shared- or unique-pointers to expressions
|
||||
template <typename T>
|
||||
static constexpr Dependency collectDependencies(const std::vector<T>& container) {
|
||||
return std::accumulate(container.begin(), container.end(), Dependency::None, [](auto a, const auto& ex) {
|
||||
return a | depsOf(ex);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
static constexpr Dependency collectDependencies(const std::vector<T>& container, F op) {
|
||||
return std::accumulate(container.begin(), container.end(), Dependency::None, [&](auto a, const auto& item) {
|
||||
return a | op(item);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename K, typename T>
|
||||
static constexpr Dependency collectDependencies(const std::map<K, T>& container) {
|
||||
return std::accumulate(container.begin(), container.end(), Dependency::None, [](auto a, const auto& v) {
|
||||
return a | depsOf(v.second);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename K, typename T>
|
||||
static constexpr Dependency collectDependencies(const std::unordered_map<K, T>& container) {
|
||||
return std::accumulate(container.begin(), container.end(), Dependency::None, [](auto a, const auto& kv) {
|
||||
return a | depsOf(kv.second);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
Kind kind;
|
||||
type::Type type;
|
||||
@@ -268,4 +332,11 @@ private:
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
|
||||
namespace util {
|
||||
std::string toString(style::expression::Dependency);
|
||||
} // namespace util
|
||||
|
||||
std::ostream& operator<<(std::ostream&, style::expression::Dependency);
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/expression/parsing_context.hpp>
|
||||
#include <mbgl/style/expression/interpolate.hpp>
|
||||
#include <mbgl/style/expression/parsing_context.hpp>
|
||||
#include <mbgl/style/expression/step.hpp>
|
||||
|
||||
#include <mbgl/util/variant.hpp>
|
||||
|
||||
#include <optional>
|
||||
@@ -12,9 +11,9 @@ namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e);
|
||||
std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression*);
|
||||
|
||||
variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e);
|
||||
variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression&);
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace expression {
|
||||
struct FormatExpressionSection {
|
||||
explicit FormatExpressionSection(std::unique_ptr<Expression> content_);
|
||||
|
||||
void setTextSectionOptions(std::optional<std::unique_ptr<Expression>> fontScale_,
|
||||
std::optional<std::unique_ptr<Expression>> textFont_,
|
||||
std::optional<std::unique_ptr<Expression>> textColor_);
|
||||
void setTextSectionOptions(std::unique_ptr<Expression>&& fontScale_,
|
||||
std::unique_ptr<Expression>&& textFont_,
|
||||
std::unique_ptr<Expression>&& textColor_);
|
||||
|
||||
// Content can be expression that evaluates to String or Image.
|
||||
std::shared_ptr<Expression> content;
|
||||
|
||||
// Text related section options.
|
||||
std::optional<std::shared_ptr<Expression>> fontScale;
|
||||
std::optional<std::shared_ptr<Expression>> textFont;
|
||||
std::optional<std::shared_ptr<Expression>> textColor;
|
||||
std::shared_ptr<Expression> fontScale;
|
||||
std::shared_ptr<Expression> textFont;
|
||||
std::shared_ptr<Expression> textColor;
|
||||
};
|
||||
|
||||
class FormatExpression final : public Expression {
|
||||
@@ -45,6 +45,11 @@ public:
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "format"; }
|
||||
|
||||
private:
|
||||
static Dependency depsOfSection(const FormatExpressionSection& s) {
|
||||
return depsOf(s.content) | depsOf(s.fontScale) | depsOf(s.textFont) | depsOf(s.textColor);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<FormatExpressionSection> sections;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,9 @@ public:
|
||||
FormatSectionOverride(const type::Type& type_,
|
||||
PossiblyEvaluatedPropertyValue<T> defaultValue_,
|
||||
std::string propertyName_)
|
||||
: Expression(Kind::FormatSectionOverride, type_),
|
||||
: Expression(Kind::FormatSectionOverride,
|
||||
type_,
|
||||
defaultValue_.getDependencies() | Dependency::Override | Dependency::Feature),
|
||||
defaultValue(std::move(defaultValue_)),
|
||||
propertyName(std::move(propertyName_)) {}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
using Bindings = std::map<std::string, std::shared_ptr<Expression>>;
|
||||
|
||||
Let(Bindings bindings_, std::unique_ptr<Expression> result_)
|
||||
: Expression(Kind::Let, result_->getType()),
|
||||
: Expression(Kind::Let, result_->getType(), collectDependencies(bindings_) | Dependency::Bind),
|
||||
bindings(std::move(bindings_)),
|
||||
result(std::move(result_)) {}
|
||||
|
||||
@@ -49,7 +49,7 @@ private:
|
||||
class Var : public Expression {
|
||||
public:
|
||||
Var(std::string name_, std::shared_ptr<Expression> value_)
|
||||
: Expression(Kind::Var, value_->getType()),
|
||||
: Expression(Kind::Var, value_->getType(), depsOf(value_) | Dependency::Var),
|
||||
name(std::move(name_)),
|
||||
value(std::move(value_)) {}
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ namespace expression {
|
||||
class Literal : public Expression {
|
||||
public:
|
||||
Literal(const Value& value_)
|
||||
: Expression(Kind::Literal, typeOf(value_)),
|
||||
: Expression(Kind::Literal, typeOf(value_), Dependency::None),
|
||||
value(value_) {}
|
||||
|
||||
Literal(const type::Array& type_, std::vector<Value> value_)
|
||||
: Expression(Kind::Literal, type_),
|
||||
: Expression(Kind::Literal, type_, Dependency::None),
|
||||
value(std::move(value_)) {}
|
||||
|
||||
EvaluationResult evaluate(const EvaluationContext&) const override { return value; }
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
std::unique_ptr<Expression> input_,
|
||||
Branches branches_,
|
||||
std::unique_ptr<Expression> otherwise_)
|
||||
: Expression(Kind::Match, type_),
|
||||
: Expression(Kind::Match, type_, depsOf(input_) | depsOf(otherwise_) | collectDependencies(branches_)),
|
||||
input(std::move(input_)),
|
||||
branches(std::move(branches_)),
|
||||
otherwise(std::move(otherwise_)) {}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
enum class Dependency : uint32_t;
|
||||
} // namespace expression
|
||||
|
||||
class LayerObserver;
|
||||
class Filter;
|
||||
@@ -159,6 +162,9 @@ public:
|
||||
|
||||
mapbox::base::WeakPtr<Layer> makeWeakPtr() { return weakFactory.makeWeakPtr(); }
|
||||
|
||||
/// Collect dependencies
|
||||
expression::Dependency getDependencies() const noexcept;
|
||||
|
||||
protected:
|
||||
virtual Mutable<Impl> mutableBaseImpl() const = 0;
|
||||
void serializeProperty(Value&, const StyleProperty&, const char* propertyName, bool isPaint) const;
|
||||
|
||||
@@ -20,18 +20,20 @@ public:
|
||||
/// Contains render passes used by the renderer, see `mbgl::RenderPass`.
|
||||
uint8_t renderPasses = 0u;
|
||||
|
||||
virtual expression::Dependency getDependencies() const noexcept = 0;
|
||||
|
||||
protected:
|
||||
LayerProperties(Immutable<Layer::Impl> impl)
|
||||
: baseImpl(std::move(impl)) {}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
inline const auto& getEvaluated(const Immutable<LayerProperties>& properties) {
|
||||
inline const auto& getEvaluated(const Immutable<LayerProperties>& properties) noexcept {
|
||||
return static_cast<const Derived&>(*properties).evaluated;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
inline const auto& getCrossfade(const Immutable<LayerProperties>& properties) {
|
||||
inline const auto& getCrossfade(const Immutable<LayerProperties>& properties) noexcept {
|
||||
return static_cast<const Derived&>(*properties).crossfade;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ class PropertyExpressionBase {
|
||||
public:
|
||||
explicit PropertyExpressionBase(std::unique_ptr<expression::Expression>);
|
||||
|
||||
bool isZoomConstant() const noexcept;
|
||||
bool isFeatureConstant() const noexcept;
|
||||
bool isRuntimeConstant() const noexcept;
|
||||
bool isZoomConstant() const noexcept { return isZoomConstant_; }
|
||||
bool isFeatureConstant() const noexcept { return isFeatureConstant_; }
|
||||
bool isRuntimeConstant() const noexcept { return isRuntimeConstant_; }
|
||||
float interpolationFactor(const Range<float>&, float) const noexcept;
|
||||
Range<float> getCoveringStops(float, float) const noexcept;
|
||||
const expression::Expression& getExpression() const noexcept;
|
||||
@@ -30,12 +30,20 @@ public:
|
||||
|
||||
bool useIntegerZoom = false;
|
||||
|
||||
using Dependency = expression::Dependency;
|
||||
Dependency getDependencies() const noexcept {
|
||||
auto v = expression ? expression->dependencies : Dependency::None;
|
||||
assert(isZoomConstant_ == !(underlying_type(v) & underlying_type(Dependency::Zoom)));
|
||||
assert(isFeatureConstant_ == !(underlying_type(v) & underlying_type(Dependency::Feature)));
|
||||
return v;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<const expression::Expression> expression;
|
||||
variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve;
|
||||
bool isZoomConstant_;
|
||||
bool isFeatureConstant_;
|
||||
bool isRuntimeConstant_;
|
||||
variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -62,6 +62,13 @@ public:
|
||||
bool hasDataDrivenPropertyDifference(const PropertyValue<T>& other) const {
|
||||
return *this != other && (isDataDriven() || other.isDataDriven());
|
||||
}
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
Dependency getDependencies() const noexcept {
|
||||
return value.match([](const Undefined&) noexcept { return Dependency::None; },
|
||||
[](const T&) noexcept { return Dependency::None; },
|
||||
[](const PropertyExpression<T>& ex) noexcept { return ex.getDependencies(); });
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
Reference in New Issue
Block a user