From 2e2bba8dc33665df952e80beb381741894a5331d Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 6 Feb 2020 16:39:50 +0800 Subject: [PATCH 1/8] Implement in.cpp --- include/mbgl/style/expression/expression.hpp | 1 + include/mbgl/style/expression/in.hpp | 43 +++++++ metrics/ignores/platform-all.json | 6 - src/mbgl/style/expression/in.cpp | 116 ++++++++++++++++++ src/mbgl/style/expression/parsing_context.cpp | 2 + test/style/expression/expression.test.cpp | 3 +- 6 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 include/mbgl/style/expression/in.hpp create mode 100644 src/mbgl/style/expression/in.cpp diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 0fd5c4959ea..e5228211858 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -168,6 +168,7 @@ enum class Kind : int32_t { FormatSectionOverride, NumberFormat, ImageExpression, + In, Within }; diff --git a/include/mbgl/style/expression/in.hpp b/include/mbgl/style/expression/in.hpp new file mode 100644 index 00000000000..ab8e2e9ff2a --- /dev/null +++ b/include/mbgl/style/expression/in.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +namespace mbgl { +namespace style { +namespace expression { + +class In : public Expression { +public: + In(std::unique_ptr needle_, std::unique_ptr haystack_) + : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) {} + + static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); + + EvaluationResult evaluate(const EvaluationContext& params) const override; + void eachChild(const std::function&) const override; + + bool operator==(const Expression& e) const override { + if (e.getKind() == Kind::In) { + auto rhs = static_cast(&e); + return *needle == *(rhs->needle) && *haystack == *(rhs->haystack); + } + return false; + } + + std::vector> possibleOutputs() const override { return {nullopt}; } + + std::string getOperator() const override { return "in"; } + +private: + std::unique_ptr needle; + std::unique_ptr haystack; + static bool isComparableType(type::Type type); + static bool isComparableRuntimeValue(type::Type type); + static bool isSearchableRuntimeValue(type::Type type); +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/metrics/ignores/platform-all.json b/metrics/ignores/platform-all.json index b53e923a9d9..9b1ad315e22 100644 --- a/metrics/ignores/platform-all.json +++ b/metrics/ignores/platform-all.json @@ -1,11 +1,5 @@ { "expression-tests/collator/accent-equals-de": "Locale-specific behavior changes based on platform.", - "expression-tests/in/assert-array": "https://github.com/mapbox/mapbox-gl-native/issues/15893", - "expression-tests/in/assert-string": "https://github.com/mapbox/mapbox-gl-native/issues/15893", - "expression-tests/in/basic-array": "https://github.com/mapbox/mapbox-gl-native/issues/15893", - "expression-tests/in/basic-string": "https://github.com/mapbox/mapbox-gl-native/issues/15893", - "expression-tests/in/invalid-haystack": "https://github.com/mapbox/mapbox-gl-native/issues/15893", - "expression-tests/in/invalid-needle": "https://github.com/mapbox/mapbox-gl-native/issues/15893", "expression-tests/interpolate-hcl/linear": "https://github.com/mapbox/mapbox-gl-native/issues/8720", "expression-tests/interpolate-lab/linear": "https://github.com/mapbox/mapbox-gl-native/issues/8720", "expression-tests/is-supported-script/default": "This tests RTL text plugin behavior specific to GL JS", diff --git a/src/mbgl/style/expression/in.cpp b/src/mbgl/style/expression/in.cpp new file mode 100644 index 00000000000..05336c7d922 --- /dev/null +++ b/src/mbgl/style/expression/in.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +namespace mbgl { +namespace style { +namespace expression { + +EvaluationResult In::evaluate(const EvaluationContext& params) const { + const EvaluationResult evaluatedNeedle = needle->evaluate(params); + const EvaluationResult evaluatedHeystack = haystack->evaluate(params); + + if (!evaluatedNeedle) { + return evaluatedNeedle.error(); + } + if (!evaluatedHeystack) { + return evaluatedHeystack.error(); + } + + type::Type evaluatedNeedleType = typeOf(*evaluatedNeedle); + if (!isComparableRuntimeValue(evaluatedNeedleType)) { + return EvaluationError{"Expected first argument to be of type boolean, string or number, but found " + + toString(evaluatedNeedleType) + " instead."}; + } + + type::Type evaluatedHeystackType = typeOf(*evaluatedHeystack); + if (!isSearchableRuntimeValue(evaluatedHeystackType)) { + return EvaluationError{"Expected second argument to be of type array or string, but found " + + toString(evaluatedHeystackType) + " instead."}; + } + + if (evaluatedNeedleType == type::Null || evaluatedHeystackType == type::Null) { + return EvaluationResult(false); + } + + if (evaluatedHeystackType == type::String) { + const auto heystackString = evaluatedHeystack->get(); + std::string needleValue = ""; + if (evaluatedNeedleType == type::Boolean) { + needleValue = evaluatedNeedle->get() ? "true" : " false"; + } else if (evaluatedNeedleType == type::String) { + needleValue = evaluatedNeedle->get(); + } else if (evaluatedNeedleType == type::Number) { + needleValue = std::to_string(evaluatedNeedle->get()); + needleValue.erase(needleValue.find_last_not_of('0') + 1, std::string::npos); + needleValue.erase(needleValue.find_last_not_of('.') + 1, std::string::npos); + } + return EvaluationResult(heystackString.find(needleValue) != std::string::npos); + } else { + const auto heystackArray = evaluatedHeystack->get>(); + + bool result = false; + if (evaluatedNeedleType == type::Boolean) { + auto needleValue = evaluatedNeedle->get(); + result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + } else if (evaluatedNeedleType == type::String) { + auto needleValue = evaluatedNeedle->get(); + result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + } else if (evaluatedNeedleType == type::Number) { + auto needleValue = evaluatedNeedle->get(); + result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + } + return EvaluationResult(result); + } +} + +void In::eachChild(const std::function& visit) const { + visit(*needle); + visit(*haystack); +} + +using namespace mbgl::style::conversion; +ParseResult In::parse(const Convertible& value, ParsingContext& ctx) { + assert(isArray(value)); + + std::size_t length = arrayLength(value); + if (length != 3) { + ctx.error("Expected 2 arguments, but found " + util::toString(length - 1) + " instead."); + return ParseResult(); + } + + ParseResult needle = ctx.parse(arrayMember(value, 1), 1, {type::Value}); + ParseResult haystack = ctx.parse(arrayMember(value, 2), 2, {type::Value}); + + if (!needle || !haystack) return ParseResult(); + + type::Type needleType = (*needle)->getType(); + type::Type haystackType = (*haystack)->getType(); + + if (!isComparableType(needleType)) { + ctx.error("Expected first argument to be of type boolean, string or number, but found " + toString(needleType) + + " instead."); + return ParseResult(); + } + + return ParseResult(std::make_unique(std::move(*needle), std::move(*haystack))); +} + +bool In::isComparableType(type::Type type) { + return type == type::Boolean || type == type::String || type == type::Number || type == type::Null || + type == type::Value; +} + +bool In::isComparableRuntimeValue(type::Type type) { + return type == type::Boolean || type == type::String || type == type::Number || type == type::Null; +} + +bool In::isSearchableRuntimeValue(type::Type type) { + return type == type::String || type.is() || type == type::Null; +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index d42c46bb09e..2f1e1c18202 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +115,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = {"any", Any::parse}, {"array", Assertion::parse}, {"at", At::parse}, + {"in", In::parse}, {"boolean", Assertion::parse}, {"case", Case::parse}, {"coalesce", Coalesce::parse}, diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp index bffadf1668a..b137df769a5 100644 --- a/test/style/expression/expression.test.cpp +++ b/test/style/expression/expression.test.cpp @@ -35,8 +35,7 @@ TEST(Expression, IsExpression) { // TODO: "interpolate-hcl": https://github.com/mapbox/mapbox-gl-native/issues/8720 // TODO: "interpolate-lab": https://github.com/mapbox/mapbox-gl-native/issues/8720 - // TODO: "in": https://github.com/mapbox/mapbox-gl-native/issues/15893 - if (name == "interpolate-hcl" || name == "interpolate-lab" || name == "in") { + if (name == "interpolate-hcl" || name == "interpolate-lab") { if (expression::isExpression(conversion::Convertible(expression))) { ASSERT_TRUE(false) << "Expression name" << name << "is implemented - please update Expression.IsExpression test."; } From 447b694e25997db7b5133b9376d94a4aa2f9ac5f Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 11 Feb 2020 17:02:08 +0800 Subject: [PATCH 2/8] Fix review comments. --- CMakeLists.txt | 1 + include/mbgl/style/expression/in.hpp | 7 +--- src/mbgl/style/expression/in.cpp | 58 ++++++++++++++-------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 485ced04aad..4428b38b539 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -586,6 +586,7 @@ add_library( ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/get_covering_stops.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/image.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/image_expression.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/in.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/interpolate.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/is_constant.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/is_expression.cpp diff --git a/include/mbgl/style/expression/in.hpp b/include/mbgl/style/expression/in.hpp index ab8e2e9ff2a..6bd57e2833f 100644 --- a/include/mbgl/style/expression/in.hpp +++ b/include/mbgl/style/expression/in.hpp @@ -8,7 +8,7 @@ namespace mbgl { namespace style { namespace expression { -class In : public Expression { +class In final : public Expression { public: In(std::unique_ptr needle_, std::unique_ptr haystack_) : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) {} @@ -26,16 +26,13 @@ class In : public Expression { return false; } - std::vector> possibleOutputs() const override { return {nullopt}; } + std::vector> possibleOutputs() const override { return {{true}, {false}}; } std::string getOperator() const override { return "in"; } private: std::unique_ptr needle; std::unique_ptr haystack; - static bool isComparableType(type::Type type); - static bool isComparableRuntimeValue(type::Type type); - static bool isSearchableRuntimeValue(type::Type type); }; } // namespace expression diff --git a/src/mbgl/style/expression/in.cpp b/src/mbgl/style/expression/in.cpp index 05336c7d922..28658b4a313 100644 --- a/src/mbgl/style/expression/in.cpp +++ b/src/mbgl/style/expression/in.cpp @@ -8,15 +8,30 @@ namespace mbgl { namespace style { namespace expression { +namespace { +bool isComparableType(type::Type type) { + return type == type::Boolean || type == type::String || type == type::Number || type == type::Null || + type == type::Value; +} + +bool isComparableRuntimeValue(type::Type type) { + return type == type::Boolean || type == type::String || type == type::Number || type == type::Null; +} + +bool isSearchableRuntimeValue(type::Type type) { + return type == type::String || type.is() || type == type::Null; +} +} + EvaluationResult In::evaluate(const EvaluationContext& params) const { const EvaluationResult evaluatedNeedle = needle->evaluate(params); - const EvaluationResult evaluatedHeystack = haystack->evaluate(params); - if (!evaluatedNeedle) { return evaluatedNeedle.error(); } - if (!evaluatedHeystack) { - return evaluatedHeystack.error(); + + const EvaluationResult evaluatedHaystack = haystack->evaluate(params); + if (!evaluatedHaystack) { + return evaluatedHaystack.error(); } type::Type evaluatedNeedleType = typeOf(*evaluatedNeedle); @@ -25,18 +40,18 @@ EvaluationResult In::evaluate(const EvaluationContext& params) const { toString(evaluatedNeedleType) + " instead."}; } - type::Type evaluatedHeystackType = typeOf(*evaluatedHeystack); - if (!isSearchableRuntimeValue(evaluatedHeystackType)) { + type::Type evaluatedHaystackType = typeOf(*evaluatedHaystack); + if (!isSearchableRuntimeValue(evaluatedHaystackType)) { return EvaluationError{"Expected second argument to be of type array or string, but found " + - toString(evaluatedHeystackType) + " instead."}; + toString(evaluatedHaystackType) + " instead."}; } - if (evaluatedNeedleType == type::Null || evaluatedHeystackType == type::Null) { + if (evaluatedNeedleType == type::Null || evaluatedHaystackType == type::Null) { return EvaluationResult(false); } - if (evaluatedHeystackType == type::String) { - const auto heystackString = evaluatedHeystack->get(); + if (evaluatedHaystackType == type::String) { + const auto haystackString = evaluatedHaystack->get(); std::string needleValue = ""; if (evaluatedNeedleType == type::Boolean) { needleValue = evaluatedNeedle->get() ? "true" : " false"; @@ -47,20 +62,20 @@ EvaluationResult In::evaluate(const EvaluationContext& params) const { needleValue.erase(needleValue.find_last_not_of('0') + 1, std::string::npos); needleValue.erase(needleValue.find_last_not_of('.') + 1, std::string::npos); } - return EvaluationResult(heystackString.find(needleValue) != std::string::npos); + return EvaluationResult(haystackString.find(needleValue) != std::string::npos); } else { - const auto heystackArray = evaluatedHeystack->get>(); + const auto haystackArray = evaluatedHaystack->get>(); bool result = false; if (evaluatedNeedleType == type::Boolean) { auto needleValue = evaluatedNeedle->get(); - result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); } else if (evaluatedNeedleType == type::String) { auto needleValue = evaluatedNeedle->get(); - result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); } else if (evaluatedNeedleType == type::Number) { auto needleValue = evaluatedNeedle->get(); - result = find(heystackArray.begin(), heystackArray.end(), needleValue) != heystackArray.end(); + result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); } return EvaluationResult(result); } @@ -98,19 +113,6 @@ ParseResult In::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique(std::move(*needle), std::move(*haystack))); } -bool In::isComparableType(type::Type type) { - return type == type::Boolean || type == type::String || type == type::Number || type == type::Null || - type == type::Value; -} - -bool In::isComparableRuntimeValue(type::Type type) { - return type == type::Boolean || type == type::String || type == type::Number || type == type::Null; -} - -bool In::isSearchableRuntimeValue(type::Type type) { - return type == type::String || type.is() || type == type::Null; -} - } // namespace expression } // namespace style } // namespace mbgl From 6f6e577acff72caa2f540ccfe4844578f4b00a2e Mon Sep 17 00:00:00 2001 From: kevin Date: Tue, 11 Feb 2020 19:34:58 +0800 Subject: [PATCH 3/8] Add expression_equality test for 'in' --- include/mbgl/style/expression/in.hpp | 3 +- src/mbgl/style/expression/in.cpp | 41 +++++++++------------ test/fixtures/expression_equality/in.a.json | 20 ++++++++++ test/fixtures/expression_equality/in.b.json | 20 ++++++++++ 4 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 test/fixtures/expression_equality/in.a.json create mode 100644 test/fixtures/expression_equality/in.b.json diff --git a/include/mbgl/style/expression/in.hpp b/include/mbgl/style/expression/in.hpp index 6bd57e2833f..f3e7551914f 100644 --- a/include/mbgl/style/expression/in.hpp +++ b/include/mbgl/style/expression/in.hpp @@ -10,8 +10,7 @@ namespace expression { class In final : public Expression { public: - In(std::unique_ptr needle_, std::unique_ptr haystack_) - : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) {} + In(std::unique_ptr needle_, std::unique_ptr haystack_); static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); diff --git a/src/mbgl/style/expression/in.cpp b/src/mbgl/style/expression/in.cpp index 28658b4a313..e0cdc9f260a 100644 --- a/src/mbgl/style/expression/in.cpp +++ b/src/mbgl/style/expression/in.cpp @@ -11,37 +11,43 @@ namespace expression { namespace { bool isComparableType(type::Type type) { return type == type::Boolean || type == type::String || type == type::Number || type == type::Null || - type == type::Value; + type == type::Value; } -bool isComparableRuntimeValue(type::Type type) { +bool isComparableRuntimeType(type::Type type) { return type == type::Boolean || type == type::String || type == type::Number || type == type::Null; } -bool isSearchableRuntimeValue(type::Type type) { +bool isSearchableRuntimeType(type::Type type) { return type == type::String || type.is() || type == type::Null; } +} // namespace + +In::In(std::unique_ptr needle_, std::unique_ptr haystack_) + : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) { + assert(isComparableType(needle->getType())); + assert(isSearchableRuntimeType(haystack->getType()) || haystack->getType() == type::Value); } EvaluationResult In::evaluate(const EvaluationContext& params) const { - const EvaluationResult evaluatedNeedle = needle->evaluate(params); - if (!evaluatedNeedle) { - return evaluatedNeedle.error(); - } - const EvaluationResult evaluatedHaystack = haystack->evaluate(params); if (!evaluatedHaystack) { return evaluatedHaystack.error(); } + const EvaluationResult evaluatedNeedle = needle->evaluate(params); + if (!evaluatedNeedle) { + return evaluatedNeedle.error(); + } + type::Type evaluatedNeedleType = typeOf(*evaluatedNeedle); - if (!isComparableRuntimeValue(evaluatedNeedleType)) { + if (!isComparableRuntimeType(evaluatedNeedleType)) { return EvaluationError{"Expected first argument to be of type boolean, string or number, but found " + toString(evaluatedNeedleType) + " instead."}; } type::Type evaluatedHaystackType = typeOf(*evaluatedHaystack); - if (!isSearchableRuntimeValue(evaluatedHaystackType)) { + if (!isSearchableRuntimeType(evaluatedHaystackType)) { return EvaluationError{"Expected second argument to be of type array or string, but found " + toString(evaluatedHaystackType) + " instead."}; } @@ -65,19 +71,8 @@ EvaluationResult In::evaluate(const EvaluationContext& params) const { return EvaluationResult(haystackString.find(needleValue) != std::string::npos); } else { const auto haystackArray = evaluatedHaystack->get>(); - - bool result = false; - if (evaluatedNeedleType == type::Boolean) { - auto needleValue = evaluatedNeedle->get(); - result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); - } else if (evaluatedNeedleType == type::String) { - auto needleValue = evaluatedNeedle->get(); - result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); - } else if (evaluatedNeedleType == type::Number) { - auto needleValue = evaluatedNeedle->get(); - result = find(haystackArray.begin(), haystackArray.end(), needleValue) != haystackArray.end(); - } - return EvaluationResult(result); + return EvaluationResult(std::find(haystackArray.begin(), haystackArray.end(), *evaluatedNeedle) != + haystackArray.end()); } } diff --git a/test/fixtures/expression_equality/in.a.json b/test/fixtures/expression_equality/in.a.json new file mode 100644 index 00000000000..2632695c6fc --- /dev/null +++ b/test/fixtures/expression_equality/in.a.json @@ -0,0 +1,20 @@ +[ + "number", + [ + "in", + [ + "number", + [ + "get", + "i" + ] + ], + [ + "array", + [ + "get", + "arr" + ] + ] + ] +] \ No newline at end of file diff --git a/test/fixtures/expression_equality/in.b.json b/test/fixtures/expression_equality/in.b.json new file mode 100644 index 00000000000..a63a94fb005 --- /dev/null +++ b/test/fixtures/expression_equality/in.b.json @@ -0,0 +1,20 @@ +[ + "number", + [ + "in", + [ + "number", + [ + "get", + "i" + ] + ], + [ + "array", + [ + "get", + "arr_other" + ] + ] + ] +] \ No newline at end of file From 0e0bed8da2a6ceea0a499f5547115653a5d1a833 Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 12 Feb 2020 17:41:22 +0800 Subject: [PATCH 4/8] Fix review comments. --- include/mbgl/style/expression/in.hpp | 12 ++------ src/mbgl/style/expression/in.cpp | 45 +++++++++++++++++++--------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/include/mbgl/style/expression/in.hpp b/include/mbgl/style/expression/in.hpp index f3e7551914f..a7de17c94d9 100644 --- a/include/mbgl/style/expression/in.hpp +++ b/include/mbgl/style/expression/in.hpp @@ -17,17 +17,11 @@ class In final : public Expression { EvaluationResult evaluate(const EvaluationContext& params) const override; void eachChild(const std::function&) const override; - bool operator==(const Expression& e) const override { - if (e.getKind() == Kind::In) { - auto rhs = static_cast(&e); - return *needle == *(rhs->needle) && *haystack == *(rhs->haystack); - } - return false; - } + bool operator==(const Expression& e) const override; - std::vector> possibleOutputs() const override { return {{true}, {false}}; } + std::vector> possibleOutputs() const override; - std::string getOperator() const override { return "in"; } + std::string getOperator() const override; private: std::unique_ptr needle; diff --git a/src/mbgl/style/expression/in.cpp b/src/mbgl/style/expression/in.cpp index e0cdc9f260a..fa2bd836569 100644 --- a/src/mbgl/style/expression/in.cpp +++ b/src/mbgl/style/expression/in.cpp @@ -18,6 +18,10 @@ bool isComparableRuntimeType(type::Type type) { return type == type::Boolean || type == type::String || type == type::Number || type == type::Null; } +bool isSearchableType(type::Type type) { + return type == type::String || type.is() || type == type::Null || type == type::Value; +} + bool isSearchableRuntimeType(type::Type type) { return type == type::String || type.is() || type == type::Null; } @@ -26,7 +30,7 @@ bool isSearchableRuntimeType(type::Type type) { In::In(std::unique_ptr needle_, std::unique_ptr haystack_) : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) { assert(isComparableType(needle->getType())); - assert(isSearchableRuntimeType(haystack->getType()) || haystack->getType() == type::Value); + assert(isSearchableType(haystack->getType())); } EvaluationResult In::evaluate(const EvaluationContext& params) const { @@ -58,17 +62,8 @@ EvaluationResult In::evaluate(const EvaluationContext& params) const { if (evaluatedHaystackType == type::String) { const auto haystackString = evaluatedHaystack->get(); - std::string needleValue = ""; - if (evaluatedNeedleType == type::Boolean) { - needleValue = evaluatedNeedle->get() ? "true" : " false"; - } else if (evaluatedNeedleType == type::String) { - needleValue = evaluatedNeedle->get(); - } else if (evaluatedNeedleType == type::Number) { - needleValue = std::to_string(evaluatedNeedle->get()); - needleValue.erase(needleValue.find_last_not_of('0') + 1, std::string::npos); - needleValue.erase(needleValue.find_last_not_of('.') + 1, std::string::npos); - } - return EvaluationResult(haystackString.find(needleValue) != std::string::npos); + const auto needleString = toString(*evaluatedNeedle); + return EvaluationResult(haystackString.find(needleString) != std::string::npos); } else { const auto haystackArray = evaluatedHaystack->get>(); return EvaluationResult(std::find(haystackArray.begin(), haystackArray.end(), *evaluatedNeedle) != @@ -92,9 +87,10 @@ ParseResult In::parse(const Convertible& value, ParsingContext& ctx) { } ParseResult needle = ctx.parse(arrayMember(value, 1), 1, {type::Value}); - ParseResult haystack = ctx.parse(arrayMember(value, 2), 2, {type::Value}); + if (!needle) return ParseResult(); - if (!needle || !haystack) return ParseResult(); + ParseResult haystack = ctx.parse(arrayMember(value, 2), 2, {type::Value}); + if (!haystack) return ParseResult(); type::Type needleType = (*needle)->getType(); type::Type haystackType = (*haystack)->getType(); @@ -105,9 +101,30 @@ ParseResult In::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(); } + if (!isSearchableType(haystackType)) { + ctx.error("Expected second argument to be of type array or string, but found " + toString(haystackType) + + " instead."); + return ParseResult(); + } return ParseResult(std::make_unique(std::move(*needle), std::move(*haystack))); } +bool In::operator==(const Expression& e) const { + if (e.getKind() == Kind::In) { + auto rhs = static_cast(&e); + return *needle == *(rhs->needle) && *haystack == *(rhs->haystack); + } + return false; +} + +std::vector> In::possibleOutputs() const { + return {{true}, {false}}; +} + +std::string In::getOperator() const { + return "in"; +} + } // namespace expression } // namespace style } // namespace mbgl From 47d470a923c94b9cc872374220287baa90706e7f Mon Sep 17 00:00:00 2001 From: kevin Date: Wed, 12 Feb 2020 19:51:26 +0800 Subject: [PATCH 5/8] [core] Update changelog. --- CHANGELOG.md | 8 ++++++-- CMakeLists.txt | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb643dd222a..4963c3f87f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,9 +22,13 @@ The `within expression` enables checking whether a feature is inside a pre-defined geometry set/boundary or not. This `within expression` returns a boolean value, `true` indicates that the feature being evaluated is inside the geometry set. The returned value can be then consumed as input by another expression or used directly by a paint/layer property. - Support for using `within expression` with layout propery will be implemented separately. + Support for using `within expression` with layout property will be implemented separately. -- [core] Add support for using `within expression` with layout propery. ([#16194](https://github.com/mapbox/mapbox-gl-native/pull/16194)) +- [core] Add support for using `within expression` with layout property. ([#16194](https://github.com/mapbox/mapbox-gl-native/pull/16194)) + +- [core] Add support for `in expression`. ([#16162](https://github.com/mapbox/mapbox-gl-native/pull/16162)) + + The `in expression` enables checking whether a Number/String/Boolean type needle is in a String/Array and returns a boolean value. ### 🐞 Bug fixes diff --git a/CMakeLists.txt b/CMakeLists.txt index 4428b38b539..deb000db9f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ add_library( ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/get_covering_stops.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/image.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/image_expression.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/in.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/interpolate.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/interpolator.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/expression/is_constant.hpp From d079958ff6d05b14df6e78a376189379b6a55573 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 15 Feb 2020 08:44:06 +0800 Subject: [PATCH 6/8] [core] Update mapbox-gl-js --- CHANGELOG.md | 2 +- mapbox-gl-js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4963c3f87f5..ce1d4f4a69a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ - [core] Add support for `in expression`. ([#16162](https://github.com/mapbox/mapbox-gl-native/pull/16162)) - The `in expression` enables checking whether a Number/String/Boolean type needle is in a String/Array and returns a boolean value. + The `in expression` enables checking whether a Number/String/Boolean type item is in a String/Array and returns a boolean value. ### 🐞 Bug fixes diff --git a/mapbox-gl-js b/mapbox-gl-js index 9c5ac9c1754..8905d24ffa3 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 9c5ac9c17545026d7ff05004be724f542b8c3247 +Subproject commit 8905d24ffa30f4f5d5ebbd67fbbf8664dc123019 From 3ddc1f653c27c667e4810ff153d0904722918846 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 15 Feb 2020 09:54:08 +0800 Subject: [PATCH 7/8] [core] Ignore render-tests/debug/padding --- metrics/ignores/platform-all.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/metrics/ignores/platform-all.json b/metrics/ignores/platform-all.json index 9b1ad315e22..0ea2dbbc6de 100644 --- a/metrics/ignores/platform-all.json +++ b/metrics/ignores/platform-all.json @@ -62,6 +62,12 @@ "render-tests/custom-layer-js/tent-3d": "skip - js specific", "render-tests/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841", "render-tests/debug/overdraw": "https://github.com/mapbox/mapbox-gl-native/issues/15638", + "render-tests/debug/padding/ease-to-btm-distort": "https://github.com/mapbox/mapbox-gl-native/issues/16212", + "render-tests/debug/padding/ease-to-left-distort": "https://github.com/mapbox/mapbox-gl-native/issues/16212", + "render-tests/debug/padding/ease-to-no-distort": "https://github.com/mapbox/mapbox-gl-native/issues/16212", + "render-tests/debug/padding/ease-to-right-distort": "https://github.com/mapbox/mapbox-gl-native/issues/16212", + "render-tests/debug/padding/ease-to-top-distort": "https://github.com/mapbox/mapbox-gl-native/issues/16212", + "render-tests/debug/padding/set-padding": "https://github.com/mapbox/mapbox-gl-native/issues/16212", "render-tests/debug/raster": "https://github.com/mapbox/mapbox-gl-native/issues/15510", "render-tests/debug/tile": "https://github.com/mapbox/mapbox-gl-native/issues/3841", "render-tests/debug/tile-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/3841", From 551fe13a1866de513fcf749aa31c4b5b7e712b02 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 15 Feb 2020 14:15:07 +0800 Subject: [PATCH 8/8] [core] Update baseline. --- metrics/binary-size/macos-xcode11/metrics.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics/binary-size/macos-xcode11/metrics.json b/metrics/binary-size/macos-xcode11/metrics.json index 06a66871439..7bd94ba9927 100644 --- a/metrics/binary-size/macos-xcode11/metrics.json +++ b/metrics/binary-size/macos-xcode11/metrics.json @@ -3,17 +3,17 @@ [ "mbgl-glfw", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-glfw", - 5616056 + 5677792 ], [ "mbgl-offline", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-offline", - 5484604 + 5542252 ], [ "mbgl-render", "/tmp/attach/install/macos-xcode11-release/bin/mbgl-render", - 5530720 + 5588368 ] ] } \ No newline at end of file