summaryrefslogtreecommitdiff
path: root/src/mbgl/style/expression/compound_expression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/style/expression/compound_expression.cpp')
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp325
1 files changed, 290 insertions, 35 deletions
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index bcde09e1b6..4226756fe4 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -19,7 +19,7 @@ namespace detail {
The Signature<Fn> structs are wrappers around an "evaluate()" function whose
purpose is to extract the necessary Type data from the evaluate function's
type. There are three key (partial) specializations:
-
+
Signature<R (Params...)>:
Wraps a simple evaluate function (const T0&, const T1&, ...) -> Result<U>
@@ -30,9 +30,9 @@ namespace detail {
Signature<R (const EvaluationContext&, Params...)>:
Wraps an evaluate function that needs to access the expression evaluation
parameters in addition to its subexpressions, i.e.,
- (const EvaluationParams& const T0&, const T1&, ...) -> Result<U>. Needed
+ (const EvaluationParams&, const T0&, const T1&, ...) -> Result<U>. Needed
for expressions like ["zoom"], ["get", key], etc.
-
+
In each of the above evaluate signatures, T0, T1, etc. are the types of
the successfully evaluated subexpressions.
*/
@@ -43,7 +43,7 @@ struct Signature;
template <class R, class... Params>
struct Signature<R (Params...)> : SignatureBase {
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
-
+
Signature(R (*evaluate_)(Params...), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -55,7 +55,7 @@ struct Signature<R (Params...)> : SignatureBase {
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
typename Signature::Args argsArray;
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
@@ -80,7 +80,7 @@ private:
template <class R, typename T>
struct Signature<R (const Varargs<T>&)> : SignatureBase {
using Args = std::vector<std::unique_ptr<Expression>>;
-
+
Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -89,11 +89,11 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase {
),
evaluate(evaluate_)
{}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
};
-
+
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
Varargs<T> evaluated;
evaluated.reserve(args.size());
@@ -115,7 +115,7 @@ struct Signature<R (const Varargs<T>&)> : SignatureBase {
template <class R, class... Params>
struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>;
-
+
Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) :
SignatureBase(
valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
@@ -124,17 +124,17 @@ struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase {
),
evaluate(evaluate_)
{}
-
+
std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
typename Signature::Args argsArray;
std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin());
return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray));
}
-
+
EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{});
}
-
+
private:
template <std::size_t ...I>
EvaluationResult applyImpl(const EvaluationContext& evaluationParameters, const Args& args, std::index_sequence<I...>) const {
@@ -150,6 +150,41 @@ private:
R (*evaluate)(const EvaluationContext&, Params...);
};
+
+// Evaluate function needing EvaluationContext and Varargs
+// (const EvaluationContext&, const Varargs<T>&) -> Result<U>
+template <class R, typename T>
+struct Signature<R (const EvaluationContext&, const Varargs<T>&)> : SignatureBase {
+ using Args = std::vector<std::unique_ptr<Expression>>;
+
+ Signature(R (*evaluate_)(const EvaluationContext&, const Varargs<T>&), std::string name_) :
+ SignatureBase(
+ valueTypeToExpressionType<std::decay_t<typename R::Value>>(),
+ VarargsType { valueTypeToExpressionType<T>() },
+ std::move(name_)
+ ),
+ evaluate(evaluate_)
+ {}
+
+ std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override {
+ return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args));
+ };
+
+ EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const {
+ Varargs<T> evaluated;
+ evaluated.reserve(args.size());
+ for (const auto& arg : args) {
+ const EvaluationResult evaluatedArg = arg->evaluate(evaluationParameters);
+ if(!evaluatedArg) return evaluatedArg.error();
+ evaluated.push_back(*fromExpressionValue<std::decay_t<T>>(*evaluatedArg));
+ }
+ const R value = evaluate(evaluationParameters, evaluated);
+ if (!value) return value.error();
+ return *value;
+ }
+
+ R (*evaluate)(const EvaluationContext&, const Varargs<T>&);
+};
// Machinery to pull out function types from class methods, lambdas, etc.
template <class R, class... Params>
@@ -181,29 +216,104 @@ static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction,
return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name));
}
+Value featureIdAsExpressionValue(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return Null;
+ return id->match([](const auto& idid) {
+ return toExpressionValue(mbgl::Value(idid));
+ });
+};
+
+optional<Value> featurePropertyAsExpressionValue(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ return property ? toExpressionValue(*property) : optional<Value>();
+};
+
+optional<std::string> featureTypeAsString(FeatureType type) {
+ switch(type) {
+ case FeatureType::Point:
+ return optional<std::string>("Point");
+ case FeatureType::LineString:
+ return optional<std::string>("LineString");
+ case FeatureType::Polygon:
+ return optional<std::string>("Polygon");
+ case FeatureType::Unknown:
+ return optional<std::string>("Unknown");
+ default:
+ return {};
+ }
+};
+
+optional<double> featurePropertyAsDouble(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ if (!property) return {};
+ return property->match(
+ [](double value) { return value; },
+ [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](int64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](auto) { return optional<double>(); }
+ );
+};
+
+optional<std::string> featurePropertyAsString(EvaluationContext params, const std::string& key) {
+ assert(params.feature);
+ auto property = params.feature->getValue(key);
+ if (!property) return {};
+ return property->match(
+ [](std::string value) { return value; },
+ [](auto) { return optional<std::string>(); }
+ );
+};
+
+optional<double> featureIdAsDouble(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return optional<double>();
+ return id->match(
+ [](double value) { return value; },
+ [](uint64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](int64_t value) { return optional<double>(static_cast<double>(value)); },
+ [](auto) { return optional<double>(); }
+ );
+};
+
+optional<std::string> featureIdAsString(EvaluationContext params) {
+ assert(params.feature);
+ auto id = params.feature->getID();
+ if (!id) return optional<std::string>();
+ return id->match(
+ [](std::string value) { return value; },
+ [](auto) { return optional<std::string>(); }
+ );
+};
+
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() {
std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions;
auto define = [&](std::string name, auto fn) {
definitions[name].push_back(makeSignature(fn, name));
};
-
+
define("e", []() -> Result<double> { return 2.718281828459045; });
define("pi", []() -> Result<double> { return 3.141592653589793; });
define("ln2", []() -> Result<double> { return 0.6931471805599453; });
define("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); });
-
+
define("to-string", [](const Value& value) -> Result<std::string> {
return value.match(
+ [](const NullValue&) -> Result<std::string> { return std::string(); },
[](const Color& c) -> Result<std::string> { return c.stringify(); }, // avoid quoting
[](const std::string& s) -> Result<std::string> { return s; }, // avoid quoting
[](const auto& v) -> Result<std::string> { return stringify(v); }
);
});
-
+
define("to-boolean", [](const Value& v) -> Result<bool> {
return v.match(
- [&] (double f) { return (bool)f; },
+ [&] (double f) { return static_cast<bool>(f); },
[&] (const std::string& s) { return s.length() > 0; },
[&] (bool b) { return b; },
[&] (const NullValue&) { return false; },
@@ -213,10 +323,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> {
return color.toArray();
});
-
+
define("rgba", rgba);
define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); });
-
+
define("zoom", [](const EvaluationContext& params) -> Result<double> {
if (!params.zoom) {
return EvaluationError {
@@ -225,7 +335,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return *(params.zoom);
});
-
+
define("heatmap-density", [](const EvaluationContext& params) -> Result<double> {
if (!params.heatmapDensity) {
return EvaluationError {
@@ -241,7 +351,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
"Feature data is unavailable in the current evaluation context."
};
}
-
+
return params.feature->getValue(key) ? true : false;
});
define("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> {
@@ -267,7 +377,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return object.at(key);
});
-
+
define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> {
if (!params.feature) {
return EvaluationError {
@@ -281,14 +391,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return result;
});
-
+
define("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";
@@ -300,14 +410,14 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
return "Unknown";
}
});
-
+
define("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();
if (!id) {
return Null;
@@ -318,7 +428,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
);
});
-
+
define("+", [](const Varargs<double>& args) -> Result<double> {
double sum = 0.0f;
for (auto arg : args) {
@@ -348,7 +458,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("asin", [](double x) -> Result<double> { return asin(x); });
define("acos", [](double x) -> Result<double> { return acos(x); });
define("atan", [](double x) -> Result<double> { return atan(x); });
-
+
define("min", [](const Varargs<double>& args) -> Result<double> {
double result = std::numeric_limits<double>::infinity();
for (double arg : args) {
@@ -377,7 +487,7 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("<", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs < rhs; });
define("<=", [](double lhs, double rhs) -> Result<bool> { return lhs <= rhs; });
define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
-
+
define("!", [](bool e) -> Result<bool> { return !e; });
define("is-supported-script", [](const std::string& x) -> Result<bool> {
@@ -400,7 +510,130 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("error", [](const std::string& input) -> Result<type::ErrorType> {
return EvaluationError { input };
});
+
+ // Legacy Filters
+ define("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> {
+ const auto rhs = featurePropertyAsExpressionValue(params, key);
+ return rhs ? lhs == *rhs : false;
+ });
+
+ define("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> {
+ return lhs == featureIdAsExpressionValue(params);
+ });
+
+ define("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> {
+ if (!params.feature) return false;
+ return featureTypeAsString(params.feature->getType()) == lhs;
+ });
+
+ define("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs < lhs : false;
+ });
+
+ define("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs > lhs : false;
+ });
+
+ define("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs <= lhs : false;
+ });
+ define("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs <= lhs : false;
+ });
+
+ define("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsDouble(params, key);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> {
+ auto rhs = featurePropertyAsString(params, key);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> {
+ auto rhs = featureIdAsDouble(params);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> {
+ auto rhs = featureIdAsString(params);
+ return rhs ? rhs >= lhs : false;
+ });
+
+ define("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
+ assert(params.feature);
+ return bool(params.feature->getValue(key));
+ });
+
+ define("filter-has-id", [](const EvaluationContext& params) -> Result<bool> {
+ assert(params.feature);
+ return bool(params.feature->getID());
+ });
+
+ define("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> {
+ assert(params.feature);
+ optional<std::string> type = featureTypeAsString(params.feature->getType());
+ return std::find(types.begin(), types.end(), type) != types.end();
+ });
+
+ define("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();
+ });
+
+ define("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;
+ });
+
return definitions;
}
@@ -419,7 +652,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v
return ParseResult();
}
const CompoundExpressionRegistry::Definition& definition = it->second;
-
+
auto length = arrayLength(value);
// Check if we have a single signature with the correct number of
@@ -445,14 +678,14 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v
args.reserve(length - 1);
for (std::size_t i = 1; i < length; i++) {
optional<type::Type> expected;
-
+
if (singleMatchingSignature) {
expected = definition[*singleMatchingSignature]->params.match(
[](const VarargsType& varargs) { return varargs.type; },
[&](const std::vector<type::Type>& params_) { return params_[i - 1]; }
);
}
-
+
auto parsed = ctx.parse(arrayMember(value, i), i, expected);
if (!parsed) {
return parsed;
@@ -479,7 +712,7 @@ ParseResult createCompoundExpression(const Definition& definition,
for (const std::unique_ptr<detail::SignatureBase>& signature : definition) {
signatureContext.clearErrors();
-
+
if (signature->params.is<std::vector<type::Type>>()) {
const std::vector<type::Type>& params = signature->params.get<std::vector<type::Type>>();
if (params.size() != args.size()) {
@@ -507,12 +740,12 @@ ParseResult createCompoundExpression(const Definition& definition,
}
}
}
-
+
if (signatureContext.getErrors().size() == 0) {
return ParseResult(signature->makeExpression(std::move(args)));
}
}
-
+
if (definition.size() == 1) {
ctx.appendErrors(std::move(signatureContext));
} else {
@@ -545,10 +778,32 @@ ParseResult createCompoundExpression(const Definition& definition,
}
ctx.error("Expected arguments of type " + signatures + ", but found (" + actualTypes + ") instead.");
}
-
+
return ParseResult();
}
+ParseResult createCompoundExpression(const std::string& name, ParsingContext& ctx) {
+ return createCompoundExpression(name, std::vector<std::unique_ptr<Expression>>(), ctx);
+}
+
+ParseResult createCompoundExpression(const std::string& name,
+ std::unique_ptr<Expression> arg1,
+ ParsingContext& ctx) {
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(arg1));
+ return createCompoundExpression(name, std::move(args), ctx);
+}
+
+ParseResult createCompoundExpression(const std::string& name,
+ std::unique_ptr<Expression> arg1,
+ std::unique_ptr<Expression> arg2,
+ ParsingContext& ctx) {
+ std::vector<std::unique_ptr<Expression>> args;
+ args.push_back(std::move(arg1));
+ args.push_back(std::move(arg2));
+ return createCompoundExpression(name, std::move(args), ctx);
+}
+
} // namespace expression
} // namespace style
} // namespace mbgl