From a0b298211908036da269e7dcc2c78025476e2bf2 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 15 Jun 2016 14:55:45 -0700 Subject: [core] Prepare Filter and FilterEvaluator for extraction (#5366) --- benchmark/parse/filter.cpp | 34 ++---- include/mbgl/style/filter.hpp | 42 +++++--- include/mbgl/style/filter_evaluator.hpp | 181 ++++++++++++++++++++++++++++++++ include/mbgl/util/geometry.hpp | 7 ++ src/mbgl/renderer/symbol_bucket.cpp | 4 +- src/mbgl/style/bucket_parameters.cpp | 5 +- src/mbgl/style/filter_evaluator.hpp | 163 ---------------------------- src/mbgl/tile/geometry_tile_data.hpp | 7 -- test/style/filter.cpp | 37 ++----- 9 files changed, 228 insertions(+), 252 deletions(-) create mode 100644 include/mbgl/style/filter_evaluator.hpp delete mode 100644 src/mbgl/style/filter_evaluator.hpp diff --git a/benchmark/parse/filter.cpp b/benchmark/parse/filter.cpp index 7450fc7804..8beff3b308 100644 --- a/benchmark/parse/filter.cpp +++ b/benchmark/parse/filter.cpp @@ -13,32 +13,6 @@ using namespace mbgl; typedef std::multimap Properties; -class StubFeature : public GeometryTileFeature { -public: - inline StubFeature(const Properties& properties_, FeatureType type_) - : properties(properties_), type(type_) { - } - - optional getValue(const std::string& key) const override { - auto it = properties.find(key); - if (it == properties.end()) - return optional(); - return it->second; - } - - FeatureType getType() const override { - return type; - } - - GeometryCollection getGeometries() const override { - return GeometryCollection(); - } - -private: - const Properties properties; - FeatureType type; -}; - style::Filter parse(const char* expression) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.Parse<0>(expression); @@ -54,10 +28,14 @@ static void Parse_Filter(benchmark::State& state) { static void Parse_EvaluateFilter(benchmark::State& state) { const style::Filter filter = parse(R"FILTER(["==", "foo", "bar"])FILTER"); const Properties properties = { { "foo", std::string("bar") } }; - const StubFeature feature(properties, FeatureType::Unknown); while (state.KeepRunning()) { - style::Filter::visit(filter, style::FilterEvaluator{ feature }); + filter(FeatureType::Unknown, [&] (const std::string& key) -> optional { + auto it = properties.find(key); + if (it == properties.end()) + return {}; + return it->second; + }); } } diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp index 9cf84f5e1d..6a5afb7b47 100644 --- a/include/mbgl/style/filter.hpp +++ b/include/mbgl/style/filter.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -9,22 +10,7 @@ namespace mbgl { namespace style { -typedef variant< - class NullFilter, - class EqualsFilter, - class NotEqualsFilter, - class LessThanFilter, - class LessThanEqualsFilter, - class GreaterThanFilter, - class GreaterThanEqualsFilter, - class InFilter, - class NotInFilter, - class AnyFilter, - class AllFilter, - class NoneFilter, - class HasFilter, - class NotHasFilter - > Filter; +class Filter; class NullFilter {}; @@ -101,5 +87,29 @@ public: std::string key; }; +using FilterBase = variant< + class NullFilter, + class EqualsFilter, + class NotEqualsFilter, + class LessThanFilter, + class LessThanEqualsFilter, + class GreaterThanFilter, + class GreaterThanEqualsFilter, + class InFilter, + class NotInFilter, + class AnyFilter, + class AllFilter, + class NoneFilter, + class HasFilter, + class NotHasFilter>; + +class Filter : public FilterBase { +public: + using FilterBase::FilterBase; + + template + bool operator()(FeatureType type, PropertyAccessor accessor) const; +}; + } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp new file mode 100644 index 0000000000..a458a2807b --- /dev/null +++ b/include/mbgl/style/filter_evaluator.hpp @@ -0,0 +1,181 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace style { + +/* + A visitor that evaluates a `Filter` for a given feature type and properties. For maximum + flexibility, it is templated on the PropertyAccessor type, which must be a callable type with + function signature `optional (const std::string&)`, returning the value for the given + key, if it exists. + + Use via `Filter::operator()`. For example: + + if (filter(feature.getType(), [&] (const std::string& key) { return feature.getValue(key); })) { + // matches the filter + } else { + // does not match + } +*/ +template +class FilterEvaluator { +public: + const FeatureType featureType; + const PropertyAccessor propertyAccessor; + + bool operator()(const NullFilter&) const { + return true; + } + + bool operator()(const EqualsFilter& filter) const { + optional actual = getValue(filter.key); + return actual && equal(*actual, filter.value); + } + + bool operator()(const NotEqualsFilter& filter) const { + optional actual = getValue(filter.key); + return !actual || !equal(*actual, filter.value); + } + + bool operator()(const LessThanFilter& filter) const { + optional actual = getValue(filter.key); + return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; }); + } + + bool operator()(const LessThanEqualsFilter& filter) const { + optional actual = getValue(filter.key); + return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; }); + } + + bool operator()(const GreaterThanFilter& filter) const { + optional actual = getValue(filter.key); + return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; }); + } + + bool operator()(const GreaterThanEqualsFilter& filter) const { + optional actual = getValue(filter.key); + return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; }); + } + + bool operator()(const InFilter& filter) const { + optional actual = getValue(filter.key); + if (!actual) + return false; + for (const auto& v: filter.values) { + if (equal(*actual, v)) { + return true; + } + } + return false; + } + + bool operator()(const NotInFilter& filter) const { + optional actual = getValue(filter.key); + if (!actual) + return true; + for (const auto& v: filter.values) { + if (equal(*actual, v)) { + return false; + } + } + return true; + } + + bool operator()(const AnyFilter& filter) const { + for (const auto& f: filter.filters) { + if (Filter::visit(f, *this)) { + return true; + } + } + return false; + } + + bool operator()(const AllFilter& filter) const { + for (const auto& f: filter.filters) { + if (!Filter::visit(f, *this)) { + return false; + } + } + return true; + } + + bool operator()(const NoneFilter& filter) const { + for (const auto& f: filter.filters) { + if (Filter::visit(f, *this)) { + return false; + } + } + 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 getValue(const std::string& key_) const { + return key_ == "$type" + ? optional(uint64_t(featureType)) + : propertyAccessor(key_); + } + + template + struct Comparator { + const Op& op; + + template + bool operator()(const T& lhs, const T& rhs) const { + return op(lhs, rhs); + } + + template + auto operator()(const T0& lhs, const T1& rhs) const + -> typename std::enable_if_t::value && !std::is_same::value && + std::is_arithmetic::value && !std::is_same::value, bool> { + return op(double(lhs), double(rhs)); + } + + template + auto operator()(const T0&, const T1&) const + -> typename std::enable_if_t::value || std::is_same::value || + !std::is_arithmetic::value || std::is_same::value, bool> { + return false; + } + + bool operator()(const std::vector&, + const std::vector&) const { + return false; + } + + bool operator()(const std::unordered_map&, + const std::unordered_map&) const { + return false; + } + }; + + template + bool compare(const Value& lhs, const Value& rhs, const Op& op) const { + return Value::binary_visit(lhs, rhs, Comparator { op }); + } + + bool equal(const Value& lhs, const Value& rhs) const { + return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; }); + } +}; + +template +inline bool Filter::operator()(FeatureType type, PropertyAccessor accessor) const { + return FilterBase::visit(*this, FilterEvaluator { type, accessor }); +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/util/geometry.hpp b/include/mbgl/util/geometry.hpp index 6b9c332bf2..7fc2668c2c 100644 --- a/include/mbgl/util/geometry.hpp +++ b/include/mbgl/util/geometry.hpp @@ -5,6 +5,13 @@ namespace mbgl { +enum class FeatureType : uint8_t { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3 +}; + template using Point = mapbox::geometry::point; diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index e34aedb47e..496745dda1 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -119,9 +119,7 @@ void SymbolBucket::parseFeatures(const GeometryTileLayer& layer, const Filter& f const GLsizei featureCount = static_cast(layer.featureCount()); for (GLsizei i = 0; i < featureCount; i++) { auto feature = layer.getFeature(i); - - FilterEvaluator evaluator(*feature); - if (!Filter::visit(filter, evaluator)) + if (!filter(feature->getType(), [&] (const auto& key) { return feature->getValue(key); })) continue; SymbolFeature ft; diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/bucket_parameters.cpp index 1a928dcecc..5bb08af873 100644 --- a/src/mbgl/style/bucket_parameters.cpp +++ b/src/mbgl/style/bucket_parameters.cpp @@ -10,11 +10,8 @@ void BucketParameters::eachFilteredFeature(const Filter& filter, auto name = layer.getName(); for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) { auto feature = layer.getFeature(i); - - FilterEvaluator evaluator(*feature); - if (!Filter::visit(filter, evaluator)) + if (!filter(feature->getType(), [&] (const auto& key) { return feature->getValue(key); })) continue; - function(*feature, i, name); } } diff --git a/src/mbgl/style/filter_evaluator.hpp b/src/mbgl/style/filter_evaluator.hpp deleted file mode 100644 index 9d5919ced1..0000000000 --- a/src/mbgl/style/filter_evaluator.hpp +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace mbgl { -namespace style { - -class FilterEvaluator { -public: - FilterEvaluator(const GeometryTileFeature& feature_) - : feature(feature_) {} - - bool operator()(const NullFilter&) const { - return true; - } - - bool operator()(const EqualsFilter& filter) const { - optional actual = getValue(filter.key); - return actual && equal(*actual, filter.value); - } - - bool operator()(const NotEqualsFilter& filter) const { - optional actual = getValue(filter.key); - return !actual || !equal(*actual, filter.value); - } - - bool operator()(const LessThanFilter& filter) const { - optional actual = getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; }); - } - - bool operator()(const LessThanEqualsFilter& filter) const { - optional actual = getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; }); - } - - bool operator()(const GreaterThanFilter& filter) const { - optional actual = getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; }); - } - - bool operator()(const GreaterThanEqualsFilter& filter) const { - optional actual = getValue(filter.key); - return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; }); - } - - bool operator()(const InFilter& filter) const { - optional actual = getValue(filter.key); - if (!actual) - return false; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return true; - } - } - return false; - } - - bool operator()(const NotInFilter& filter) const { - optional actual = getValue(filter.key); - if (!actual) - return true; - for (const auto& v: filter.values) { - if (equal(*actual, v)) { - return false; - } - } - return true; - } - - bool operator()(const AnyFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return true; - } - } - return false; - } - - bool operator()(const AllFilter& filter) const { - for (const auto& f: filter.filters) { - if (!Filter::visit(f, *this)) { - return false; - } - } - return true; - } - - bool operator()(const NoneFilter& filter) const { - for (const auto& f: filter.filters) { - if (Filter::visit(f, *this)) { - return false; - } - } - 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 getValue(const std::string& key) const { - return key == "$type" - ? optional(uint64_t(feature.getType())) - : feature.getValue(key); - } - - template - struct Comparator { - const Op& op; - - template - bool operator()(const T& lhs, const T& rhs) const { - return op(lhs, rhs); - } - - template - auto operator()(const T0& lhs, const T1& rhs) const - -> typename std::enable_if_t::value && !std::is_same::value && - std::is_arithmetic::value && !std::is_same::value, bool> { - return op(double(lhs), double(rhs)); - } - - template - auto operator()(const T0&, const T1&) const - -> typename std::enable_if_t::value || std::is_same::value || - !std::is_arithmetic::value || std::is_same::value, bool> { - return false; - } - - bool operator()(const std::vector&, - const std::vector&) const { - return false; - } - - bool operator()(const std::unordered_map&, - const std::unordered_map&) const { - return false; - } - }; - - template - bool compare(const Value& lhs, const Value& rhs, const Op& op) const { - return Value::binary_visit(lhs, rhs, Comparator { op }); - } - - bool equal(const Value& lhs, const Value& rhs) const { - return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; }); - } - - const GeometryTileFeature& feature; -}; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 753ba6b8a2..1dc22e0c55 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -17,13 +17,6 @@ namespace mbgl { -enum class FeatureType : uint8_t { - Unknown = 0, - Point = 1, - LineString = 2, - Polygon = 3 -}; - class CanonicalTileID; // Normalized vector tile coordinates. diff --git a/test/style/filter.cpp b/test/style/filter.cpp index d28ee4a357..4a1010445e 100644 --- a/test/style/filter.cpp +++ b/test/style/filter.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include @@ -14,33 +13,6 @@ using namespace mbgl::style; typedef std::multimap Properties; -class StubFeature : public GeometryTileFeature { -public: - inline StubFeature(Properties properties_, FeatureType type_) - : properties(std::move(properties_)) - , type(type_) - {} - - optional getValue(const std::string &key) const override { - auto it = properties.find(key); - if (it == properties.end()) - return optional(); - return it->second; - } - - FeatureType getType() const override { - return type; - } - - GeometryCollection getGeometries() const override { - return GeometryCollection(); - } - -private: - const Properties properties; - FeatureType type; -}; - Filter parse(const char * expression) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.Parse<0>(expression); @@ -48,9 +20,12 @@ Filter parse(const char * expression) { } bool evaluate(const Filter& filter, const Properties& properties, FeatureType type = FeatureType::Unknown) { - StubFeature feature(properties, type); - FilterEvaluator evaluator(feature); - return Filter::visit(filter, evaluator); + return filter(type, [&] (const std::string& key) -> optional { + auto it = properties.find(key); + if (it == properties.end()) + return {}; + return it->second; + }); } TEST(Filter, EqualsString) { -- cgit v1.2.1