Skip to content

Commit

Permalink
Track expression dependencies (#2113)
Browse files Browse the repository at this point in the history
  • Loading branch information
TimSylvester committed Mar 7, 2024
1 parent 9614b56 commit 25678a4
Show file tree
Hide file tree
Showing 105 changed files with 1,078 additions and 335 deletions.
6 changes: 4 additions & 2 deletions include/mbgl/style/color_ramp_property_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ class ColorRampPropertyValue {
}

public:
ColorRampPropertyValue()
: value(nullptr) {}
ColorRampPropertyValue() noexcept = default;
ColorRampPropertyValue(std::shared_ptr<expression::Expression> value_)
: value(std::move(value_)) {}

Expand All @@ -46,6 +45,9 @@ class ColorRampPropertyValue {
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
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/at.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_)) {}

Expand Down
4 changes: 2 additions & 2 deletions include/mbgl/style/expression/boolean_operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -31,7 +31,7 @@ class Any : public Expression {
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);
Expand Down
8 changes: 7 additions & 1 deletion include/mbgl/style/expression/case.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Case : public Expression {
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_)) {}

Expand All @@ -32,6 +32,12 @@ class Case : public Expression {

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;
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/coalesce.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/coercion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/collator_expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class CollatorExpression : public Expression {

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
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {}
Expand Down
109 changes: 90 additions & 19 deletions include/mbgl/style/expression/expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -135,23 +137,23 @@ class EvaluationResult : public Result<Value> {
};

/**
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,
Expand Down Expand Up @@ -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;

Expand All @@ -195,8 +220,8 @@ class Expression {
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,
Expand Down Expand Up @@ -229,6 +254,8 @@ class Expression {

virtual std::string getOperator() const = 0;

const Dependency dependencies;

protected:
template <typename T>
static bool childrenEqual(const T& lhs, const T& rhs) {
Expand Down Expand Up @@ -261,11 +288,55 @@ class Expression {
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;
};

} // namespace expression
} // namespace style

namespace util {
std::string toString(style::expression::Dependency);
} // namespace util

std::ostream& operator<<(std::ostream&, style::expression::Dependency);

} // namespace mbgl
7 changes: 3 additions & 4 deletions include/mbgl/style/expression/find_zoom_curve.hpp
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -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
Expand Down
17 changes: 11 additions & 6 deletions include/mbgl/style/expression/format_expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -45,6 +45,11 @@ class FormatExpression final : public Expression {
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;
};
Expand Down
4 changes: 3 additions & 1 deletion include/mbgl/style/expression/format_section_override.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ class FormatSectionOverride final : public Expression {
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_)) {}

Expand Down
4 changes: 2 additions & 2 deletions include/mbgl/style/expression/let.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Let : public Expression {
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_)) {}

Expand Down Expand Up @@ -49,7 +49,7 @@ class Let : public Expression {
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_)) {}

Expand Down
4 changes: 2 additions & 2 deletions include/mbgl/style/expression/literal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/match.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Match : public Expression {
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_)) {}
Expand Down

0 comments on commit 25678a4

Please sign in to comment.