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
|
||||
|
||||
@@ -248,14 +248,14 @@ namespace mbgl {
|
||||
double totalFrameEncodingTime = 0;
|
||||
double totalFrameRenderingTime = 0;
|
||||
for (const auto& row : result) {
|
||||
NSLog(@"| %-*s | %4.1f ms | %4.1f ms |", int(colWidth), row.first.c_str(), 1e3 * row.second.first, 1e3 * row.second.second);
|
||||
NSLog(@"| %-*s | %4.2f ms | %4.2f ms |", int(colWidth), row.first.c_str(), 1e3 * row.second.first, 1e3 * row.second.second);
|
||||
totalFrameEncodingTime += row.second.first;
|
||||
totalFrameRenderingTime += row.second.second;
|
||||
}
|
||||
|
||||
NSLog(@"Average frame encoding time: %4.1f ms", totalFrameEncodingTime * 1e3 / result.size());
|
||||
NSLog(@"Average frame rendering time: %4.1f ms", totalFrameRenderingTime * 1e3 / result.size());
|
||||
|
||||
NSLog(@"Average frame encoding time: %4.2f ms", totalFrameEncodingTime * 1e3 / result.size());
|
||||
NSLog(@"Average frame rendering time: %4.2f ms", totalFrameRenderingTime * 1e3 / result.size());
|
||||
|
||||
// NSLog(@"Total uploads: %zu", mbgl::uploadCount);
|
||||
// NSLog(@"Total uploads with dirty vattr: %zu", mbgl::uploadVertextAttrsDirty);
|
||||
// NSLog(@"Total uploads with invalid segs: %zu", mbgl::uploadInvalidSegments);
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
self.testStatus = NO;
|
||||
self.runner = new TestRunner();
|
||||
|
||||
NSError *error;
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
NSString *xcTestBundleRoot = [[NSBundle bundleForClass:[self class]] resourcePath];
|
||||
|
||||
@@ -4,9 +4,42 @@
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/style/style_impl.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/traits.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
namespace {
|
||||
void logStyleDependencies(EventSeverity severity, Event event, const style::Style& style) {
|
||||
using Dependency = style::expression::Dependency;
|
||||
constexpr auto maskCount = underlying_type(Dependency::MaskCount);
|
||||
std::array<std::size_t, maskCount + 1> counts = {0};
|
||||
const auto layers = style.getLayers();
|
||||
for (const auto& layer : layers) {
|
||||
const auto deps = layer->getDependencies();
|
||||
if (deps == Dependency::None) {
|
||||
counts[0]++;
|
||||
} else {
|
||||
for (size_t i = 0; i < maskCount; ++i) {
|
||||
const auto mask = Dependency{1u << i};
|
||||
if ((deps & mask) == mask) {
|
||||
counts[i + 1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ostringstream ss;
|
||||
ss << "Style '" << style.getName() << "' has " << layers.size() << " layers:\n";
|
||||
ss << " " << Dependency::None << ": " << counts[0] << "\n";
|
||||
for (size_t i = 0; i < maskCount; ++i) {
|
||||
ss << " " << Dependency{1u << i} << ": " << counts[i + 1] << "\n";
|
||||
}
|
||||
Log::Record(severity, event, ss.str());
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
Map::Impl::Impl(RendererFrontend& frontend_,
|
||||
MapObserver& observer_,
|
||||
std::shared_ptr<FileSource> fileSource_,
|
||||
@@ -84,6 +117,10 @@ void Map::Impl::onStyleLoaded() {
|
||||
annotationManager.onStyleLoaded();
|
||||
}
|
||||
observer.onDidFinishLoadingStyle();
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
logStyleDependencies(EventSeverity::Info, Event::Style, *style);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Map::Impl::onStyleError(std::exception_ptr error) {
|
||||
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
ResultType operator()(const T& constant) const { return ResultType(constant); }
|
||||
|
||||
ResultType operator()(const style::PropertyExpression<T>& expression) const {
|
||||
if (useIntegerZoom) { // Compiler will optimize out the unused branch.
|
||||
if constexpr (useIntegerZoom) { // Compiler will optimize out the unused branch.
|
||||
if (!expression.isFeatureConstant() || !expression.isRuntimeConstant()) {
|
||||
auto returnExpression = expression;
|
||||
returnExpression.useIntegerZoom = true;
|
||||
|
||||
@@ -42,7 +42,9 @@ inline const BackgroundLayer::Impl& impl_cast(const Immutable<style::Layer::Impl
|
||||
|
||||
RenderBackgroundLayer::RenderBackgroundLayer(Immutable<style::BackgroundLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<BackgroundLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderBackgroundLayer::~RenderBackgroundLayer() = default;
|
||||
|
||||
|
||||
@@ -62,7 +62,9 @@ inline const style::CircleLayer::Impl& impl_cast(const Immutable<style::Layer::I
|
||||
|
||||
RenderCircleLayer::RenderCircleLayer(Immutable<style::CircleLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<CircleLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
void RenderCircleLayer::transition(const TransitionParameters& parameters) {
|
||||
unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated));
|
||||
|
||||
@@ -47,7 +47,9 @@ inline const FillExtrusionLayer::Impl& impl_cast(const Immutable<style::Layer::I
|
||||
|
||||
RenderFillExtrusionLayer::RenderFillExtrusionLayer(Immutable<style::FillExtrusionLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<FillExtrusionLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderFillExtrusionLayer::~RenderFillExtrusionLayer() = default;
|
||||
|
||||
|
||||
@@ -59,7 +59,9 @@ inline const FillLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& imp
|
||||
|
||||
RenderFillLayer::RenderFillLayer(Immutable<style::FillLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<FillLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderFillLayer::~RenderFillLayer() = default;
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ inline const HeatmapLayer::Impl& impl_cast(const Immutable<Layer::Impl>& impl) {
|
||||
RenderHeatmapLayer::RenderHeatmapLayer(Immutable<HeatmapLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<HeatmapLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
colorRamp = std::make_shared<PremultipliedImage>(Size(256, 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ inline const HillshadeLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>
|
||||
|
||||
RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<HillshadeLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderHillshadeLayer::~RenderHillshadeLayer() = default;
|
||||
|
||||
|
||||
@@ -55,7 +55,9 @@ const auto posNormalAttribName = "a_pos_normal";
|
||||
RenderLineLayer::RenderLineLayer(Immutable<style::LineLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<LineLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()),
|
||||
colorRamp(std::make_shared<PremultipliedImage>(Size(256, 1))) {}
|
||||
colorRamp(std::make_shared<PremultipliedImage>(Size(256, 1))) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderLineLayer::~RenderLineLayer() = default;
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@ inline const RasterLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& i
|
||||
|
||||
RenderRasterLayer::RenderRasterLayer(Immutable<style::RasterLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<RasterLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderRasterLayer::~RenderRasterLayer() = default;
|
||||
|
||||
|
||||
@@ -358,7 +358,9 @@ inline const SymbolLayer::Impl& impl_cast(const Immutable<style::Layer::Impl>& i
|
||||
|
||||
RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl)
|
||||
: RenderLayer(makeMutable<SymbolLayerProperties>(std::move(_impl))),
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {}
|
||||
unevaluated(impl_cast(baseImpl).paint.untransitioned()) {
|
||||
styleDependencies = unevaluated.getDependencies();
|
||||
}
|
||||
|
||||
RenderSymbolLayer::~RenderSymbolLayer() = default;
|
||||
|
||||
|
||||
@@ -57,6 +57,13 @@ public:
|
||||
return expression.evaluate(zoom, feature, featureState, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
Dependency getDependencies() const noexcept {
|
||||
return value.match(
|
||||
[](const T&) noexcept { return Dependency::None; },
|
||||
[](const style::PropertyExpression<T>& expression) noexcept { return expression.getDependencies(); });
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -105,6 +112,13 @@ public:
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
Dependency getDependencies() const noexcept {
|
||||
return value.match(
|
||||
[](const Faded<T>&) noexcept { return Dependency::None; },
|
||||
[](const style::PropertyExpression<T>& expression) noexcept { return expression.getDependencies(); });
|
||||
}
|
||||
};
|
||||
|
||||
namespace util {
|
||||
|
||||
@@ -194,6 +194,9 @@ public:
|
||||
bool isLayerRenderable() const noexcept { return isRenderable; }
|
||||
#endif
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
Dependency getStyleDependencies() const { return styleDependencies; }
|
||||
|
||||
protected:
|
||||
// Checks whether the current hardware can render this layer. If it can't,
|
||||
// we'll show a warning in the console to inform the developer.
|
||||
@@ -299,6 +302,8 @@ protected:
|
||||
// Current layer index as specified by the layerIndexChanged event
|
||||
int32_t layerIndex{0};
|
||||
|
||||
Dependency styleDependencies = Dependency::None;
|
||||
|
||||
// Current renderable status as specified by the markLayerRenderable event
|
||||
bool isRenderable{false};
|
||||
|
||||
|
||||
@@ -300,8 +300,14 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(
|
||||
for (RenderLayer& layer : orderedLayers) {
|
||||
const std::string& id = layer.getID();
|
||||
const bool layerAddedOrChanged = layerDiff.added.count(id) || layerDiff.changed.count(id);
|
||||
if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) {
|
||||
auto previousMask = layer.evaluatedProperties->constantsMask();
|
||||
|
||||
// Only re-evaluate on change of zoom if the style has some reference to it
|
||||
using Dependency = expression::Dependency;
|
||||
const bool zoomChangedAndMatters = zoomChanged && !layerAddedOrChanged &&
|
||||
(layer.getStyleDependencies() & Dependency::Zoom) != Dependency::None;
|
||||
|
||||
if (layerAddedOrChanged || zoomChangedAndMatters || layer.hasTransition() || layer.hasCrossfade()) {
|
||||
const auto previousMask = layer.evaluatedProperties->constantsMask();
|
||||
layer.evaluate(evaluationParameters);
|
||||
if (previousMask != layer.evaluatedProperties->constantsMask()) {
|
||||
constantsMaskChanged.insert(id);
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace expression {
|
||||
using namespace mbgl::style::conversion;
|
||||
|
||||
Assertion::Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_)
|
||||
: Expression(Kind::Assertion, std::move(type_)),
|
||||
: Expression(Kind::Assertion, std::move(type_), collectDependencies(inputs_)),
|
||||
inputs(std::move(inputs_)) {
|
||||
assert(!inputs.empty());
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@ namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
using CoerceFunction = EvaluationResult (*)(const Value&);
|
||||
|
||||
namespace {
|
||||
|
||||
EvaluationResult toBoolean(const Value& v) {
|
||||
return v.match([&](double f) { return static_cast<bool>(f); },
|
||||
[&](const std::string& s) { return s.length() > 0; },
|
||||
@@ -76,28 +80,39 @@ EvaluationResult toImage(const Value& imageValue) {
|
||||
return Image(toString(imageValue).c_str());
|
||||
}
|
||||
|
||||
Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_)
|
||||
: Expression(Kind::Coercion, std::move(type_)),
|
||||
EvaluationResult toStringValue(const Value& imageValue) {
|
||||
return toString(imageValue);
|
||||
}
|
||||
|
||||
CoerceFunction getCoerceFunction(const type::Type& t) {
|
||||
if (t.is<type::BooleanType>()) {
|
||||
return toBoolean;
|
||||
} else if (t.is<type::ColorType>()) {
|
||||
return toColor;
|
||||
} else if (t.is<type::NumberType>()) {
|
||||
return toNumber;
|
||||
} else if (t.is<type::StringType>()) {
|
||||
return toStringValue;
|
||||
} else if (t.is<type::FormattedType>()) {
|
||||
return toFormatted;
|
||||
} else if (t.is<type::ImageType>()) {
|
||||
return toImage;
|
||||
}
|
||||
assert(false);
|
||||
return toStringValue;
|
||||
}
|
||||
|
||||
Dependency extraDependency(const type::Type& t) {
|
||||
return t.is<type::ImageType>() ? Dependency::Image : Dependency::None;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Coercion::Coercion(const type::Type& type_, std::vector<std::unique_ptr<Expression>> inputs_)
|
||||
: Expression(Kind::Coercion, type_, collectDependencies(inputs_) | extraDependency(type_)),
|
||||
coerceSingleValue(getCoerceFunction(getType())),
|
||||
inputs(std::move(inputs_)) {
|
||||
assert(!inputs.empty());
|
||||
type::Type t = getType();
|
||||
if (t.is<type::BooleanType>()) {
|
||||
coerceSingleValue = toBoolean;
|
||||
} else if (t.is<type::ColorType>()) {
|
||||
coerceSingleValue = toColor;
|
||||
} else if (t.is<type::NumberType>()) {
|
||||
coerceSingleValue = toNumber;
|
||||
} else if (t.is<type::StringType>()) {
|
||||
coerceSingleValue = [](const Value& v) -> EvaluationResult {
|
||||
return toString(v);
|
||||
};
|
||||
} else if (t.is<type::FormattedType>()) {
|
||||
coerceSingleValue = toFormatted;
|
||||
} else if (t.is<type::ImageType>()) {
|
||||
coerceSingleValue = toImage;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
mbgl::Value Coercion::serialize() const {
|
||||
|
||||
@@ -11,7 +11,9 @@ namespace expression {
|
||||
CollatorExpression::CollatorExpression(std::unique_ptr<Expression> caseSensitive_,
|
||||
std::unique_ptr<Expression> diacriticSensitive_,
|
||||
std::optional<std::unique_ptr<Expression>> locale_)
|
||||
: Expression(Kind::CollatorExpression, type::Collator),
|
||||
: Expression(Kind::CollatorExpression,
|
||||
type::Collator,
|
||||
depsOf(caseSensitive_) | depsOf(diacriticSensitive_) | depsOf(locale_)),
|
||||
caseSensitive(std::move(caseSensitive_)),
|
||||
diacriticSensitive(std::move(diacriticSensitive_)),
|
||||
locale(std::move(locale_)) {}
|
||||
@@ -56,7 +58,7 @@ ParseResult CollatorExpression::parse(const Convertible& value, ParsingContext&
|
||||
ParseResult locale;
|
||||
if (localeOption) {
|
||||
locale = ctx.parse(*localeOption, 1, {type::String});
|
||||
if (!locale) {
|
||||
if (!locale || !*locale) {
|
||||
return ParseResult();
|
||||
}
|
||||
}
|
||||
@@ -68,15 +70,17 @@ ParseResult CollatorExpression::parse(const Convertible& value, ParsingContext&
|
||||
void CollatorExpression::eachChild(const std::function<void(const Expression&)>& fn) const {
|
||||
fn(*caseSensitive);
|
||||
fn(*diacriticSensitive);
|
||||
if (locale) {
|
||||
if (locale && *locale) {
|
||||
fn(**locale);
|
||||
}
|
||||
}
|
||||
|
||||
bool CollatorExpression::operator==(const Expression& e) const {
|
||||
if (e.getKind() == Kind::CollatorExpression) {
|
||||
auto rhs = static_cast<const CollatorExpression*>(&e);
|
||||
if ((locale && (!rhs->locale || **locale != **(rhs->locale))) || (!locale && rhs->locale)) {
|
||||
const auto* rhs = static_cast<const CollatorExpression*>(&e);
|
||||
const bool lLocSet = locale && *locale;
|
||||
const bool rLocSet = rhs->locale && *rhs->locale;
|
||||
if ((!lLocSet && rLocSet) || (lLocSet && (!rLocSet || **locale != **rhs->locale))) {
|
||||
return false;
|
||||
}
|
||||
return *caseSensitive == *(rhs->caseSensitive) && *diacriticSensitive == *(rhs->diacriticSensitive);
|
||||
@@ -88,7 +92,7 @@ mbgl::Value CollatorExpression::serialize() const {
|
||||
std::unordered_map<std::string, mbgl::Value> options;
|
||||
options["case-sensitive"] = caseSensitive->serialize();
|
||||
options["diacritic-sensitive"] = diacriticSensitive->serialize();
|
||||
if (locale) {
|
||||
if (locale && *locale) {
|
||||
options["locale"] = (*locale)->serialize();
|
||||
}
|
||||
return std::vector<mbgl::Value>{{std::string("collator"), options}};
|
||||
@@ -105,12 +109,13 @@ EvaluationResult CollatorExpression::evaluate(const EvaluationContext& params) c
|
||||
}
|
||||
|
||||
if (locale) {
|
||||
auto localeResult = (*locale)->evaluate(params);
|
||||
if (!localeResult) {
|
||||
if (auto localeResult = (*locale)->evaluate(params)) {
|
||||
return Collator(caseSensitiveResult->get<bool>(),
|
||||
diacriticSensitiveResult->get<bool>(),
|
||||
localeResult->get<std::string>());
|
||||
} else {
|
||||
return localeResult.error();
|
||||
}
|
||||
return Collator(
|
||||
caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>(), localeResult->get<std::string>());
|
||||
} else {
|
||||
return Collator(caseSensitiveResult->get<bool>(), diacriticSensitiveResult->get<bool>());
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ static CollatorComparison::CompareFunctionType getCollatorComparisonFunction(con
|
||||
}
|
||||
|
||||
BasicComparison::BasicComparison(std::string op_, std::unique_ptr<Expression> lhs_, std::unique_ptr<Expression> rhs_)
|
||||
: Expression(Kind::Comparison, type::Boolean),
|
||||
: Expression(Kind::Comparison, type::Boolean, depsOf(lhs_) | depsOf(rhs_)),
|
||||
op(std::move(op_)),
|
||||
compare(getBasicCompareFunction(op)),
|
||||
lhs(std::move(lhs_)),
|
||||
@@ -168,7 +168,7 @@ CollatorComparison::CollatorComparison(std::string op_,
|
||||
std::unique_ptr<Expression> lhs_,
|
||||
std::unique_ptr<Expression> rhs_,
|
||||
std::unique_ptr<Expression> collator_)
|
||||
: Expression(Kind::Comparison, type::Boolean),
|
||||
: Expression(Kind::Comparison, type::Boolean, depsOf(lhs_) | depsOf(rhs_) | depsOf(collator_)),
|
||||
op(std::move(op_)),
|
||||
compare(getCollatorComparisonFunction(op)),
|
||||
lhs(std::move(lhs_)),
|
||||
|
||||
@@ -47,17 +47,22 @@ namespace detail {
|
||||
struct SignatureBase {
|
||||
using Args = std::vector<std::unique_ptr<Expression>>;
|
||||
|
||||
SignatureBase(type::Type result_, variant<std::vector<type::Type>, VarargsType> params_, std::string name_)
|
||||
SignatureBase(type::Type result_,
|
||||
variant<std::vector<type::Type>, VarargsType> params_,
|
||||
std::string name_,
|
||||
Dependency dependencies_)
|
||||
: result(std::move(result_)),
|
||||
params(std::move(params_)),
|
||||
name(std::move(name_)) {}
|
||||
name(std::move(name_)),
|
||||
dependencies(dependencies_) {}
|
||||
virtual ~SignatureBase() = default;
|
||||
|
||||
virtual EvaluationResult apply(const EvaluationContext&, const Args&) const = 0;
|
||||
|
||||
type::Type result;
|
||||
variant<std::vector<type::Type>, VarargsType> params;
|
||||
std::string name;
|
||||
const type::Type result;
|
||||
const variant<std::vector<type::Type>, VarargsType> params;
|
||||
const std::string name;
|
||||
const Dependency dependencies;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -87,10 +92,11 @@ struct Signature;
|
||||
// Simple evaluate function (const T0&, const T1&, ...) -> Result<U>
|
||||
template <class R, class... Params>
|
||||
struct Signature<R(Params...)> : SignatureBase {
|
||||
Signature(R (*evaluate_)(Params...), const std::string& name_)
|
||||
Signature(R (*evaluate_)(Params...), const std::string& name_, Dependency dependencies_)
|
||||
: SignatureBase(valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
std::vector<type::Type>{valueTypeToExpressionType<std::decay_t<Params>>()...},
|
||||
name_),
|
||||
name_,
|
||||
dependencies_),
|
||||
evaluate(evaluate_) {}
|
||||
|
||||
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const override {
|
||||
@@ -119,10 +125,11 @@ private:
|
||||
// Varargs evaluate function (const Varargs<T>&) -> Result<U>
|
||||
template <class R, typename T>
|
||||
struct Signature<R(const Varargs<T>&)> : SignatureBase {
|
||||
Signature(R (*evaluate_)(const Varargs<T>&), const std::string& name_)
|
||||
Signature(R (*evaluate_)(const Varargs<T>&), const std::string& name_, Dependency dependencies_)
|
||||
: SignatureBase(valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
VarargsType{valueTypeToExpressionType<T>()},
|
||||
name_),
|
||||
name_,
|
||||
dependencies_),
|
||||
evaluate(evaluate_) {}
|
||||
|
||||
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const override {
|
||||
@@ -145,10 +152,11 @@ struct Signature<R(const Varargs<T>&)> : SignatureBase {
|
||||
// (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>
|
||||
template <class R, class... Params>
|
||||
struct Signature<R(const EvaluationContext&, Params...)> : SignatureBase {
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, Params...), const std::string& name_)
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, Params...), const std::string& name_, Dependency dependencies_)
|
||||
: SignatureBase(valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
std::vector<type::Type>{valueTypeToExpressionType<std::decay_t<Params>>()...},
|
||||
name_),
|
||||
name_,
|
||||
dependencies_),
|
||||
evaluate(evaluate_) {}
|
||||
|
||||
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const override {
|
||||
@@ -178,10 +186,13 @@ private:
|
||||
// (const EvaluationContext&, const Varargs<T>&) -> Result<U>
|
||||
template <class R, typename T>
|
||||
struct Signature<R(const EvaluationContext&, const Varargs<T>&)> : SignatureBase {
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&), const std::string& name_)
|
||||
Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&),
|
||||
const std::string& name_,
|
||||
Dependency dependencies_)
|
||||
: SignatureBase(valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
|
||||
VarargsType{valueTypeToExpressionType<T>()},
|
||||
name_),
|
||||
name_,
|
||||
dependencies_),
|
||||
evaluate(evaluate_) {}
|
||||
|
||||
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const override {
|
||||
@@ -215,8 +226,11 @@ struct SignatureType<Lambda, std::enable_if_t<std::is_class_v<Lambda>>> {
|
||||
};
|
||||
|
||||
template <typename Fn>
|
||||
static std::unique_ptr<detail::SignatureBase> makeSignature(std::string name, Fn evaluateFunction) {
|
||||
return std::make_unique<Signature<typename SignatureType<Fn>::Type>>(evaluateFunction, std::move(name));
|
||||
static std::unique_ptr<detail::SignatureBase> makeSignature(std::string name,
|
||||
Fn evaluateFunction,
|
||||
Dependency dependencies = Dependency::None) {
|
||||
return std::make_unique<Signature<typename SignatureType<Fn>::Type>>(
|
||||
evaluateFunction, std::move(name), dependencies);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -322,14 +336,17 @@ const auto& rgbCompoundExpression() {
|
||||
}
|
||||
|
||||
const auto& zoomCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("zoom", [](const EvaluationContext& params) -> Result<double> {
|
||||
if (!params.zoom) {
|
||||
return EvaluationError{
|
||||
"The 'zoom' expression is unavailable in the current "
|
||||
"evaluation context."};
|
||||
}
|
||||
return *(params.zoom);
|
||||
});
|
||||
static auto signature = detail::makeSignature(
|
||||
"zoom",
|
||||
[](const EvaluationContext& params) -> Result<double> {
|
||||
if (!params.zoom) {
|
||||
return EvaluationError{
|
||||
"The 'zoom' expression is unavailable in the current "
|
||||
"evaluation context."};
|
||||
}
|
||||
return *(params.zoom);
|
||||
},
|
||||
Dependency::Zoom);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -374,7 +391,8 @@ const auto& accumulatedCompoundExpression() {
|
||||
|
||||
const auto& hasContextCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
|
||||
"has",
|
||||
[](const EvaluationContext& params, const std::string& key) -> Result<bool> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
@@ -382,21 +400,25 @@ const auto& hasContextCompoundExpression() {
|
||||
}
|
||||
|
||||
return static_cast<bool>(params.feature->getValue(key));
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& hasObjectCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> {
|
||||
"has",
|
||||
[](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> {
|
||||
return object.find(key) != object.end();
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& getContextCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"get", [](const EvaluationContext& params, const std::string& key) -> Result<Value> {
|
||||
"get",
|
||||
[](const EvaluationContext& params, const std::string& key) -> Result<Value> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
@@ -408,28 +430,30 @@ const auto& getContextCompoundExpression() {
|
||||
return Null;
|
||||
}
|
||||
return Value(toExpressionValue(*propertyValue));
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& getObjectCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"get", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<Value> {
|
||||
"get",
|
||||
[](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<Value> {
|
||||
if (object.find(key) == object.end()) {
|
||||
return Null;
|
||||
}
|
||||
return object.at(key);
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& propertiesCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> {
|
||||
"properties",
|
||||
[](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
"context."};
|
||||
return EvaluationError{"Feature data is unavailable in the current evaluation context."};
|
||||
}
|
||||
std::unordered_map<std::string, Value> result;
|
||||
const PropertyMap& properties = params.feature->getProperties();
|
||||
@@ -438,44 +462,50 @@ const auto& propertiesCompoundExpression() {
|
||||
result[entry.first] = toExpressionValue(entry.second);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& geometryTypeCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("geometry-type",
|
||||
[](const EvaluationContext& params) -> Result<std::string> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
"context."};
|
||||
}
|
||||
static auto signature = detail::makeSignature(
|
||||
"geometry-type",
|
||||
[](const EvaluationContext& params) -> Result<std::string> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
"context."};
|
||||
}
|
||||
|
||||
auto type = params.feature->getType();
|
||||
if (type == FeatureType::Point) {
|
||||
return "Point";
|
||||
} else if (type == FeatureType::LineString) {
|
||||
return "LineString";
|
||||
} else if (type == FeatureType::Polygon) {
|
||||
return "Polygon";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
});
|
||||
auto type = params.feature->getType();
|
||||
if (type == FeatureType::Point) {
|
||||
return "Point";
|
||||
} else if (type == FeatureType::LineString) {
|
||||
return "LineString";
|
||||
} else if (type == FeatureType::Polygon) {
|
||||
return "Polygon";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& idCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("id", [](const EvaluationContext& params) -> Result<Value> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
"context."};
|
||||
}
|
||||
static auto signature = detail::makeSignature(
|
||||
"id",
|
||||
[](const EvaluationContext& params) -> Result<Value> {
|
||||
if (!params.feature) {
|
||||
return EvaluationError{
|
||||
"Feature data is unavailable in the current evaluation "
|
||||
"context."};
|
||||
}
|
||||
|
||||
auto id = params.feature->getID();
|
||||
return id.match([](const auto& idValue) { return toExpressionValue(mbgl::Value(idValue)); });
|
||||
});
|
||||
auto id = params.feature->getID();
|
||||
return id.match([](const auto& idValue) { return toExpressionValue(mbgl::Value(idValue)); });
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -675,7 +705,8 @@ const auto& errorCompoundExpression() {
|
||||
|
||||
const auto& featureStateCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"feature-state", [](const EvaluationContext& params, const std::string& key) -> Result<Value> {
|
||||
"feature-state",
|
||||
[](const EvaluationContext& params, const std::string& key) -> Result<Value> {
|
||||
mbgl::Value state;
|
||||
if (params.featureState != nullptr) {
|
||||
auto it = params.featureState->find(key);
|
||||
@@ -684,43 +715,52 @@ const auto& featureStateCompoundExpression() {
|
||||
}
|
||||
}
|
||||
return toExpressionValue(state);
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
// Legacy Filters
|
||||
const auto& filterEqualsCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-==", [](const EvaluationContext& params, const std::string& key, const Value& lhs) -> Result<bool> {
|
||||
"filter-==",
|
||||
[](const EvaluationContext& params, const std::string& key, const Value& lhs) -> Result<bool> {
|
||||
const auto rhs = featurePropertyAsExpressionValue(params, key);
|
||||
return rhs ? lhs == *rhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdEqualsCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-==", [](const EvaluationContext& params, const Value& lhs) -> Result<bool> {
|
||||
"filter-id-==",
|
||||
[](const EvaluationContext& params, const Value& lhs) -> Result<bool> {
|
||||
return lhs == featureIdAsExpressionValue(params);
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterTypeEqualsCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-type-==", [](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
"filter-type-==",
|
||||
[](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
if (!params.feature) return false;
|
||||
return featureTypeAsString(params.feature->getType()) == lhs;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterLessThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
"filter-<",
|
||||
[](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsDouble(params, key);
|
||||
return rhs ? rhs < lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -730,34 +770,41 @@ const auto& filterLessThanStringCompoundExpression() {
|
||||
[](const EvaluationContext& params, const std::string& key, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsString(params, key);
|
||||
return rhs ? rhs < lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdLessThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("filter-id-<",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs < lhs : false;
|
||||
});
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-<",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs < lhs : false;
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdLessThanStringCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-<", [](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
"filter-id-<",
|
||||
[](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsString(params);
|
||||
return rhs ? rhs < lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterMoreThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
"filter->",
|
||||
[](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsDouble(params, key);
|
||||
return rhs ? rhs > lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -767,34 +814,41 @@ const auto& filterMoreThanStringCompoundExpression() {
|
||||
[](const EvaluationContext& params, const std::string& key, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsString(params, key);
|
||||
return rhs ? rhs > lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdMoreThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("filter-id->",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs > lhs : false;
|
||||
});
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id->",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs > lhs : false;
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdMoreThanStringCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id->", [](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
"filter-id->",
|
||||
[](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsString(params);
|
||||
return rhs ? rhs > lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterLessOrEqualThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
"filter-<=",
|
||||
[](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsDouble(params, key);
|
||||
return rhs ? rhs <= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -804,34 +858,41 @@ const auto& filterLessOrEqualThanStringCompoundExpression() {
|
||||
[](const EvaluationContext& params, const std::string& key, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsString(params, key);
|
||||
return rhs ? rhs <= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdLessOrEqualThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
"filter-id-<=",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs <= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdLessOrEqualThanStringCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-<=", [](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
"filter-id-<=",
|
||||
[](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsString(params);
|
||||
return rhs ? rhs <= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterGreaterOrEqualThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
"filter->=",
|
||||
[](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsDouble(params, key);
|
||||
return rhs ? rhs >= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -841,72 +902,88 @@ const auto& filterGreaterOrEqualThanStringCompoundExpression() {
|
||||
[](const EvaluationContext& params, const std::string& key, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featurePropertyAsString(params, key);
|
||||
return rhs ? rhs >= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdGreaterOrEqualThanNumberCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
"filter-id->=",
|
||||
[](const EvaluationContext& params, double lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsDouble(params);
|
||||
return rhs ? rhs >= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdGreaterOrEqualThanStringCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id->=", [](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
"filter-id->=",
|
||||
[](const EvaluationContext& params, const std::string& lhs) -> Result<bool> {
|
||||
auto rhs = featureIdAsString(params);
|
||||
return rhs ? rhs >= lhs : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterHasCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
|
||||
"filter-has",
|
||||
[](const EvaluationContext& params, const std::string& key) -> Result<bool> {
|
||||
assert(params.feature);
|
||||
return bool(params.feature->getValue(key));
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterHasIdCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("filter-has-id", [](const EvaluationContext& params) -> Result<bool> {
|
||||
assert(params.feature);
|
||||
return !params.feature->getID().is<NullValue>();
|
||||
});
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-has-id",
|
||||
[](const EvaluationContext& params) -> Result<bool> {
|
||||
assert(params.feature);
|
||||
return !params.feature->getID().is<NullValue>();
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterTypeInCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> {
|
||||
"filter-type-in",
|
||||
[](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> {
|
||||
assert(params.feature);
|
||||
std::optional<std::string> type = featureTypeAsString(params.feature->getType());
|
||||
return std::find(types.begin(), types.end(), type) != types.end();
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterIdInCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> {
|
||||
"filter-id-in",
|
||||
[](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> {
|
||||
auto id = featureIdAsExpressionValue(params);
|
||||
return std::find(ids.begin(), ids.end(), id) != ids.end();
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& filterInCompoundExpression() {
|
||||
static auto signature = detail::makeSignature(
|
||||
"filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> {
|
||||
"filter-in",
|
||||
[](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> {
|
||||
if (varargs.size() < 2) return false;
|
||||
assert(varargs[0].is<std::string>());
|
||||
auto value = featurePropertyAsExpressionValue(params, varargs[0].get<std::string>());
|
||||
return value ? std::find(varargs.begin() + 1, varargs.end(), *value) != varargs.end() : false;
|
||||
});
|
||||
},
|
||||
Dependency::Feature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
@@ -1158,7 +1235,7 @@ ParseResult createCompoundExpression(const std::string& name,
|
||||
|
||||
CompoundExpression::CompoundExpression(const detail::SignatureBase& signature_,
|
||||
std::vector<std::unique_ptr<Expression>> args_)
|
||||
: Expression(Kind::CompoundExpression, signature_.result),
|
||||
: Expression(Kind::CompoundExpression, signature_.result, signature_.dependencies | collectDependencies(args_)),
|
||||
signature(signature_),
|
||||
args(std::move(args_)) {}
|
||||
|
||||
|
||||
@@ -770,7 +770,7 @@ namespace style {
|
||||
namespace expression {
|
||||
|
||||
Distance::Distance(GeoJSON geojson, Feature::geometry_type geometries_)
|
||||
: Expression(Kind::Distance, type::Number),
|
||||
: Expression(Kind::Distance, type::Number, Dependency::Feature),
|
||||
geoJSONSource(std::move(geojson)),
|
||||
geometries(std::move(geometries_)) {}
|
||||
|
||||
|
||||
@@ -1,9 +1,49 @@
|
||||
#include <mbgl/style/expression/compound_expression.hpp>
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
using Dependency = style::expression::Dependency;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Dependency deps) {
|
||||
if (deps == Dependency::None) {
|
||||
os << "None";
|
||||
return os;
|
||||
}
|
||||
|
||||
bool any = false;
|
||||
const auto add = [&](Dependency dep, std::string_view name) {
|
||||
if ((deps & dep) != Dependency::None) {
|
||||
os << (any ? "|" : std::string_view{}) << name;
|
||||
any = true;
|
||||
}
|
||||
};
|
||||
|
||||
add(Dependency::Feature, "Feature");
|
||||
add(Dependency::Image, "Image");
|
||||
add(Dependency::Zoom, "Zoom");
|
||||
add(Dependency::Location, "Location");
|
||||
add(Dependency::Bind, "Bind");
|
||||
add(Dependency::Var, "Var");
|
||||
add(Dependency::Override, "Override");
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace util {
|
||||
|
||||
std::string toString(const style::expression::Dependency deps) {
|
||||
std::ostringstream ss;
|
||||
ss << deps;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <mbgl/style/expression/let.hpp>
|
||||
#include <mbgl/style/expression/coalesce.hpp>
|
||||
#include <mbgl/style/expression/is_constant.hpp>
|
||||
|
||||
#include <mbgl/util/logging.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
|
||||
#include <optional>
|
||||
@@ -79,16 +79,16 @@ std::optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCu
|
||||
return result;
|
||||
}
|
||||
|
||||
variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e) {
|
||||
if (isZoomConstant(*e)) {
|
||||
return nullptr;
|
||||
}
|
||||
return findZoomCurve(e)->match(
|
||||
[](const ParsingError&) -> variant<std::nullptr_t, const Interpolate*, const Step*> {
|
||||
assert(false);
|
||||
using ZoomCurveOrNull = variant<std::nullptr_t, const Interpolate*, const Step*>;
|
||||
|
||||
ZoomCurveOrNull findZoomCurveChecked(const expression::Expression& e) {
|
||||
assert(!expression::isZoomConstant(e));
|
||||
return findZoomCurve(&e)->match(
|
||||
[](const ParsingError& err) -> ZoomCurveOrNull {
|
||||
Log::Error(Event::Style, "Invalid Expression: " + err.message);
|
||||
return nullptr;
|
||||
},
|
||||
[](auto zoomCurve) -> variant<std::nullptr_t, const Interpolate*, const Step*> { return zoomCurve; });
|
||||
[](auto zoomCurve) -> ZoomCurveOrNull { return zoomCurve; });
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
|
||||
@@ -9,27 +9,24 @@ namespace expression {
|
||||
FormatExpressionSection::FormatExpressionSection(std::unique_ptr<Expression> content_)
|
||||
: content(std::move(content_)) {}
|
||||
|
||||
void FormatExpressionSection::setTextSectionOptions(std::optional<std::unique_ptr<Expression>> fontScale_,
|
||||
std::optional<std::unique_ptr<Expression>> textFont_,
|
||||
std::optional<std::unique_ptr<Expression>> textColor_) {
|
||||
void FormatExpressionSection::setTextSectionOptions(std::unique_ptr<Expression>&& fontScale_,
|
||||
std::unique_ptr<Expression>&& textFont_,
|
||||
std::unique_ptr<Expression>&& textColor_) {
|
||||
if (fontScale_) {
|
||||
assert(*fontScale_);
|
||||
fontScale = std::shared_ptr<Expression>(std::move(*fontScale_));
|
||||
fontScale = std::shared_ptr<Expression>(std::move(fontScale_));
|
||||
}
|
||||
|
||||
if (textFont_) {
|
||||
assert(*textFont_);
|
||||
textFont = std::shared_ptr<Expression>(std::move(*textFont_));
|
||||
textFont = std::shared_ptr<Expression>(std::move(textFont_));
|
||||
}
|
||||
|
||||
if (textColor_) {
|
||||
assert(*textColor_);
|
||||
textColor = std::shared_ptr<Expression>(std::move(*textColor_));
|
||||
textColor = std::shared_ptr<Expression>(std::move(textColor_));
|
||||
}
|
||||
}
|
||||
|
||||
FormatExpression::FormatExpression(std::vector<FormatExpressionSection> sections_)
|
||||
: Expression(Kind::FormatExpression, type::Formatted),
|
||||
: Expression(Kind::FormatExpression, type::Formatted, collectDependencies(sections_, &depsOfSection)),
|
||||
sections(std::move(sections_)) {}
|
||||
|
||||
using namespace mbgl::style::conversion;
|
||||
@@ -80,7 +77,9 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
|
||||
}
|
||||
}
|
||||
|
||||
sections.back().setTextSectionOptions(std::move(fontScale), std::move(textFont), std::move(textColor));
|
||||
sections.back().setTextSectionOptions(fontScale ? std::move(*fontScale) : std::unique_ptr<Expression>{},
|
||||
textFont ? std::move(*textFont) : std::unique_ptr<Expression>{},
|
||||
textColor ? std::move(*textColor) : std::unique_ptr<Expression>{});
|
||||
} else {
|
||||
ParseResult parsedArg = ctx.parse(arg, 1, {type::Value});
|
||||
if (!parsedArg) {
|
||||
@@ -100,13 +99,13 @@ void FormatExpression::eachChild(const std::function<void(const Expression&)>& f
|
||||
for (auto& section : sections) {
|
||||
fn(*section.content);
|
||||
if (section.fontScale) {
|
||||
fn(**section.fontScale);
|
||||
fn(*section.fontScale);
|
||||
}
|
||||
if (section.textFont) {
|
||||
fn(**section.textFont);
|
||||
fn(*section.textFont);
|
||||
}
|
||||
if (section.textColor) {
|
||||
fn(**section.textColor);
|
||||
fn(*section.textColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,15 +122,15 @@ bool FormatExpression::operator==(const Expression& e) const {
|
||||
if (*lhsSection.content != *rhsSection.content) {
|
||||
return false;
|
||||
}
|
||||
if ((lhsSection.fontScale && (!rhsSection.fontScale || **lhsSection.fontScale != **rhsSection.fontScale)) ||
|
||||
if ((lhsSection.fontScale && (!rhsSection.fontScale || *lhsSection.fontScale != *rhsSection.fontScale)) ||
|
||||
(!lhsSection.fontScale && rhsSection.fontScale)) {
|
||||
return false;
|
||||
}
|
||||
if ((lhsSection.textFont && (!rhsSection.textFont || **lhsSection.textFont != **rhsSection.textFont)) ||
|
||||
if ((lhsSection.textFont && (!rhsSection.textFont || *lhsSection.textFont != *rhsSection.textFont)) ||
|
||||
(!lhsSection.textFont && rhsSection.textFont)) {
|
||||
return false;
|
||||
}
|
||||
if ((lhsSection.textColor && (!rhsSection.textColor || **lhsSection.textColor != **rhsSection.textColor)) ||
|
||||
if ((lhsSection.textColor && (!rhsSection.textColor || *lhsSection.textColor != *rhsSection.textColor)) ||
|
||||
(!lhsSection.textColor && rhsSection.textColor)) {
|
||||
return false;
|
||||
}
|
||||
@@ -147,13 +146,13 @@ mbgl::Value FormatExpression::serialize() const {
|
||||
serialized.push_back(section.content->serialize());
|
||||
std::unordered_map<std::string, mbgl::Value> options;
|
||||
if (section.fontScale) {
|
||||
options.emplace(kFormattedSectionFontScale, (*section.fontScale)->serialize());
|
||||
options.emplace(kFormattedSectionFontScale, section.fontScale->serialize());
|
||||
}
|
||||
if (section.textFont) {
|
||||
options.emplace(kFormattedSectionTextFont, (*section.textFont)->serialize());
|
||||
options.emplace(kFormattedSectionTextFont, section.textFont->serialize());
|
||||
}
|
||||
if (section.textColor) {
|
||||
options.emplace(kFormattedSectionTextColor, (*section.textColor)->serialize());
|
||||
options.emplace(kFormattedSectionTextColor, section.textColor->serialize());
|
||||
}
|
||||
serialized.emplace_back(options);
|
||||
}
|
||||
@@ -188,7 +187,7 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con
|
||||
|
||||
std::optional<double> evaluatedFontScale;
|
||||
if (section.fontScale) {
|
||||
auto fontScaleResult = (*section.fontScale)->evaluate(params);
|
||||
auto fontScaleResult = section.fontScale->evaluate(params);
|
||||
if (!fontScaleResult) {
|
||||
return fontScaleResult.error();
|
||||
}
|
||||
@@ -197,7 +196,7 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con
|
||||
|
||||
std::optional<FontStack> evaluatedTextFont;
|
||||
if (section.textFont) {
|
||||
auto textFontResult = (*section.textFont)->evaluate(params);
|
||||
auto textFontResult = section.textFont->evaluate(params);
|
||||
if (!textFontResult) {
|
||||
return textFontResult.error();
|
||||
}
|
||||
@@ -212,7 +211,7 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con
|
||||
|
||||
std::optional<Color> evaluatedTextColor;
|
||||
if (section.textColor) {
|
||||
auto textColorResult = (*section.textColor)->evaluate(params);
|
||||
auto textColorResult = section.textColor->evaluate(params);
|
||||
if (!textColorResult) {
|
||||
return textColorResult.error();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace style {
|
||||
namespace expression {
|
||||
|
||||
ImageExpression::ImageExpression(std::unique_ptr<Expression> imageID_)
|
||||
: Expression(Kind::ImageExpression, type::Image),
|
||||
: Expression(Kind::ImageExpression, type::Image, depsOf(imageID_) | Dependency::Image),
|
||||
imageID(std::move(imageID_)) {
|
||||
assert(imageID);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ bool isSearchableRuntimeType(const type::Type& type) {
|
||||
} // namespace
|
||||
|
||||
In::In(std::unique_ptr<Expression> needle_, std::unique_ptr<Expression> haystack_)
|
||||
: Expression(Kind::In, type::Boolean),
|
||||
: Expression(Kind::In, type::Boolean, depsOf(needle_) | depsOf(haystack_)),
|
||||
needle(std::move(needle_)),
|
||||
haystack(std::move(haystack_)) {
|
||||
assert(isComparableType(needle->getType()));
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace expression {
|
||||
IndexOf::IndexOf(std::unique_ptr<Expression> keyword_,
|
||||
std::unique_ptr<Expression> input_,
|
||||
std::unique_ptr<Expression> fromIndex_)
|
||||
: Expression(Kind::IndexOf, type::Number),
|
||||
: Expression(Kind::IndexOf, type::Number, depsOf(keyword_) | depsOf(input_) | depsOf(fromIndex_)),
|
||||
keyword(std::move(keyword_)),
|
||||
input(std::move(input_)),
|
||||
fromIndex(std::move(fromIndex_)) {}
|
||||
|
||||
@@ -250,7 +250,7 @@ Interpolate::Interpolate(const type::Type& type_,
|
||||
Interpolator interpolator_,
|
||||
std::unique_ptr<Expression> input_,
|
||||
std::map<double, std::unique_ptr<Expression>> stops_)
|
||||
: Expression(Kind::Interpolate, type_),
|
||||
: Expression(Kind::Interpolate, type_, depsOf(input_) | collectDependencies(stops_)),
|
||||
interpolator(std::move(interpolator_)),
|
||||
input(std::move(input_)),
|
||||
stops(std::move(stops_)) {
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace style {
|
||||
namespace expression {
|
||||
|
||||
Length::Length(std::unique_ptr<Expression> input_)
|
||||
: Expression(Kind::Length, type::Number),
|
||||
: Expression(Kind::Length, type::Number, depsOf(input_)),
|
||||
input(std::move(input_)) {}
|
||||
|
||||
EvaluationResult Length::evaluate(const EvaluationContext& params) const {
|
||||
|
||||
@@ -16,7 +16,10 @@ NumberFormat::NumberFormat(std::unique_ptr<Expression> number_,
|
||||
std::unique_ptr<Expression> currency_,
|
||||
std::unique_ptr<Expression> minFractionDigits_,
|
||||
std::unique_ptr<Expression> maxFractionDigits_)
|
||||
: Expression(Kind::NumberFormat, type::String),
|
||||
: Expression(Kind::NumberFormat,
|
||||
type::String,
|
||||
depsOf(number_) | depsOf(locale_) | depsOf(currency_) | depsOf(minFractionDigits_) |
|
||||
depsOf(maxFractionDigits_)),
|
||||
number(std::move(number_)),
|
||||
locale(std::move(locale_)),
|
||||
currency(std::move(currency_)),
|
||||
|
||||
@@ -22,7 +22,7 @@ int normalizeIndex(int index, int length) {
|
||||
Slice::Slice(std::unique_ptr<Expression> input_,
|
||||
std::unique_ptr<Expression> fromIndex_,
|
||||
std::unique_ptr<Expression> toIndex_)
|
||||
: Expression(Kind::Slice, input_->getType()),
|
||||
: Expression(Kind::Slice, input_->getType(), depsOf(input_) | depsOf(fromIndex_) | depsOf(toIndex_)),
|
||||
input(std::move(input_)),
|
||||
fromIndex(std::move(fromIndex_)),
|
||||
toIndex(std::move(toIndex_)) {}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace expression {
|
||||
Step::Step(const type::Type& type_,
|
||||
std::unique_ptr<Expression> input_,
|
||||
std::map<double, std::unique_ptr<Expression>> stops_)
|
||||
: Expression(Kind::Step, type_),
|
||||
: Expression(Kind::Step, type_, depsOf(input_) | collectDependencies(stops_)),
|
||||
input(std::move(input_)),
|
||||
stops(std::move(stops_)) {
|
||||
assert(input->getType() == type::Number);
|
||||
|
||||
@@ -206,7 +206,7 @@ namespace style {
|
||||
namespace expression {
|
||||
|
||||
Within::Within(GeoJSON geojson, Feature::geometry_type geometries_)
|
||||
: Expression(Kind::Within, type::Boolean),
|
||||
: Expression(Kind::Within, type::Boolean, Dependency::Feature),
|
||||
geoJSONSource(std::move(geojson)),
|
||||
geometries(std::move(geometries_)) {}
|
||||
|
||||
|
||||
@@ -223,5 +223,10 @@ const LayerTypeInfo* Layer::getTypeInfo() const noexcept {
|
||||
return baseImpl->getTypeInfo();
|
||||
}
|
||||
|
||||
/// Collect dependencies
|
||||
expression::Dependency Layer::getDependencies() const noexcept {
|
||||
return baseImpl->getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -48,6 +48,9 @@ public:
|
||||
// Populates the given \a fontStack with fonts being used by the layer.
|
||||
virtual void populateFontStack(std::set<FontStack>& fontStack) const;
|
||||
|
||||
/// Collect the style dependencies for this layer
|
||||
virtual expression::Dependency getDependencies() const noexcept { return expression::Dependency::None; }
|
||||
|
||||
std::string id;
|
||||
std::string source;
|
||||
std::string sourceLayer;
|
||||
|
||||
@@ -31,6 +31,10 @@ const BackgroundLayer::Impl& BackgroundLayerProperties::layerImpl() const {
|
||||
return static_cast<const BackgroundLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency BackgroundLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const BackgroundLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
CrossfadeParameters crossfade;
|
||||
|
||||
@@ -29,6 +29,10 @@ const CircleLayer::Impl& CircleLayerProperties::layerImpl() const {
|
||||
return static_cast<const CircleLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency CircleLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -93,6 +93,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const CircleLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
CirclePaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -28,6 +28,8 @@ class CustomDrawableLayerProperties final : public LayerProperties {
|
||||
public:
|
||||
explicit CustomDrawableLayerProperties(Immutable<CustomDrawableLayer::Impl> impl)
|
||||
: LayerProperties(std::move(impl)) {}
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override { return expression::Dependency::None; }
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -28,6 +28,8 @@ class CustomLayerProperties final : public LayerProperties {
|
||||
public:
|
||||
explicit CustomLayerProperties(Immutable<CustomLayer::Impl> impl)
|
||||
: LayerProperties(std::move(impl)) {}
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override { return expression::Dependency::None; }
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -31,6 +31,10 @@ const FillExtrusionLayer::Impl& FillExtrusionLayerProperties::layerImpl() const
|
||||
return static_cast<const FillExtrusionLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency FillExtrusionLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const FillExtrusionLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
CrossfadeParameters crossfade;
|
||||
|
||||
@@ -31,6 +31,10 @@ const FillLayer::Impl& FillLayerProperties::layerImpl() const {
|
||||
return static_cast<const FillLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency FillLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const FillLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
CrossfadeParameters crossfade;
|
||||
|
||||
@@ -29,6 +29,10 @@ const HeatmapLayer::Impl& HeatmapLayerProperties::layerImpl() const {
|
||||
return static_cast<const HeatmapLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency HeatmapLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const HeatmapLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
HeatmapPaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -29,6 +29,10 @@ const HillshadeLayer::Impl& HillshadeLayerProperties::layerImpl() const {
|
||||
return static_cast<const HillshadeLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency HillshadeLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const HillshadeLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
HillshadePaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -40,6 +40,10 @@ const <%- camelize(type) %>Layer::Impl& <%- camelize(type) %>LayerProperties::la
|
||||
return static_cast<const <%- camelize(type) %>Layer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency <%- camelize(type) %>LayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies()<% if (layoutProperties.length) { -%> | layerImpl().layout.getDependencies()<% } -%>;
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const <%- camelize(type) %>Layer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
<% if (type === 'background' || type === 'fill' || type === 'line' || type === 'fill-extrusion') { -%>
|
||||
|
||||
@@ -14,6 +14,10 @@ public:
|
||||
bool hasLayoutDifference(const Layer::Impl&) const override;
|
||||
void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override {
|
||||
return layout.getDependencies() | paint.getDependencies();
|
||||
}
|
||||
|
||||
LineLayoutProperties::Unevaluated layout;
|
||||
LinePaintProperties::Transitionable paint;
|
||||
|
||||
|
||||
@@ -31,6 +31,10 @@ const LineLayer::Impl& LineLayerProperties::layerImpl() const {
|
||||
return static_cast<const LineLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency LineLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const LineLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
CrossfadeParameters crossfade;
|
||||
|
||||
@@ -29,6 +29,10 @@ const LocationIndicatorLayer::Impl& LocationIndicatorLayerProperties::layerImpl(
|
||||
return static_cast<const LocationIndicatorLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency LocationIndicatorLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const LocationIndicatorLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
LocationIndicatorPaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -29,6 +29,10 @@ const RasterLayer::Impl& RasterLayerProperties::layerImpl() const {
|
||||
return static_cast<const RasterLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency RasterLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const RasterLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
RasterPaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -29,6 +29,10 @@ const SymbolLayer::Impl& SymbolLayerProperties::layerImpl() const {
|
||||
return static_cast<const SymbolLayer::Impl&>(*baseImpl);
|
||||
}
|
||||
|
||||
expression::Dependency SymbolLayerProperties::getDependencies() const noexcept {
|
||||
return layerImpl().paint.getDependencies() | layerImpl().layout.getDependencies();
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -351,6 +351,8 @@ public:
|
||||
|
||||
unsigned long constantsMask() const override;
|
||||
|
||||
expression::Dependency getDependencies() const noexcept override;
|
||||
|
||||
const SymbolLayer::Impl& layerImpl() const;
|
||||
// Data members.
|
||||
SymbolPaintProperties::PossiblyEvaluated evaluated;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
#include <mbgl/style/conversion/stringify.hpp>
|
||||
#include <mbgl/renderer/transition_parameters.hpp>
|
||||
#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
|
||||
#include <mbgl/renderer/property_evaluation_parameters.hpp>
|
||||
#include <mbgl/renderer/transition_parameters.hpp>
|
||||
#include <mbgl/style/color_ramp_property_value.hpp>
|
||||
#include <mbgl/style/conversion/stringify.hpp>
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
#include <mbgl/util/indexed_tuple.hpp>
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
|
||||
@@ -133,6 +134,8 @@ public:
|
||||
using DataDrivenProperties = FilteredTypeList<PropertyTypes, IsDataDriven>;
|
||||
using OverridableProperties = FilteredTypeList<PropertyTypes, IsOverridable>;
|
||||
|
||||
using Dependency = expression::Dependency;
|
||||
|
||||
template <class TypeList>
|
||||
using Tuple = IndexedTuple<PropertyTypes, TypeList>;
|
||||
|
||||
@@ -245,6 +248,26 @@ public:
|
||||
return Evaluated{evaluate<Ps>(z, feature)...};
|
||||
}
|
||||
|
||||
/// Extract dependencies from a possibly-evaluated property which may have an expression.
|
||||
template <class P>
|
||||
Dependency getDependencies(const P&) const noexcept {
|
||||
return Dependency::None;
|
||||
}
|
||||
template <class P>
|
||||
Dependency getDependencies(const PossiblyEvaluatedPropertyValue<P>& v) const noexcept {
|
||||
return v.getDependencies();
|
||||
}
|
||||
template <class P>
|
||||
Dependency getDependencies(const PossiblyEvaluatedPropertyValue<Faded<P>>& v) const noexcept {
|
||||
return v.getDependencies();
|
||||
}
|
||||
|
||||
Dependency getDependencies() const noexcept {
|
||||
Dependency result = Dependency::None;
|
||||
util::ignore({(result |= getDependencies(this->template get<Ps>()))...});
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long constantsMask() const { return ConstantsMask<DataDrivenProperties>::getMask(*this); }
|
||||
};
|
||||
|
||||
@@ -276,6 +299,26 @@ public:
|
||||
util::ignore({(conversion::stringify<Ps>(writer, this->template get<Ps>()), 0)...});
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
/// Get the combined dependencies of any contained expressions
|
||||
constexpr Dependency getDependencies() const noexcept {
|
||||
Dependency result = Dependency::None;
|
||||
util::ignore({(result |= getDependencies(this->template get<Ps>()))...});
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned long constantsMask() const { return ConstantsMask<DataDrivenProperties>::getMask(*this); }
|
||||
|
||||
protected:
|
||||
template <class P>
|
||||
Dependency getDependencies(const PropertyValue<P>& v) const noexcept {
|
||||
return v.getDependencies();
|
||||
}
|
||||
|
||||
template <class P>
|
||||
Dependency getDependencies(const Transitioning<P>& v) const noexcept {
|
||||
return v.getValue().getDependencies();
|
||||
}
|
||||
};
|
||||
|
||||
class Transitionable : public Tuple<TransitionableTypes> {
|
||||
@@ -298,6 +341,24 @@ public:
|
||||
other.template get<Ps>().value))...});
|
||||
return result;
|
||||
}
|
||||
|
||||
Dependency getDependencies() const noexcept {
|
||||
Dependency result = Dependency::None;
|
||||
util::ignore({(result |= getDependencies(this->template get<Ps>()))...});
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename P>
|
||||
Dependency getDependencies(const style::Transitionable<PropertyValue<P>>& v) const noexcept {
|
||||
return v.value.getDependencies();
|
||||
}
|
||||
Dependency getDependencies(const style::ColorRampPropertyValue& v) const noexcept {
|
||||
return v.getDependencies();
|
||||
}
|
||||
Dependency getDependencies(const style::Transitionable<ColorRampPropertyValue>& v) const noexcept {
|
||||
return v.value.getDependencies();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -5,23 +5,10 @@ namespace style {
|
||||
|
||||
PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr<expression::Expression> expression_)
|
||||
: expression(std::move(expression_)),
|
||||
zoomCurve(expression::findZoomCurveChecked(expression.get())) {
|
||||
isZoomConstant_ = expression::isZoomConstant(*expression);
|
||||
isFeatureConstant_ = expression::isFeatureConstant(*expression);
|
||||
isRuntimeConstant_ = expression::isRuntimeConstant(*expression);
|
||||
}
|
||||
|
||||
bool PropertyExpressionBase::isZoomConstant() const noexcept {
|
||||
return isZoomConstant_;
|
||||
}
|
||||
|
||||
bool PropertyExpressionBase::isFeatureConstant() const noexcept {
|
||||
return isFeatureConstant_;
|
||||
}
|
||||
|
||||
bool PropertyExpressionBase::isRuntimeConstant() const noexcept {
|
||||
return isRuntimeConstant_;
|
||||
}
|
||||
isZoomConstant_(expression::isZoomConstant(*expression)),
|
||||
isFeatureConstant_(expression::isFeatureConstant(*expression)),
|
||||
isRuntimeConstant_(expression::isRuntimeConstant(*expression)),
|
||||
zoomCurve(isZoomConstant_ ? nullptr : expression::findZoomCurveChecked(*expression)) {}
|
||||
|
||||
float PropertyExpressionBase::interpolationFactor(const Range<float>& inputLevels,
|
||||
const float inputValue) const noexcept {
|
||||
|
||||
@@ -51,6 +51,7 @@ add_library(
|
||||
${PROJECT_SOURCE_DIR}/test/style/conversion/property_value.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/conversion/stringify.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/conversion/tileset.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/expression/dependency.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/expression/expression.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/expression/util.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/style/filter.test.cpp
|
||||
|
||||
1
test/fixtures/expression_equality/collator1.a.json
vendored
Normal file
1
test/fixtures/expression_equality/collator1.a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator1.b.json
vendored
Normal file
1
test/fixtures/expression_equality/collator1.b.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": false, "diacritic-sensitive": true, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator2.a.json
vendored
Normal file
1
test/fixtures/expression_equality/collator2.a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator2.b.json
vendored
Normal file
1
test/fixtures/expression_equality/collator2.b.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": false, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator3.a.json
vendored
Normal file
1
test/fixtures/expression_equality/collator3.a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator3.b.json
vendored
Normal file
1
test/fixtures/expression_equality/collator3.b.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true, "locale": "en"} ]
|
||||
1
test/fixtures/expression_equality/collator4.a.json
vendored
Normal file
1
test/fixtures/expression_equality/collator4.a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true} ]
|
||||
1
test/fixtures/expression_equality/collator4.b.json
vendored
Normal file
1
test/fixtures/expression_equality/collator4.b.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": false, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator5.a.json
vendored
Normal file
1
test/fixtures/expression_equality/collator5.a.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": true, "locale": "de"} ]
|
||||
1
test/fixtures/expression_equality/collator5.b.json
vendored
Normal file
1
test/fixtures/expression_equality/collator5.b.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ "collator", {"case-sensitive": true, "diacritic-sensitive": false} ]
|
||||
@@ -4,7 +4,7 @@
|
||||
[1, "WARNING", "ParseStyle", "Expected color but found number instead."],
|
||||
[1, "WARNING", "ParseStyle", "Expected arguments of type (number, number, number, number), but found (number, string, number, number) instead."],
|
||||
[1, "WARNING", "ParseStyle", "\"zoom\" expression may only be used as input to a top-level \"step\" or \"interpolate\" expression."],
|
||||
[1, "WARNING", "ParseStyle", "value must be a string"],
|
||||
[3, "WARNING", "ParseStyle", "value must be a string"],
|
||||
[1, "WARNING", "ParseStyle", "data expressions not supported"],
|
||||
[1, "WARNING", "ParseStyle", "Type array<number> is not interpolatable."]
|
||||
]
|
||||
|
||||
@@ -52,6 +52,24 @@
|
||||
"visibility": ["literal", true]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invalid value - must be a string",
|
||||
"type": "fill",
|
||||
"source": "source",
|
||||
"source-layer": 42069,
|
||||
"layout": {
|
||||
"visibility": "visible"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invalid value - must be a string (enum)",
|
||||
"type": "fill",
|
||||
"source": "source",
|
||||
"source-layer": "layer",
|
||||
"layout": {
|
||||
"visibility": [42069, true]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "invalid expression - not a DDS property",
|
||||
"type": "fill-extrusion",
|
||||
|
||||
@@ -72,9 +72,14 @@ size_t FixtureLog::uncheckedCount() const {
|
||||
return observer ? observer->uncheckedCount() : 0;
|
||||
}
|
||||
|
||||
std::vector<FixtureLog::Message> FixtureLog::unchecked() const {
|
||||
return observer ? observer->unchecked() : std::vector<FixtureLog::Message>{};
|
||||
}
|
||||
|
||||
FixtureLog::~FixtureLog() {
|
||||
if (observer) {
|
||||
Log::removeObserver();
|
||||
Log::removeObserver(); // destroys `observer`
|
||||
observer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
bool empty() const;
|
||||
size_t uncheckedCount() const;
|
||||
size_t count(const Message& message, bool substring = false) const;
|
||||
std::vector<Message> unchecked() const;
|
||||
|
||||
~FixtureLog();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/style/conversion/constant.hpp>
|
||||
#include <mbgl/style/conversion/property_value.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
@@ -52,33 +53,37 @@ TEST(StyleConversion, Function) {
|
||||
ASSERT_EQ("function base must be a number", error.message);
|
||||
}
|
||||
|
||||
TEST(StyleConversion, CompositeFunctionExpression) {
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void parseCheck(const std::string& json, std::string expectedError = {}) {
|
||||
using namespace std::string_literals;
|
||||
SCOPED_TRACE("Expression: "s + json);
|
||||
|
||||
Error error;
|
||||
const auto expr = convertJSON<PropertyValue<T>>(json, error, true, false);
|
||||
if (expectedError.empty()) {
|
||||
ASSERT_TRUE(expr);
|
||||
} else {
|
||||
ASSERT_FALSE(expr);
|
||||
ASSERT_EQ(expectedError, error.message);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
auto parseFunction = [&](const std::string& json) {
|
||||
return convertJSON<PropertyValue<float>>(json, error, true, false);
|
||||
};
|
||||
|
||||
auto fn1 = parseFunction(R"(["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10])");
|
||||
ASSERT_TRUE(fn1);
|
||||
|
||||
auto fn2 = parseFunction(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10], 0])");
|
||||
ASSERT_TRUE(fn2);
|
||||
|
||||
auto fn3 = parseFunction(
|
||||
TEST(StyleConversion, CompositeFunctionExpression) {
|
||||
parseCheck<float>(R"(["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10])");
|
||||
parseCheck<float>(R"(["coalesce", ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10], 0])");
|
||||
parseCheck<float>(
|
||||
R"(["let", "a", 0, ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10] ])");
|
||||
ASSERT_TRUE(fn3);
|
||||
|
||||
auto fn4 = parseFunction(
|
||||
parseCheck<float>(
|
||||
R"(["coalesce", ["let", "a", 0, ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10]], 0])");
|
||||
ASSERT_TRUE(fn4);
|
||||
|
||||
auto fn5 = parseFunction(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["number", ["get", "x"]], 0, ["zoom"], 10, 10], 0])");
|
||||
ASSERT_FALSE(fn5);
|
||||
ASSERT_EQ(R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)",
|
||||
error.message);
|
||||
parseCheck<float>(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["number", ["get", "x"]], 0, ["zoom"], 10, 10], 0])",
|
||||
R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)");
|
||||
parseCheck<float>(R"(["number", ["get", "x", ["literal", {"x": 0}]]])");
|
||||
parseCheck<bool>(R"(["has", "x", ["literal", {"x": 0}]])");
|
||||
parseCheck<bool>(R"(["has", "x", ["properties"]])");
|
||||
}
|
||||
|
||||
TEST(StyleConversion, TokenStrings) {
|
||||
|
||||
79
test/style/expression/dependency.test.cpp
Normal file
79
test/style/expression/dependency.test.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/expression/format_section_override.hpp>
|
||||
#include <mbgl/style/layers/custom_layer_impl.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::expression;
|
||||
using namespace mbgl::style::expression::dsl;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace std {
|
||||
using ::mbgl::operator<<;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto createOverride(expression::type::Type exprType,
|
||||
PossiblyEvaluatedPropertyValue<T> propValue,
|
||||
std::string propName) {
|
||||
return std::make_unique<FormatSectionOverride<T>>(std::move(exprType), std::move(propValue), std::move(propName));
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Get) {
|
||||
EXPECT_EQ(Dependency::Feature, number(get("property"))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Id) {
|
||||
EXPECT_EQ(Dependency::Feature, id()->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Zoom) {
|
||||
EXPECT_EQ(Dependency::Zoom, zoom()->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Convert) {
|
||||
EXPECT_EQ(Dependency::Feature, toColor(string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, toString(number(string(get("color"))))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, boolean(string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, toFormatted(toColor(string(get("color"))))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature | Dependency::Image, toImage(string(get("color")))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Compare) {
|
||||
EXPECT_EQ(Dependency::Feature, eq(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, lt(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, gt(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, eq(string(get("color")), string(get("color")))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Interpolate) {
|
||||
EXPECT_EQ(Dependency::Feature, step(number(id()), literal(0.0), 0.0, literal(0.0))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, step(literal(0.0), number(id()), 0.0, literal(0.0))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, step(literal(0.0), literal(0.0), 0.0, number(id()))->dependencies);
|
||||
|
||||
interpolate(linear(), number(id()), 0.0, literal(0.0), 0.0, literal(0.0), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, number(id()), 0.0, literal(0.0), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, literal(0.0), 0.0, number(id()), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, literal(0.0), 0.0, literal(0.0), 0.0, number(id()));
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Image) {
|
||||
EXPECT_EQ(Dependency::Image, image(literal("airport-11"))->dependencies);
|
||||
EXPECT_EQ(Dependency::Image | Dependency::Feature, image(get(literal("image_name"s)))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Distance) {
|
||||
const std::string pointGeoSource = R"({
|
||||
"type": "Point",
|
||||
"coordinates":[24.938492774963375,60.16980226227959]})";
|
||||
const auto exprStr = R"(["distance", )" + pointGeoSource + R"( ])";
|
||||
const auto expression = createExpression(exprStr.c_str());
|
||||
EXPECT_EQ(Dependency::Feature, expression->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, CustomLayer) {
|
||||
auto impl = makeMutable<CustomLayer::Impl>("", nullptr);
|
||||
EXPECT_EQ(Dependency::None, CustomLayerProperties{std::move(impl)}.getDependencies());
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/expression/is_expression.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/expression/is_expression.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
@@ -81,6 +82,10 @@ TEST_P(ExpressionEqualityTest, ExpressionEquality) {
|
||||
|
||||
EXPECT_TRUE(*expression_a1 == *expression_a2);
|
||||
EXPECT_TRUE(*expression_a1 != *expression_b);
|
||||
|
||||
// Exercise the type-not-equal branches
|
||||
using namespace expression;
|
||||
EXPECT_FALSE(*expression_b == *((expression_b->getKind() == Kind::Literal) ? dsl::id() : dsl::literal(0.0)));
|
||||
}
|
||||
|
||||
static void populateNames(std::vector<std::string>& names) {
|
||||
@@ -127,6 +132,7 @@ static void populateNames(std::vector<std::string>& names) {
|
||||
INSTANTIATE_TEST_SUITE_P(Expression, ExpressionEqualityTest, ::testing::ValuesIn([] {
|
||||
std::vector<std::string> names;
|
||||
populateNames(names);
|
||||
std::sort(names.begin(), names.end());
|
||||
EXPECT_GT(names.size(), 0u);
|
||||
return names;
|
||||
}()));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user