diff options
-rw-r--r-- | src/mbgl/style/filter.hpp | 14 | ||||
-rw-r--r-- | src/mbgl/style/filter_evaluator.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.cpp | 25 | ||||
-rw-r--r-- | test/style/filter.cpp | 22 |
4 files changed, 67 insertions, 2 deletions
diff --git a/src/mbgl/style/filter.hpp b/src/mbgl/style/filter.hpp index 0a1dcbd17a..6ad6969fbf 100644 --- a/src/mbgl/style/filter.hpp +++ b/src/mbgl/style/filter.hpp @@ -20,7 +20,9 @@ typedef variant< class NotInFilter, class AnyFilter, class AllFilter, - class NoneFilter + class NoneFilter, + class HasFilter, + class NotHasFilter > Filter; class NullFilter {}; @@ -88,4 +90,14 @@ public: std::vector<Filter> filters; }; +class HasFilter { +public: + std::string key; +}; + +class NotHasFilter { +public: + std::string key; +}; + } // namespace mbgl diff --git a/src/mbgl/style/filter_evaluator.hpp b/src/mbgl/style/filter_evaluator.hpp index ab550ee26c..b607a0c658 100644 --- a/src/mbgl/style/filter_evaluator.hpp +++ b/src/mbgl/style/filter_evaluator.hpp @@ -97,6 +97,14 @@ public: return true; } + bool operator()(const HasFilter& filter) const { + return bool(getValue(filter.key)); + } + + bool operator()(const NotHasFilter& filter) const { + return !getValue(filter.key); + } + private: optional<Value> getValue(const std::string& key) const { return key == "$type" diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 27edf15f97..4f081e7d85 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -534,6 +534,25 @@ Value parseValue(const JSValue& value) { } template <class Expression> +Filter parseUnaryFilter(const JSValue& value) { + Filter empty; + + if (value.Size() < 2) { + Log::Warning(Event::ParseStyle, "filter expression must have 2 elements"); + return empty; + } + + if (!value[1u].IsString()) { + Log::Warning(Event::ParseStyle, "filter expression key must be a string"); + return empty; + } + + Expression expression; + expression.key = { value[1u].GetString(), value[1u].GetStringLength() }; + return expression; +} + +template <class Expression> Filter parseBinaryFilter(const JSValue& value) { Filter empty; @@ -635,8 +654,12 @@ Filter parseFilter(const JSValue& value) { return parseCompoundFilter<AnyFilter>(value); } else if (op == "none") { return parseCompoundFilter<NoneFilter>(value); + } else if (op == "has") { + return parseUnaryFilter<HasFilter>(value); + } else if (op == "!has") { + return parseUnaryFilter<NotHasFilter>(value); } else { - Log::Warning(Event::ParseStyle, "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\""); + Log::Warning(Event::ParseStyle, "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\""); return empty; } } diff --git a/test/style/filter.cpp b/test/style/filter.cpp index da0e5ff4a3..f258c31492 100644 --- a/test/style/filter.cpp +++ b/test/style/filter.cpp @@ -114,3 +114,25 @@ TEST(Filter, None) { ASSERT_FALSE(evaluate(parse("[\"none\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]"), {{ std::string("foo"), int64_t(1) }})); } + +TEST(Filter, Has) { + ASSERT_TRUE(evaluate(parse("[\"has\", \"foo\"]"), + {{ std::string("foo"), int64_t(1) }})); + ASSERT_TRUE(evaluate(parse("[\"has\", \"foo\"]"), + {{ std::string("foo"), int64_t(0) }})); + ASSERT_TRUE(evaluate(parse("[\"has\", \"foo\"]"), + {{ std::string("foo"), false }})); + ASSERT_FALSE(evaluate(parse("[\"has\", \"foo\"]"), + {{}})); +} + +TEST(Filter, NotHas) { + ASSERT_FALSE(evaluate(parse("[\"!has\", \"foo\"]"), + {{ std::string("foo"), int64_t(1) }})); + ASSERT_FALSE(evaluate(parse("[\"!has\", \"foo\"]"), + {{ std::string("foo"), int64_t(0) }})); + ASSERT_FALSE(evaluate(parse("[\"!has\", \"foo\"]"), + {{ std::string("foo"), false }})); + ASSERT_TRUE(evaluate(parse("[\"!has\", \"foo\"]"), + {{}})); +} |