diff options
author | Kevin Li <kevin.li@mapbox.com> | 2020-02-15 17:36:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-15 17:36:57 +0800 |
commit | 02274e76019bcfb938f50cdb638eca49c33de786 (patch) | |
tree | ed472d6d3eb511a51bd9fcd2fb568b96976aafd7 /src | |
parent | 59294aaef333bdd455bd13d6bab6fca730379b52 (diff) | |
download | qtlocation-mapboxgl-02274e76019bcfb938f50cdb638eca49c33de786.tar.gz |
[core] Implement 'in' expression. (#16162)
* Implement in.cpp
* Fix review comments.
* Add expression_equality test for 'in'
* Fix review comments.
* [core] Update changelog.
* [core] Update mapbox-gl-js
* [core] Ignore render-tests/debug/padding
* [core] Update baseline.
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/style/expression/in.cpp | 130 | ||||
-rw-r--r-- | src/mbgl/style/expression/parsing_context.cpp | 2 |
2 files changed, 132 insertions, 0 deletions
diff --git a/src/mbgl/style/expression/in.cpp b/src/mbgl/style/expression/in.cpp new file mode 100644 index 0000000000..fa2bd83656 --- /dev/null +++ b/src/mbgl/style/expression/in.cpp @@ -0,0 +1,130 @@ +#include <string.h> +#include <mbgl/style/conversion_impl.hpp> +#include <mbgl/style/expression/in.hpp> +#include <mbgl/style/expression/type.hpp> +#include <mbgl/util/string.hpp> + +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 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::Array>() || type == type::Null || type == type::Value; +} + +bool isSearchableRuntimeType(type::Type type) { + return type == type::String || type.is<type::Array>() || type == type::Null; +} +} // namespace + +In::In(std::unique_ptr<Expression> needle_, std::unique_ptr<Expression> haystack_) + : Expression(Kind::In, type::Boolean), needle(std::move(needle_)), haystack(std::move(haystack_)) { + assert(isComparableType(needle->getType())); + assert(isSearchableType(haystack->getType())); +} + +EvaluationResult In::evaluate(const EvaluationContext& params) const { + 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 (!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 (!isSearchableRuntimeType(evaluatedHaystackType)) { + return EvaluationError{"Expected second argument to be of type array or string, but found " + + toString(evaluatedHaystackType) + " instead."}; + } + + if (evaluatedNeedleType == type::Null || evaluatedHaystackType == type::Null) { + return EvaluationResult(false); + } + + if (evaluatedHaystackType == type::String) { + const auto haystackString = evaluatedHaystack->get<std::string>(); + const auto needleString = toString(*evaluatedNeedle); + return EvaluationResult(haystackString.find(needleString) != std::string::npos); + } else { + const auto haystackArray = evaluatedHaystack->get<std::vector<Value>>(); + return EvaluationResult(std::find(haystackArray.begin(), haystackArray.end(), *evaluatedNeedle) != + haystackArray.end()); + } +} + +void In::eachChild(const std::function<void(const Expression&)>& 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}); + if (!needle) 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(); + + if (!isComparableType(needleType)) { + ctx.error("Expected first argument to be of type boolean, string or number, but found " + toString(needleType) + + " instead."); + 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<In>(std::move(*needle), std::move(*haystack))); +} + +bool In::operator==(const Expression& e) const { + if (e.getKind() == Kind::In) { + auto rhs = static_cast<const In*>(&e); + return *needle == *(rhs->needle) && *haystack == *(rhs->haystack); + } + return false; +} + +std::vector<optional<Value>> In::possibleOutputs() const { + return {{true}, {false}}; +} + +std::string In::getOperator() const { + return "in"; +} + +} // 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 d42c46bb09..2f1e1c1820 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -15,6 +15,7 @@ #include <mbgl/style/expression/expression.hpp> #include <mbgl/style/expression/format_expression.hpp> #include <mbgl/style/expression/image_expression.hpp> +#include <mbgl/style/expression/in.hpp> #include <mbgl/style/expression/interpolate.hpp> #include <mbgl/style/expression/length.hpp> #include <mbgl/style/expression/let.hpp> @@ -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}, |