diff options
author | Fabian Guerra <fabian.guerra@mapbox.com> | 2018-05-17 11:47:31 -0400 |
---|---|---|
committer | Fabian Guerra <fabian.guerra@mapbox.com> | 2018-05-17 11:47:31 -0400 |
commit | 30376f3ce1d17522d9e64901b1bbc52906ee5267 (patch) | |
tree | 1f00d04a223a76a86e16ddebc77f56d2cff88b5b /src/mbgl/style | |
parent | 7d1e52a3255d4eecdcd37e4fb600eb76fa9333f8 (diff) | |
parent | 146057adf90e85e3edc80446f02d20e5f6cab378 (diff) | |
download | qtlocation-mapboxgl-30376f3ce1d17522d9e64901b1bbc52906ee5267.tar.gz |
Merge branch 'release-boba' into masterupstream/fabian-merge-release-4.0.1-master
# Conflicts:
# mapbox-gl-js
# platform/android/CHANGELOG.md
# platform/android/MapboxGLAndroidSDK/gradle.properties
# platform/android/gradle/dependencies.gradle
# platform/darwin/src/MGLVectorTileSource.mm
# platform/darwin/src/MGLVectorTileSource_Private.h
# platform/ios/CHANGELOG.md
# src/mbgl/style/expression/compound_expression.cpp
Diffstat (limited to 'src/mbgl/style')
-rw-r--r-- | src/mbgl/style/conversion/filter.cpp | 343 | ||||
-rw-r--r-- | src/mbgl/style/conversion/stringify.hpp | 159 | ||||
-rw-r--r-- | src/mbgl/style/expression/compound_expression.cpp | 325 | ||||
-rw-r--r-- | src/mbgl/style/expression/literal.cpp | 8 | ||||
-rw-r--r-- | src/mbgl/style/filter.cpp | 12 | ||||
-rw-r--r-- | src/mbgl/style/filter_evaluator.cpp | 225 |
6 files changed, 433 insertions, 639 deletions
diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp index 3c941945fd..386d85e921 100644 --- a/src/mbgl/style/conversion/filter.cpp +++ b/src/mbgl/style/conversion/filter.cpp @@ -1,17 +1,39 @@ #include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/expression/literal.hpp> #include <mbgl/util/geometry.hpp> #include <mbgl/style/expression/expression.hpp> #include <mbgl/style/expression/type.hpp> -#include <mbgl/style/expression/parsing_context.hpp> +#include <mbgl/style/expression/compound_expression.hpp> +#include <mbgl/style/expression/boolean_operator.hpp> namespace mbgl { namespace style { namespace conversion { -using GeometryValue = mapbox::geometry::value; +using namespace mbgl::style::expression; + +static bool isExpression(const Convertible& filter); +std::unique_ptr<Expression> convertLegacyFilter(const Convertible& values, Error& error); + +optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { + if (isExpression(value)) { + ParsingContext parsingContext(type::Boolean); + ParseResult parseResult = parsingContext.parseExpression(value); + if (!parseResult) { + error = { parsingContext.getCombinedErrors() }; + return {}; + } else { + return { Filter(std::move(parseResult)) }; + } + } else { + std::unique_ptr<Expression> expression = convertLegacyFilter(value, error); + if (!expression) return {}; + return Filter(optional<std::unique_ptr<Expression>>(std::move(expression))); + } +} // This is a port from https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/feature_filter/index.js -static bool isExpressionFilter(const Convertible& filter) { +bool isExpression(const Convertible& filter) { if (!isArray(filter) || arrayLength(filter) == 0) { return false; } @@ -20,7 +42,7 @@ static bool isExpressionFilter(const Convertible& filter) { if (!op) { return false; - + } else if (*op == "has") { if (arrayLength(filter) < 2) return false; optional<std::string> operand = toString(arrayMember(filter, 1)); @@ -35,7 +57,7 @@ static bool isExpressionFilter(const Convertible& filter) { } else if (*op == "any" || *op == "all") { for (std::size_t i = 1; i < arrayLength(filter); i++) { Convertible f = arrayMember(filter, i); - if (!isExpressionFilter(f) && !toBool(f)) { + if (!isExpression(f) && !toBool(f)) { return false; } } @@ -46,257 +68,136 @@ static bool isExpressionFilter(const Convertible& filter) { } } -static optional<GeometryValue> normalizeValue(const optional<GeometryValue>& value, Error& error) { - if (!value) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return *value; - } -} +std::unique_ptr<Expression> createExpression(std::string op, std::vector<std::unique_ptr<Expression>> args, Error& error) { + if (op == "any") { + return std::make_unique<Any>(std::move(args)); + + } else if (op == "all") { + return std::make_unique<All>(std::move(args)); -static optional<FeatureType> toFeatureType(const Convertible& value, Error& error) { - optional<std::string> type = toString(value); - if (!type) { - error = { "value for $type filter must be a string" }; - return {}; - } else if (*type == "Point") { - return FeatureType::Point; - } else if (*type == "LineString") { - return FeatureType::LineString; - } else if (*type == "Polygon") { - return FeatureType::Polygon; } else { - error = { "value for $type filter must be Point, LineString, or Polygon" }; - return {}; + ParsingContext parsingContext(type::Boolean); + ParseResult parseResult = createCompoundExpression(op, std::move(args), parsingContext); + if (!parseResult) { + error = { parsingContext.getCombinedErrors() }; + return {}; + } else { + return std::move(*parseResult); + } } } -static optional<FeatureIdentifier> toFeatureIdentifier(const Convertible& value, Error& error) { - optional<GeometryValue> identifier = toValue(value); - if (!identifier) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return (*identifier).match( - [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, - [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, - [&] (const auto&) -> optional<FeatureIdentifier> { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - }); - } +std::unique_ptr<Expression> createExpression(std::string op, std::unique_ptr<Expression> expression, Error& error) { + std::vector<std::unique_ptr<Expression>> args; + args.push_back(std::move(expression)); + return createExpression(op, std::move(args), error); } -template <class FilterType, class IdentifierFilterType> -optional<Filter> convertUnaryFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 2) { - error = { "filter expression must have 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$id") { - return { IdentifierFilterType {} }; +std::unique_ptr<Expression> convertLiteral(const Convertible& convertible, Error& error) { + ParsingContext parsingContext; + ParseResult parseResult = Literal::parse(convertible, parsingContext); + if (parseResult) { + return std::move(*parseResult); } else { - return { FilterType { *key } }; + error = { parsingContext.getCombinedErrors() }; + return {}; } } -template <class FilterType, class TypeFilterType, class IdentifierFilterType> -optional<Filter> convertEqualityFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; +std::vector<std::unique_ptr<Expression>> convertLiteralArray(const Convertible &input, Error& error, std::size_t startIndex = 0) { + std::vector<std::unique_ptr<Expression>> output; + for (std::size_t i = startIndex; i < arrayLength(input); i++) { + output.push_back(convertLiteral(arrayMember(input, i), error)); } + return output; +} - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; +std::unique_ptr<Expression> convertLegacyComparisonFilter(const Convertible& values, Error& error, optional<std::string> opOverride = {}) { + optional<std::string> op = opOverride ? opOverride : toString(arrayMember(values, 0)); + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; return {}; - } - - if (*key == "$type") { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { TypeFilterType { *filterValue } }; - - } else if (*key == "$id") { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { IdentifierFilterType { *filterValue } }; - + } else if (*property == "$type") { + return createExpression("filter-type-" + *op, convertLiteralArray(values, error, 2), error); + } else if (*property == "$id") { + return createExpression("filter-id-" + *op, convertLiteralArray(values, error, 2), error); } else { - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; + return createExpression("filter-" + *op, convertLiteralArray(values, error, 1), error); } } - -template <class FilterType> -optional<Filter> convertBinaryFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { + +std::unique_ptr<Expression> convertLegacyHasFilter(const Convertible& values, Error& error) { + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; return {}; + } else if (*property == "$type") { + return std::make_unique<Literal>(true); + } else if (*property == "$id") { + return createExpression("filter-has-id", std::vector<std::unique_ptr<Expression>>(), error); + } else { + return createExpression("filter-has", std::make_unique<Literal>(*property), error); } - - return { FilterType { *key, *filterValue } }; } -template <class FilterType, class TypeFilterType, class IdentifierFilterType> -optional<Filter> convertSetFilter(const Convertible& value, Error& error) { - if (arrayLength(value) < 2) { - error = { "filter expression must at least 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - std::vector<FeatureType> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { TypeFilterType { std::move(values) } }; - - } else if (*key == "$id") { - std::vector<FeatureIdentifier> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { IdentifierFilterType { std::move(values) } }; - +std::unique_ptr<Expression> convertLegacyInFilter(const Convertible& values, Error& error) { + optional<std::string> property = toString(arrayMember(values, 1)); + + if (!property) { + error = { "filter property must be a string" }; + return {}; + } else if (arrayLength(values) == 0) { + return std::make_unique<Literal>(false); + } else if (*property == "$type") { + return createExpression("filter-type-in", convertLiteralArray(values, error, 2), error); + } else if (*property == "$id") { + return createExpression("filter-id-in", convertLiteralArray(values, error, 2), error); } else { - std::vector<GeometryValue> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { FilterType { *key, std::move(values) } }; + return createExpression("filter-in", convertLiteralArray(values, error, 1), error); } } -template <class FilterType> -optional<Filter> convertCompoundFilter(const Convertible& value, Error& error) { - std::vector<Filter> filters; - for (std::size_t i = 1; i < arrayLength(value); ++i) { - optional<Filter> element = convert<Filter>(arrayMember(value, i), error); - if (!element) { - return {}; - } - filters.push_back(*element); +std::vector<std::unique_ptr<Expression>> convertLegacyFilterArray(const Convertible &input, Error& error, std::size_t startIndex = 0) { + std::vector<std::unique_ptr<Expression>> output; + for (std::size_t i = startIndex; i < arrayLength(input); i++) { + output.push_back(convertLegacyFilter(arrayMember(input, i), error)); } - - return { FilterType { std::move(filters) } }; + return output; } -optional<Filter> convertExpressionFilter(const Convertible& value, Error& error) { - expression::ParsingContext ctx(expression::type::Boolean); - expression::ParseResult expression = ctx.parseExpression(value); - if (!expression) { - error = { ctx.getCombinedErrors() }; - return {}; - } - - return { ExpressionFilter { std::move(*expression) } }; -} - -optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { - if (isExpressionFilter(value)) { - return convertExpressionFilter(value, error); +std::unique_ptr<Expression> convertLegacyFilter(const Convertible& values, Error& error) { + if (isUndefined(values)) { + return std::make_unique<Literal>(true); } - if (!isArray(value)) { - error = { "filter expression must be an array" }; - return {}; - } - - if (arrayLength(value) < 1) { - error = { "filter expression must have at least 1 element" }; - return {}; - } + optional<std::string> op = toString(arrayMember(values, 0)); - optional<std::string> op = toString(arrayMember(value, 0)); if (!op) { error = { "filter operator must be a string" }; return {}; + } else if (arrayLength(values) <= 1) { + return std::make_unique<Literal>(*op != "any"); + } else { + return ( + *op == "==" || + *op == "<" || + *op == ">" || + *op == "<=" || + *op == ">=" ? convertLegacyComparisonFilter(values, error) : + *op == "!=" ? createExpression("!", convertLegacyComparisonFilter(values, error, {"=="}), error) : + *op == "any" ? createExpression("any", convertLegacyFilterArray(values, error, 1), error) : + *op == "all" ? createExpression("all", convertLegacyFilterArray(values, error, 1), error) : + *op == "none" ? createExpression("!", createExpression("any", convertLegacyFilterArray(values, error, 1), error), error) : + *op == "in" ? convertLegacyInFilter(values, error) : + *op == "!in" ? createExpression("!", convertLegacyInFilter(values, error), error) : + *op == "has" ? convertLegacyHasFilter(values, error) : + *op == "!has" ? createExpression("!", convertLegacyHasFilter(values, error), error) : + std::make_unique<Literal>(true) + ); } - - if (*op == "==") { - return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); - } else if (*op == "!=") { - return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); - } else if (*op == ">") { - return convertBinaryFilter<GreaterThanFilter>(value, error); - } else if (*op == ">=") { - return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); - } else if (*op == "<") { - return convertBinaryFilter<LessThanFilter>(value, error); - } else if (*op == "<=") { - return convertBinaryFilter<LessThanEqualsFilter>(value, error); - } else if (*op == "in") { - return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); - } else if (*op == "!in") { - return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); - } else if (*op == "all") { - return convertCompoundFilter<AllFilter>(value, error); - } else if (*op == "any") { - return convertCompoundFilter<AnyFilter>(value, error); - } else if (*op == "none") { - return convertCompoundFilter<NoneFilter>(value, error); - } else if (*op == "has") { - return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); - } else if (*op == "!has") { - return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); - } - - error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; - return {}; } } // namespace conversion diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 7b7727d7c4..74171763a0 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -126,162 +126,9 @@ void stringify(Writer& writer, const FeatureIdentifier& id) { } template <class Writer> -class StringifyFilter { -public: - Writer& writer; - - void operator()(const NullFilter&) { - writer.Null(); - } - - void operator()(const EqualsFilter& f) { - stringifyBinaryFilter(f, "=="); - } - - void operator()(const NotEqualsFilter& f) { - stringifyBinaryFilter(f, "!="); - } - - void operator()(const LessThanFilter& f) { - stringifyBinaryFilter(f, "<"); - } - - void operator()(const LessThanEqualsFilter& f) { - stringifyBinaryFilter(f, "<="); - } - - void operator()(const GreaterThanFilter& f) { - stringifyBinaryFilter(f, ">"); - } - - void operator()(const GreaterThanEqualsFilter& f) { - stringifyBinaryFilter(f, ">="); - } - - void operator()(const InFilter& f) { - stringifySetFilter(f, "in"); - } - - void operator()(const NotInFilter& f) { - stringifySetFilter(f, "!in"); - } - - void operator()(const AllFilter& f) { - stringifyCompoundFilter(f, "all"); - } - - void operator()(const AnyFilter& f) { - stringifyCompoundFilter(f, "any"); - } - - void operator()(const NoneFilter& f) { - stringifyCompoundFilter(f, "none"); - } - - void operator()(const HasFilter& f) { - stringifyUnaryFilter("has", f.key); - } - - void operator()(const NotHasFilter& f) { - stringifyUnaryFilter("!has", f.key); - } - - void operator()(const TypeEqualsFilter& f) { - stringifyBinaryFilter(f, "==", "$type"); - } - - void operator()(const TypeNotEqualsFilter& f) { - stringifyBinaryFilter(f, "!=", "$type"); - } - - void operator()(const TypeInFilter& f) { - stringifySetFilter(f, "in", "$type"); - } - - void operator()(const TypeNotInFilter& f) { - stringifySetFilter(f, "!in", "$type"); - } - - void operator()(const IdentifierEqualsFilter& f) { - stringifyBinaryFilter(f, "==", "$id"); - } - - void operator()(const IdentifierNotEqualsFilter& f) { - stringifyBinaryFilter(f, "!=", "$id"); - } - - void operator()(const IdentifierInFilter& f) { - stringifySetFilter(f, "in", "$id"); - } - - void operator()(const IdentifierNotInFilter& f) { - stringifySetFilter(f, "!in", "$id"); - } - - void operator()(const HasIdentifierFilter&) { - stringifyUnaryFilter("has", "$id"); - } - - void operator()(const NotHasIdentifierFilter&) { - stringifyUnaryFilter("!has", "$id"); - } - - void operator()(const ExpressionFilter& filter) { - stringify(writer, filter.expression->serialize()); - } - -private: - template <class F> - void stringifyBinaryFilter(const F& f, const char * op) { - stringifyBinaryFilter(f, op, f.key); - } - - template <class F> - void stringifyBinaryFilter(const F& f, const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - stringify(writer, f.value); - writer.EndArray(); - } - - template <class F> - void stringifySetFilter(const F& f, const char * op) { - stringifySetFilter(f, op, f.key); - } - - template <class F> - void stringifySetFilter(const F& f, const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - for (const auto& value : f.values) { - stringify(writer, value); - } - writer.EndArray(); - } - - template <class F> - void stringifyCompoundFilter(const F& f, const char * op) { - writer.StartArray(); - writer.String(op); - for (const auto& filter : f.filters) { - Filter::visit(filter, *this); - } - writer.EndArray(); - } - - void stringifyUnaryFilter(const char * op, const std::string& key) { - writer.StartArray(); - writer.String(op); - writer.String(key); - writer.EndArray(); - } -}; - -template <class Writer> -void stringify(Writer& writer, const Filter& f) { - Filter::visit(f, StringifyFilter<Writer> { writer }); +void stringify(Writer& writer, const Filter& filter) { + if (!filter.expression) writer.Null(); + else stringify(writer, (*filter.expression)->serialize()); } template <class Writer> 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 diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 8a63980dba..f68cfd5cf5 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -109,6 +109,14 @@ mbgl::Value Literal::serialize() const { return *fromExpressionValue<mbgl::Value>(value); } } + +std::unique_ptr<Literal> createLiteral(const char* value) { + return createLiteral(std::string(value)); +} + +std::unique_ptr<Literal> createLiteral(Value value) { + return std::make_unique<Literal>(value); +} } // namespace expression } // namespace style diff --git a/src/mbgl/style/filter.cpp b/src/mbgl/style/filter.cpp index 51aa6bcf82..2559eb4816 100644 --- a/src/mbgl/style/filter.cpp +++ b/src/mbgl/style/filter.cpp @@ -1,12 +1,20 @@ #include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/tile/geometry_tile_data.hpp> namespace mbgl { namespace style { bool Filter::operator()(const expression::EvaluationContext &context) const { - return FilterBase::visit(*this, FilterEvaluator { context }); + + if (!this->expression) return true; + + const expression::EvaluationResult result = (*this->expression)->evaluate(context); + if (result) { + const optional<bool> typed = expression::fromExpressionValue<bool>(*result); + return typed ? *typed : false; + } else { + return true; + } } } // namespace style diff --git a/src/mbgl/style/filter_evaluator.cpp b/src/mbgl/style/filter_evaluator.cpp deleted file mode 100644 index 72022172f4..0000000000 --- a/src/mbgl/style/filter_evaluator.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> - -namespace mbgl { -namespace style { - -template <class Op> -struct Comparator { - const Op& op; - - template <class T> - bool operator()(const T& lhs, const T& rhs) const { - return op(lhs, rhs); - } - - template <class T0, class T1> - auto operator()(const T0& lhs, const T1& rhs) const - -> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value && - std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> { - return op(double(lhs), double(rhs)); - } - - template <class T0, class T1> - auto operator()(const T0&, const T1&) const - -> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value || - !std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> { - return false; - } - - bool operator()(const NullValue&, - const NullValue&) const { - // Should be unreachable; null is not currently allowed by the style specification. - assert(false); - return false; - } - - bool operator()(const std::vector<Value>&, - const std::vector<Value>&) const { - // Should be unreachable; nested values are not currently allowed by the style specification. - assert(false); - return false; - } - - bool operator()(const PropertyMap&, - const PropertyMap&) const { - // Should be unreachable; nested values are not currently allowed by the style specification. - assert(false); - return false; - } -}; - -template <class Op> -bool compare(const Value& lhs, const Value& rhs, const Op& op) { - return Value::binary_visit(lhs, rhs, Comparator<Op> { op }); -} - -bool equal(const Value& lhs, const Value& rhs) { - return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; }); -} - -bool FilterEvaluator::operator()(const NullFilter&) const { - return true; -} - -bool FilterEvaluator::operator()(const EqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && equal(*actual, filter.value); -} - -bool FilterEvaluator::operator()(const NotEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return !actual || !equal(*actual, filter.value); -} - -bool FilterEvaluator::operator()(const LessThanFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; }); -} - -bool FilterEvaluator::operator()(const LessThanEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; }); -} - -bool FilterEvaluator::operator()(const GreaterThanFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; }); -} - -bool FilterEvaluator::operator()(const GreaterThanEqualsFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; }); -} - -bool FilterEvaluator::operator()(const InFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - if (!actual) - return false; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const NotInFilter& filter) const { - optional<Value> actual = context.feature->getValue(filter.key); - if (!actual) - return true; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const AnyFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const AllFilter& filter) const { - for (const auto& f: filter.filters) { - if (!Filter::visit(f, *this)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const NoneFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const HasFilter& filter) const { - return bool(context.feature->getValue(filter.key)); -} - -bool FilterEvaluator::operator()(const NotHasFilter& filter) const { - return !context.feature->getValue(filter.key); -} - -bool FilterEvaluator::operator()(const TypeEqualsFilter& filter) const { - return context.feature->getType() == filter.value; -} - -bool FilterEvaluator::operator()(const TypeNotEqualsFilter& filter) const { - return context.feature->getType() != filter.value; -} - -bool FilterEvaluator::operator()(const TypeInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getType() == v) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const TypeNotInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getType() == v) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const IdentifierEqualsFilter& filter) const { - return context.feature->getID() == filter.value; -} - -bool FilterEvaluator::operator()(const IdentifierNotEqualsFilter& filter) const { - return context.feature->getID() != filter.value; -} - -bool FilterEvaluator::operator()(const IdentifierInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getID() == v) { - return true; - } - } - return false; -} - -bool FilterEvaluator::operator()(const IdentifierNotInFilter& filter) const { - for (const auto& v: filter.values) { - if (context.feature->getID() == v) { - return false; - } - } - return true; -} - -bool FilterEvaluator::operator()(const HasIdentifierFilter&) const { - return bool(context.feature->getID()); -} - -bool FilterEvaluator::operator()(const NotHasIdentifierFilter&) const { - return !context.feature->getID(); -} - -bool FilterEvaluator::operator()(const ExpressionFilter& filter) const { - const expression::EvaluationResult result = filter.expression->evaluate(context); - if (result) { - const optional<bool> typed = expression::fromExpressionValue<bool>(*result); - return typed ? *typed : false; - } - return false; -} - -} // namespace style -} // namespace mbgl |