From aff667d7427ba341edb93386d2b6690aa8aa0a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 26 Jun 2014 15:04:18 +0200 Subject: add filter expressions --- include/llmr/map/filter_expression.hpp | 181 ++++++------ include/llmr/map/tile_parser.hpp | 12 +- include/llmr/map/vector_tile.hpp | 25 +- include/llmr/style/bucket_description.hpp | 2 +- include/llmr/style/style_bucket.hpp | 3 +- include/llmr/style/style_parser.hpp | 9 +- include/llmr/style/value.hpp | 12 +- include/llmr/util/recursive_wrapper.hpp | 31 +- include/llmr/util/variant.hpp | 453 ++++++++++++++++++++++-------- src/map/filter_expression.cpp | 282 +++++++++++++++++++ src/map/map.cpp | 2 - src/map/tile_parser.cpp | 18 +- src/map/vector_tile.cpp | 199 ++++++++----- src/style/style_parser.cpp | 165 ++++++----- 14 files changed, 974 insertions(+), 420 deletions(-) create mode 100644 src/map/filter_expression.cpp diff --git a/include/llmr/map/filter_expression.hpp b/include/llmr/map/filter_expression.hpp index 50e6ce1d78..3c4ac857e5 100644 --- a/include/llmr/map/filter_expression.hpp +++ b/include/llmr/map/filter_expression.hpp @@ -4,125 +4,114 @@ #include #include -#include +#include #include +#include +#include namespace llmr { -enum class FilterOperator { - Equal, - NotEqual, - Greater, - GreaterEqual, - Less, - LessEqual -}; +class VectorTileTagExtractor; -enum class ExpressionOperator { - Or, - And -}; +class FilterComparison { +public: + enum class Operator : uint8_t { + Equal, + NotEqual, + Greater, + GreaterEqual, + Less, + LessEqual, + In, + NotIn + }; + + class Instance { + public: + Instance(Operator op, std::forward_list &&values) + : op(op), values(values) {} + + bool compare(const Value &property_value) const; + bool compare(const std::forward_list &property_values) const; + + private: + template inline bool includes(const Value &property_value, const Comparer &comparer) const; + template inline bool compare(const Value &property_value, const Comparer &comparer) const; + template inline bool all(const std::forward_list &property_values, const Comparer &comparer) const; + + private: + Operator op = Operator::Equal; + std::forward_list values; + + friend std::ostream& operator <<(std::ostream &, const Instance &); + }; +public: + FilterComparison(const std::string &field) : field(field) {}; -inline FilterOperator filterOperatorType(const std::string &op) { - if (op == "!=" || op == "not") { - return FilterOperator::NotEqual; - } else if (op == "==" || op == "eq") { - return FilterOperator::Equal; - } else if (op == ">" || op == "gt") { - return FilterOperator::Greater; - } else if (op == ">=" || op == "gte") { - return FilterOperator::GreaterEqual; - } else if (op == "<" || op == "lt") { - return FilterOperator::Less; - } else if (op == "<=" || op == "lte") { - return FilterOperator::LessEqual; - } else { - fprintf(stderr, "[WARNING] filter operator '%s' unrecognized\n", op.c_str()); - return FilterOperator::Equal; - } -} + const std::string &getField() const; + inline bool compare(const VectorTileTagExtractor &extractor) const; -inline ExpressionOperator expressionOperatorType(const std::string &op) { - if (op == "&&" || op == "and") { - return ExpressionOperator::And; - } else if (op == "||" || op == "or") { - return ExpressionOperator::Or; - } else { - fprintf(stderr, "[WARNING] expression operator '%s' unrecognized\n", op.c_str()); - return ExpressionOperator::Or; + template + inline void add(Args&& ...args) { + instances.emplace_front(::std::forward(args)...); } -} +private: + std::string field; + std::forward_list instances; -class PropertyFilter; -class PropertyExpression; + friend std::ostream& operator <<(std::ostream &, const FilterComparison &); +}; -typedef util::variant< - util::recursive_wrapper, - util::recursive_wrapper, - std::true_type -> PropertyFilterExpression; +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison); +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance); -class PropertyFilter { -public: - inline PropertyFilter(const std::string &field, FilterOperator op, const Value &value) : field(field), op(op), value(value) {}; - inline PropertyFilter(PropertyFilter &&filter) - : field(std::move(filter.field)), - op(filter.op), - value(std::move(filter.value)) { - } +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op); - // Returns true if the filter passes, even if the key is missing. - inline bool isMissingFieldOkay() const { - switch (op) { - case FilterOperator::NotEqual: - return true; - default: - return false; - } - } - - inline bool compare(const Value &other) const { - switch (op) { - case FilterOperator::Equal: - return util::relaxed_equal(other, value); - case FilterOperator::NotEqual: - return !util::relaxed_equal(other, value); - case FilterOperator::Greater: - return util::relaxed_greater(other, value); - case FilterOperator::GreaterEqual: - return util::relaxed_greater_equal(other, value); - case FilterOperator::Less: - return util::relaxed_less(other, value); - case FilterOperator::LessEqual: - return util::relaxed_less_equal(other, value); - default: - return false; - } - } +class FilterExpression { public: - std::string field; - FilterOperator op = FilterOperator::Equal; - Value value; -}; + typedef util::recursive_wrapper Wrapper; + + enum class Operator : uint8_t { + And, + Or, + Xor, + Nor + }; + + enum class GeometryType : uint8_t { + Any, + Point, + Line, + Polygon + }; -class PropertyExpression { public: - inline PropertyExpression() {} - inline PropertyExpression(PropertyExpression &&expression) - : op(expression.op), - operands(std::move(expression.operands)) { - } + FilterExpression() = default; + FilterExpression(Operator op) : op(op) {}; -public: - ExpressionOperator op = ExpressionOperator::Or; - std::vector operands; + bool empty() const; + + bool compare(const VectorTileTagExtractor &extractor) const; + void add(const FilterComparison &comparison); + void add(const FilterExpression &expression); + void setGeometryType(GeometryType g); + +private: + Operator op = Operator::And; + GeometryType type = GeometryType::Any; + std::forward_list comparisons; + std::forward_list expressions; + + friend std::ostream& operator <<(std::ostream &, const FilterExpression &); }; +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression); +FilterExpression::GeometryType parseGeometryType(const std::string &geometry); } #endif diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 9e763a13af..2809c6b4e7 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -42,13 +42,13 @@ private: void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face); std::unique_ptr createBucket(std::shared_ptr bucket_desc); - std::unique_ptr createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill); - std::unique_ptr createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line); - std::unique_ptr createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon); - std::unique_ptr createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text); + std::unique_ptr createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill); + std::unique_ptr createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line); + std::unique_ptr createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon); + std::unique_ptr createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text); - template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter); - template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter); + template void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args); private: const VectorTile vector_data; diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index b2f3d416e3..f9e01c38b6 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -40,6 +40,22 @@ public: std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature); + +class VectorTileTagExtractor { +public: + VectorTileTagExtractor(const VectorTileLayer &layer); + + void setTags(const pbf &pbf); + std::forward_list getValues(const std::string &key) const; + void setType(FilterExpression::GeometryType type); + FilterExpression::GeometryType getType() const; + +private: + const VectorTileLayer &layer_; + pbf tags_; + FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any; +}; + /* * Allows iterating over the features of a VectorTileLayer using a * BucketDescription as filter. Only features matching the descriptions will @@ -54,11 +70,6 @@ public: bool operator!=(const iterator& other) const; const pbf& operator*() const; - private: - bool matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf); - bool matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf); - bool matchesFilter(const PropertyFilter &filter, const pbf &tags_pbf); - private: const FilteredVectorTileLayer& parent; bool valid = false; @@ -67,14 +78,14 @@ public: }; public: - FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression); + FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression); iterator begin() const; iterator end() const; private: const VectorTileLayer& layer; - const PropertyFilterExpression& filterExpression; + const FilterExpression& filterExpression; }; std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement); diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 9b1bb5c774..6011b53990 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -22,7 +22,7 @@ public: std::string source_name; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; // Specifies how the geometry for this bucket should be created StyleBucketRender render; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index bd6dcf7147..eee9929a89 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -7,6 +7,7 @@ #include #include +#include namespace llmr { @@ -73,7 +74,7 @@ public: std::string name; std::shared_ptr source; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; StyleBucketRender render = std::false_type(); }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index cdfd61094e..29a41fb141 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -39,7 +39,6 @@ private: void parseRasterize(JSVal value, std::shared_ptr &layer); void parseReference(JSVal value, std::shared_ptr &layer); void parseBucket(JSVal value, std::shared_ptr &layer); - void parseFilter(JSVal value, std::shared_ptr &layer); void parseRender(JSVal value, std::shared_ptr &layer); // Parses optional properties into a render bucket. @@ -54,9 +53,11 @@ private: template bool parseStyleProperty(const char *property_name, const std::vector &keys, ClassProperties &klass, JSVal value); -// PropertyFilterExpression parseFilterOrExpression(JSVal value); -// Value parseValue(JSVal value); -// + + FilterExpression parseFilter(JSVal, FilterExpression::Operator op); + FilterExpression parseFilter(JSVal); + Value parseValue(JSVal value); + std::forward_list parseValues(JSVal values); private: std::unordered_map constants; diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp index 8734386253..bdcba4cad3 100644 --- a/include/llmr/style/value.hpp +++ b/include/llmr/style/value.hpp @@ -62,6 +62,8 @@ template <> struct string_to_number { template struct relaxed_operator_visitor { + typedef bool result_type; + bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); } template ::value>::type> @@ -114,23 +116,23 @@ struct relaxed_less_equal_operator { } // end namespace detail inline bool relaxed_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_greater(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_less(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); + return apply_visitor(detail::relaxed_operator_visitor(), lhs, rhs); } } diff --git a/include/llmr/util/recursive_wrapper.hpp b/include/llmr/util/recursive_wrapper.hpp index 557b576c03..b87dc5699a 100644 --- a/include/llmr/util/recursive_wrapper.hpp +++ b/include/llmr/util/recursive_wrapper.hpp @@ -1,19 +1,15 @@ -#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP -#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP #include -namespace llmr { - -namespace util { +namespace llmr { namespace util { template class recursive_wrapper { public: - - typedef T type; - + using type = T; private: T* p_; @@ -34,19 +30,19 @@ private: public: - recursive_wrapper& operator=(const recursive_wrapper& rhs) + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) { assign( rhs.get() ); return *this; } - recursive_wrapper& operator=(const T& rhs) + inline recursive_wrapper& operator=(T const& rhs) { assign( rhs ); return *this; } - void swap(recursive_wrapper& operand) noexcept + inline void swap(recursive_wrapper& operand) noexcept { T* temp = operand.p_; operand.p_ = p_; @@ -71,10 +67,10 @@ public: T& get() { return *get_pointer(); } const T& get() const { return *get_pointer(); } - T* get_pointer() { return p_; } const T* get_pointer() const { return p_; } - + operator T const&() const { return this->get(); } + operator T&() { return this->get(); } }; template @@ -103,8 +99,9 @@ recursive_wrapper::recursive_wrapper(T const& operand) template recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) - : p_(new T( std::move(operand.get()) )) + : p_(operand.p_) { + operand.p_ = nullptr; } template @@ -125,8 +122,6 @@ inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept lhs.swap(rhs); } -} - -} +}} -#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/include/llmr/util/variant.hpp b/include/llmr/util/variant.hpp index b887ae494d..57f8593439 100644 --- a/include/llmr/util/variant.hpp +++ b/include/llmr/util/variant.hpp @@ -1,5 +1,5 @@ -#ifndef UTIL_VARIANT_HPP -#define UTIL_VARIANT_HPP +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP #include #include @@ -9,50 +9,119 @@ #include // operator new #include // size_t #include +#include -#ifdef NDEBUG -#define VARIANT_INLINE inline __attribute__((always_inline)) +#include "recursive_wrapper.hpp" + +#ifdef _MSC_VER + // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + #ifdef NDEBUG + #define VARIANT_INLINE __forceinline + #else + #define VARIANT_INLINE __declspec(noinline) + #endif #else -#define VARIANT_INLINE __attribute__((noinline)) + #ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) + #else + #define VARIANT_INLINE __attribute__((noinline)) + #endif #endif -namespace llmr { +#define VARIANT_MAJOR_VERSION 0 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 -namespace util { +// translates to 100 +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) -namespace detail { +namespace llmr { namespace util { namespace detail { static constexpr std::size_t invalid_value = std::size_t(-1); template -struct type_traits; +struct direct_type; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = std::is_same::value ? sizeof...(Types) : type_traits::id; + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) : direct_type::index; }; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = invalid_value; + static constexpr std::size_t index = invalid_value; +}; + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? sizeof...(Types) : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type::index : direct_index; }; template struct is_valid_type; template -struct is_valid_type +struct is_valid_type { - static constexpr bool value = std::is_same::value - || is_valid_type::value; + static constexpr bool value = std::is_convertible::value + || is_valid_type::value; }; template struct is_valid_type : std::false_type {}; -} +template +struct select_type +{ + static_assert(N < sizeof...(Types), "index out of bounds"); +}; + +template +struct select_type +{ + using type = typename select_type::type; +}; + +template +struct select_type<0, T, Types...> +{ + using type = T; +}; + +} // namespace detail + +// static visitor +template +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + template struct static_max; @@ -125,37 +194,77 @@ template<> struct variant_helper<> namespace detail { +template +struct unwrapper +{ + T const& operator() (T const& obj) const + { + return obj; + } + + T& operator() (T & obj) const + { + return obj; + } +}; + + +template +struct unwrapper> +{ + auto operator() (recursive_wrapper const& obj) const + -> typename recursive_wrapper::type const& + { + return obj.get(); + } +}; + + template struct dispatcher; template -struct dispatcher +struct dispatcher { - typedef typename std::result_of::type result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper()(v. template get())); + } + else + { + return dispatcher::apply_const(v, f); + } + } - VARIANT_INLINE static result_type apply(V const& v, F f) + VARIANT_INLINE static result_type apply(V & v, F f) { - if (v.get_type_id() == sizeof...(Types)) + if (v.get_type_index() == sizeof...(Types)) { - return f(v. template get()); + return f(unwrapper()(v. template get())); } else { - return dispatcher::apply(v, f); + return dispatcher::apply(v, f); } } }; -template -struct dispatcher +template +struct dispatcher { - typedef typename std::result_of::type result_type; - - VARIANT_INLINE static result_type apply(V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, F) { - throw std::runtime_error("unary dispatch: FAIL"); + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); } + VARIANT_INLINE static result_type apply(V &, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } }; @@ -163,28 +272,46 @@ template struct binary_dispatcher_rhs; template -struct binary_dispatcher_rhs +struct binary_dispatcher_rhs { - typedef typename std::result_of::type result_type; - VARIANT_INLINE static result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); + } + else + { + return binary_dispatcher_rhs::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) { - if (rhs.get_type_id() == sizeof...(Types)) // call binary functor + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(lhs. template get(), rhs. template get()); + return f(unwrapper()(lhs. template get()), + unwrapper()(rhs. template get())); } else { - return binary_dispatcher_rhs::apply(lhs, rhs, f); + return binary_dispatcher_rhs::apply(lhs, rhs, f); } } + }; -template -struct binary_dispatcher_rhs +template +struct binary_dispatcher_rhs { - typedef typename std::result_of::type result_type; - - VARIANT_INLINE static result_type apply(V const&, V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -195,28 +322,45 @@ template struct binary_dispatcher_lhs; template -struct binary_dispatcher_lhs +struct binary_dispatcher_lhs { - typedef typename std::result_of::type binary_result_type; - VARIANT_INLINE static binary_result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { - if (lhs.get_type_id() == sizeof...(Types)) // call binary functor + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor { return f(lhs. template get(), rhs. template get()); } else { - return binary_dispatcher_lhs::apply(lhs, rhs, f); + return binary_dispatcher_lhs::apply_const(lhs, rhs, f); } } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get(), rhs. template get()); + } + else + { + return binary_dispatcher_lhs::apply(lhs, rhs, f); + } + } + }; -template -struct binary_dispatcher_lhs +template +struct binary_dispatcher_lhs { - typedef typename std::result_of::type result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -226,37 +370,60 @@ template struct binary_dispatcher; template -struct binary_dispatcher +struct binary_dispatcher { - typedef typename std::result_of::type binary_result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get(), v1. template get()); // call binary functor + } + else + { + return binary_dispatcher_rhs::apply_const(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs::apply_const(v0, v1, f); + } + return binary_dispatcher::apply_const(v0, v1, f); + } - VARIANT_INLINE static binary_result_type apply(V const& v0, V const& v1, F f) + VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) { - if (v0.get_type_id() == sizeof...(Types)) + if (v0.get_type_index() == sizeof...(Types)) { - if (v0.get_type_id() == v1.get_type_id()) + if (v0.get_type_index() == v1.get_type_index()) { return f(v0. template get(), v1. template get()); // call binary functor } else { - return binary_dispatcher_rhs::apply(v0, v1, f); + return binary_dispatcher_rhs::apply(v0, v1, f); } } - else if (v1.get_type_id() == sizeof...(Types)) + else if (v1.get_type_index() == sizeof...(Types)) { - return binary_dispatcher_lhs::apply(v0, v1, f); + return binary_dispatcher_lhs::apply(v0, v1, f); } - return binary_dispatcher::apply(v0, v1, f); + return binary_dispatcher::apply(v0, v1, f); } }; -template -struct binary_dispatcher +template +struct binary_dispatcher { - typedef typename std::result_of::type binary_result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static binary_result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -275,19 +442,19 @@ struct equal_comp struct less_comp { template - bool operator()(const T& lhs, const T& rhs) const + bool operator()(T const& lhs, T const& rhs) const { return lhs < rhs; } }; template -class comparer +class comparer : public static_visitor { public: explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) {} - comparer& operator=(const comparer&) = delete; + comparer& operator=(comparer const&) = delete; // visitor template bool operator()(T const& rhs_content) const @@ -301,16 +468,16 @@ private: // operator<< helper template -class printer +class printer : public static_visitor<> { public: explicit printer(Out & out) : out_(out) {} - printer& operator=(printer const &) = delete; + printer& operator=(printer const&) = delete; // visitor template - void operator()( T const & operand) const + void operator()(T const& operand) const { out_ << operand; } @@ -318,7 +485,7 @@ private: Out & out_; }; -} // detail +} // namespace detail template class variant @@ -329,81 +496,106 @@ private: static const std::size_t data_align = static_max::value; using data_type = typename std::aligned_storage::type; - using helper_type = variant_helper; - std::size_t type_id; + std::size_t type_index; data_type data; public: VARIANT_INLINE variant() - : type_id(detail::invalid_value) {} + : type_index(sizeof...(Types) - 1) + { + new (&data) typename detail::select_type<0, Types...>::type(); + } - template + template ::value>::type> VARIANT_INLINE explicit variant(T const& val) noexcept - : type_id(detail::type_traits::id) + : type_index(detail::value_traits::index) { - static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); - new (&data) T(val); + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(val); } - template + template ::value>::type> VARIANT_INLINE variant(T && val) noexcept - : type_id(detail::type_traits::id) + : type_index(detail::value_traits::index) { - static_assert(detail::is_valid_type::value, "Not a valid type for this variant"); - new (&data) T(std::forward(val)); // nothrow + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(std::forward(val)); // nothrow } VARIANT_INLINE variant(variant const& old) - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::copy(old.type_id, &old.data, &data); + helper_type::copy(old.type_index, &old.data, &data); } VARIANT_INLINE variant(variant&& old) noexcept - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::move(old.type_id, &old.data, &data); + helper_type::move(old.type_index, &old.data, &data); } friend void swap(variant & first, variant & second) { using std::swap; //enable ADL - swap(first.type_id, second.type_id); + swap(first.type_index, second.type_index); swap(first.data, second.data); } - VARIANT_INLINE variant& operator= (variant other) + VARIANT_INLINE variant& operator=(variant other) { swap(*this, other); return *this; } + // conversions + // move-assign + template + VARIANT_INLINE variant& operator=(T && rhs) noexcept + { + variant temp(std::move(rhs)); + swap(*this, temp); + return *this; + } + + // copy-assign + template + VARIANT_INLINE variant& operator=(T const& rhs) + { + variant temp(rhs); + swap(*this, temp); + return *this; + } + template VARIANT_INLINE bool is() const { - return (type_id == detail::type_traits::id); + return (type_index == detail::direct_type::index); } VARIANT_INLINE bool valid() const { - return (type_id != detail::invalid_value); + return (type_index != detail::invalid_value); } template VARIANT_INLINE void set(Args&&... args) { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); new (&data) T(std::forward(args)...); - type_id = detail::type_traits::id; + type_index = detail::direct_type::index; } template VARIANT_INLINE T& get() { - if (type_id == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); } @@ -416,7 +608,7 @@ public: template VARIANT_INLINE T const& get() const { - if (type_id == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); } @@ -426,37 +618,57 @@ public: } } - VARIANT_INLINE std::size_t get_type_id() const + VARIANT_INLINE std::size_t get_type_index() const { - return type_id; + return type_index; } // visitor // unary template - typename std::result_of::type - VARIANT_INLINE static visit(V const& v, F f) + auto VARIANT_INLINE + static visit(V const& v, F f) + -> decltype(detail::dispatcher::apply_const(v, f)) + { + return detail::dispatcher::apply_const(v, f); + } + // non-const + template + auto VARIANT_INLINE + static visit(V & v, F f) + -> decltype(detail::dispatcher::apply(v, f)) { return detail::dispatcher::apply(v, f); } + // binary + // const + template + auto VARIANT_INLINE + static binary_visit(V const& v0, V const& v1, F f) + -> decltype(detail::binary_dispatcher::apply_const(v0, v1, f)) + { + return detail::binary_dispatcher::apply_const(v0, v1, f); + } + // non-const template - typename std::result_of::type - VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F f) + auto VARIANT_INLINE + static binary_visit(V& v0, V& v1, F f) + -> decltype(detail::binary_dispatcher::apply(v0, v1, f)) { return detail::binary_dispatcher::apply(v0, v1, f); } ~variant() noexcept { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); } // comparison operators // equality VARIANT_INLINE bool operator==(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) return false; detail::comparer visitor(*this); return visit(rhs, visitor); @@ -464,9 +676,9 @@ public: // less than VARIANT_INLINE bool operator<(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) { - return this->get_type_id() < rhs.get_type_id(); + return this->get_type_index() < rhs.get_type_index(); // ^^ borrowed from boost::variant } detail::comparer visitor(*this); @@ -475,17 +687,30 @@ public: }; // unary visitor interface + +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} +// non-const template -typename std::result_of::type -VARIANT_INLINE static apply_visitor(V const& v, F f) +auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) { - return V::visit(v,f); + return V::visit(v, f); } // binary visitor interface +// const +template +auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} +// non-const template -typename std::result_of::type -VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) +auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) { return V::binary_visit(v0, v1, f); } @@ -493,14 +718,14 @@ VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) // operator<< template -VARIANT_INLINE std::basic_ostream& -operator<< (std::basic_ostream& out, Variant const& rhs) +VARIANT_INLINE std::basic_ostream& +operator<< (std::basic_ostream& out, Variant const& rhs) { - detail::printer > visitor(out); - apply_visitor(rhs, visitor); + detail::printer> visitor(out); + apply_visitor(visitor, rhs); return out; } -} -} -#endif // UTIL_VARIANT_HPP +}} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/src/map/filter_expression.cpp b/src/map/filter_expression.cpp new file mode 100644 index 0000000000..9e293b0026 --- /dev/null +++ b/src/map/filter_expression.cpp @@ -0,0 +1,282 @@ +#include +#include + +namespace llmr { + + +template +inline bool FilterComparison::Instance::includes(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (comparer(property_value, filter_value)) { + return true; + } + } + return false; +} + +template +inline bool FilterComparison::Instance::compare(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (!comparer(property_value, filter_value)) { + return false; + } + } + return true; +} + +template +inline bool FilterComparison::Instance::all(const std::forward_list &property_values, const Comparer &comparer) const { + for (const Value &property_value : property_values) { + if (!compare(property_value, comparer)) { + return false; + } + } + return true; +} + + + +bool FilterComparison::Instance::compare(const Value &property_value) const { + switch (op) { + case Operator::Equal: + case Operator::In: + return includes(property_value, util::relaxed_equal); + case Operator::NotEqual: + case Operator::NotIn: + return !includes(property_value, util::relaxed_equal); + case Operator::Greater: + return compare(property_value, util::relaxed_greater); + case Operator::GreaterEqual: + return compare(property_value, util::relaxed_greater_equal); + case Operator::Less: + return compare(property_value, util::relaxed_less); + case Operator::LessEqual: + return compare(property_value, util::relaxed_less_equal); + default: + return false; + } +} + +bool FilterComparison::Instance::compare(const std::forward_list &property_values) const { + switch (op) { + case Operator::Equal: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::NotEqual: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::In: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::NotIn: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::Greater: + return all(property_values, util::relaxed_greater); + case Operator::GreaterEqual: + return all(property_values, util::relaxed_greater_equal); + case Operator::Less: + return all(property_values, util::relaxed_less); + case Operator::LessEqual: + return all(property_values, util::relaxed_less_equal); + } +} + + +const std::string &FilterComparison::getField() const { + return field; +} + +inline bool FilterComparison::compare(const VectorTileTagExtractor &extractor) const { + const std::forward_list values = extractor.getValues(field); + + // All instances are ANDed together. + for (const Instance &instance : instances) { + if (!instance.compare(values)) { + return false; + } + } + return true; +} + + + +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison) { + s << "comparison" << std::endl; + for (const FilterComparison::Instance &instance : comparison.instances) { + s << " - " << comparison.field << " " << instance << std::endl; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance) { + switch (instance.op) { + case FilterComparison::Operator::Equal: s << "=="; break; + case FilterComparison::Operator::NotEqual: s << "!="; break; + case FilterComparison::Operator::Greater: s << ">"; break; + case FilterComparison::Operator::GreaterEqual: s << ">="; break; + case FilterComparison::Operator::Less: s << "<"; break; + case FilterComparison::Operator::LessEqual: s << "<="; break; + case FilterComparison::Operator::In: s << "in"; break; + case FilterComparison::Operator::NotIn: s << "!in"; break; + } + + s << " [ "; + for (const Value &value : instance.values) { + s << toString(value) << " "; + } + s << "]"; + return s; +} + + +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op) { + if (op == "==") return FilterComparison::Operator::Equal; + if (op == "!=") return FilterComparison::Operator::NotEqual; + if (op == ">") return FilterComparison::Operator::Greater; + if (op == ">=") return FilterComparison::Operator::GreaterEqual; + if (op == "<") return FilterComparison::Operator::Less; + if (op == "<=") return FilterComparison::Operator::LessEqual; + if (op == "in") return FilterComparison::Operator::In; + if (op == "!in") return FilterComparison::Operator::NotIn; + return FilterComparison::Operator::Equal; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::Operator op) { + switch (op) { + case FilterExpression::Operator::And: s << "AND"; break; + case FilterExpression::Operator::Or: s << "OR"; break; + case FilterExpression::Operator::Xor: s << "XOR"; break; + case FilterExpression::Operator::Nor: s << "NOR"; break; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) { + switch (type) { + case FilterExpression::GeometryType::Point: s << "point"; break; + case FilterExpression::GeometryType::Line: s << "line"; break; + case FilterExpression::GeometryType::Polygon: s << "polygon"; break; + case FilterExpression::GeometryType::Any: s << "any"; break; + } + return s; +} + + + +bool FilterExpression::compare(const VectorTileTagExtractor &extractor) const { + if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) { + return false; + } + + switch (op) { + case Operator::And: + for (const FilterComparison &comparison : comparisons) { + if (!comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (!expression.compare(extractor)) { + return false; + } + } + return true; + case Operator::Or: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return true; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return true; + } + } + return false; + case Operator::Xor: { + int count = 0; + for (const FilterComparison &comparison : comparisons) { + count += comparison.compare(extractor); + if (count > 1) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + count += expression.compare(extractor); + if (count > 1) { + return false; + } + } + return count == 1; + } + case Operator::Nor: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return false; + } + } + return true; + default: + return true; + } +} + +bool FilterExpression::empty() const { + return type == GeometryType::Any && comparisons.empty() && expressions.empty(); +} + +void FilterExpression::add(const FilterComparison &comparison) { + comparisons.emplace_front(comparison); +} + +void FilterExpression::add(const FilterExpression &expression) { + expressions.emplace_front(expression); +} + +void FilterExpression::setGeometryType(GeometryType g) { + type = g; +} + +FilterExpression::GeometryType parseGeometryType(const std::string &geometry) { + if (geometry == "point") return FilterExpression::GeometryType::Point; + if (geometry == "line") return FilterExpression::GeometryType::Line; + if (geometry == "polygon") return FilterExpression::GeometryType::Polygon; + return FilterExpression::GeometryType::Any; +} + +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression) { + s << "expression " << expression.op << std::endl; + s << " - $type = " << expression.type << std::endl; + for (const FilterComparison &comparison : expression.comparisons) { + s << comparison; + } + s << "end expression" << std::endl; + return s; +} + +} diff --git a/src/map/map.cpp b/src/map/map.cpp index 01f7ac6072..db94ca97db 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -169,8 +169,6 @@ void Map::setup() { view.make_active(); painter.setup(); - - setStyleJSON(styleJSON); } void Map::setStyleJSON(std::string newStyleJSON) { diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index b4041ada4e..e834e6fa95 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -132,7 +132,7 @@ std::unique_ptr TileParser::createBucket(std::shared_ptr bu } template -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) { FilteredVectorTileLayer filtered_layer(layer, filter); for (pbf feature : filtered_layer) { if (obsolete()) @@ -150,7 +150,7 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } template -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) { FilteredVectorTileLayer filtered_layer(layer, filter); for (const pbf &feature_pbf : filtered_layer) { if (obsolete()) { @@ -161,25 +161,25 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } -std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) { +std::unique_ptr TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill) { std::unique_ptr bucket = std::make_unique(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill); addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line) { +std::unique_ptr TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line) { std::unique_ptr bucket = std::make_unique(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line); addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon) { +std::unique_ptr TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon) { std::unique_ptr bucket = std::make_unique(tile.iconVertexBuffer, icon); addBucketFeatures(bucket, layer, filter, *spriteAtlas); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) { +std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) { const StyleBucketText &properties = text; @@ -235,9 +235,3 @@ std::unique_ptr TileParser::createTextBucket(const VectorTileLayer& laye return std::move(bucket); } - - - - -//typedef std::pair GlyphRange; -// diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 24f03e1a97..54a971cd87 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -102,7 +102,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } } -FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression) +FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression) : layer(layer), filterExpression(filterExpression) { } @@ -122,120 +122,167 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren operator++(); } -bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) { - if (filterExpression.is>()) { - return matchesFilter(filterExpression.get>().get(), tags_pbf); - } else if (filterExpression.is>()) { - return matchesExpression(filterExpression.get>().get(), tags_pbf); - } else if (filterExpression.is()) { - return true; - } else { - return false; - } +//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) { +// if (filterExpression.empty()) { +// return true; +// } +// +// +// +// +// if (filterExpression.is>()) { +// return matchesFilter(filterExpression.get>().get(), tags_pbf); +// } else if (filterExpression.is>()) { +// return matchesExpression(filterExpression.get>().get(), tags_pbf); +// } else if (filterExpression.is()) { +// return true; +// } else { +// return false; +// } +// return true; +//} + +// +//bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { +// auto field_it = parent.layer.key_index.find(filter.field); +// if (field_it != parent.layer.key_index.end()) { +// const uint32_t filter_key = field_it->second; +// +// // Now loop through all the key/value pair tags. +// // tags are packed varints. They should have an even length. +// pbf tags_pbf = const_tags_pbf; +// while (tags_pbf) { +// uint32_t tag_key = tags_pbf.varint(); +// if (!tags_pbf) { +// // This should not happen; otherwise the vector tile +// // is invalid. +// throw std::runtime_error("uneven number of feature tag ids"); +// } +// uint32_t tag_val = tags_pbf.varint(); +// +// if (tag_key == filter_key) { +// if (parent.layer.values.size() > tag_val) { +// const Value &value = parent.layer.values[tag_val]; +// return filter.compare(value); +// } else { +// throw std::runtime_error("feature references out of range value"); +// } +// } +// } +// } +// +// // The feature doesn't contain the field that we're looking to compare. +// // Depending on the filter, this may still be okay. +// return filter.isMissingFieldOkay(); +//} +// +//bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { +// if (expression.op == ExpressionOperator::Or) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (matchesFilterExpression(filterExpression, tags_pbf)) { +// return true; +// } +// } +// return false; +// } else if (expression.op == ExpressionOperator::And) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (!matchesFilterExpression(filterExpression, tags_pbf)) { +// return false; +// } +// } +// return true; +// } else { +// return false; +// } +//} +// + +VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {} + + +void VectorTileTagExtractor::setTags(const pbf &pbf) { + tags_ = pbf; } +std::forward_list VectorTileTagExtractor::getValues(const std::string &key) const { + std::forward_list values; -bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { - auto field_it = parent.layer.key_index.find(filter.field); - if (field_it != parent.layer.key_index.end()) { + auto field_it = layer_.key_index.find(key); + if (field_it != layer_.key_index.end()) { + auto it = values.before_begin(); const uint32_t filter_key = field_it->second; // Now loop through all the key/value pair tags. // tags are packed varints. They should have an even length. - pbf tags_pbf = const_tags_pbf; + pbf tags_pbf = tags_; + uint32_t tag_key, tag_val; while (tags_pbf) { - uint32_t tag_key = tags_pbf.varint(); + tag_key = tags_pbf.varint(); if (!tags_pbf) { - // This should not happen; otherwise the vector tile - // is invalid. - throw std::runtime_error("uneven number of feature tag ids"); + // This should not happen; otherwise the vector tile is invalid. + fprintf(stderr, "[WARNING] uneven number of feature tag ids\n"); + return values; } - uint32_t tag_val = tags_pbf.varint(); + // Note: We need to run this command in all cases, even if the keys don't match. + tag_val = tags_pbf.varint(); if (tag_key == filter_key) { - if (parent.layer.values.size() > tag_val) { - const Value &value = parent.layer.values[tag_val]; - return filter.compare(value); + if (layer_.values.size() > tag_val) { + it = values.emplace_after(it, layer_.values[tag_val]); } else { - throw std::runtime_error("feature references out of range value"); + fprintf(stderr, "[WARNING] feature references out of range value\n"); + break; } } } } - // The feature doesn't contain the field that we're looking to compare. - // Depending on the filter, this may still be okay. - return filter.isMissingFieldOkay(); + return values; } -bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { - if (expression.op == ExpressionOperator::Or) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (matchesFilterExpression(filterExpression, tags_pbf)) { - return true; - } - } - return false; - } else if (expression.op == ExpressionOperator::And) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (!matchesFilterExpression(filterExpression, tags_pbf)) { - return false; - } - } - return true; - } else { - return false; - } +void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) { + type_ = type; } - +FilterExpression::GeometryType VectorTileTagExtractor::getType() const { + return type_; +} void FilteredVectorTileLayer::iterator::operator++() { valid = false; - const PropertyFilterExpression &expression = parent.filterExpression; + const FilterExpression &expression = parent.filterExpression; while (data.next(2)) { // feature feature = data.message(); pbf feature_pbf = feature; - BucketType type = BucketType::None; - bool matched = false; // Treat the absence of any expression filters as a match. - if (!expression.valid() || expression.is()) { + if (expression.empty()) { matched = true; } - while (feature_pbf.next()) { - if (feature_pbf.tag == 2) { // tags - if (matched) { - // There is no filter, so we want to parse the entire layer anyway. - feature_pbf.skip(); - } else { - // We only want to parse some features. - const pbf tags_pbf = feature_pbf.message(); - matched = matchesFilterExpression(expression, tags_pbf); - if (!matched) { - break; // feature_pbf loop early + if (!matched) { + VectorTileTagExtractor extractor(parent.layer); + + // Retrieve the basic information + while (feature_pbf.next()) { + if (feature_pbf.tag == 2) { // tags + extractor.setTags(feature_pbf.message()); + } else if (feature_pbf.tag == 3) { // geometry type + switch (FeatureType(feature_pbf.varint())) { + case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break; + case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break; + case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break; + default: break; } + } else { + feature_pbf.skip(); } - } else if (feature_pbf.tag == 3) { // geometry type - switch (feature_pbf.varint()) { - case 1 /* Point */: type = BucketType::Icon; break; - case 2 /* LineString */: type = BucketType::Line; break; - case 3 /* Polygon */: type = BucketType::Fill; break; - default: type = BucketType::None; break; - } - - // TODO: Parse feature type -// if (type != parent.bucket_desc.feature_type) { -// matched = false; -// break; // feature_pbf loop early -// } - } else { - feature_pbf.skip(); } + + matched = expression.compare(extractor); } if (matched) { diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 390096e9de..34aa7f2228 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -622,7 +622,7 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr &layer) { if (value.HasMember("filter")) { JSVal value_filter = replaceConstant(value["filter"]); - parseFilter(value_filter, layer); + layer->bucket->filter = parseFilter(value_filter); } if (value.HasMember("render")) { @@ -631,8 +631,92 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr &layer) { } } -void StyleParser::parseFilter(JSVal value, std::shared_ptr &layer) { - // TODO +FilterExpression StyleParser::parseFilter(JSVal value) { + return parseFilter(value, value.IsArray() ? FilterExpression::Operator::Or : FilterExpression::Operator::And); +} + +FilterExpression StyleParser::parseFilter(JSVal value, FilterExpression::Operator op) { + FilterExpression expression(op); + if (value.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); + for (; itr != value.MemberEnd(); ++itr) { + const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + if (name == "&") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::And)); + } else if (name == "|") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Or)); + } else if (name == "^") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Xor)); + } else if (name == "!") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Nor)); + } else if (name == "$type") { + JSVal type = replaceConstant(itr->value); + if (type.IsString()) { + expression.setGeometryType(parseGeometryType({ type.GetString(), type.GetStringLength() })); + } + } else { + FilterComparison comparison(name); + JSVal filterValue = replaceConstant(itr->value); + if (filterValue.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = filterValue.MemberBegin(); + for (; itr != filterValue.MemberEnd(); ++itr) { + comparison.add( + parseFilterComparisonOperator({ itr->name.GetString(), itr->name.GetStringLength() }), + parseValues(replaceConstant(itr->value)) + ); + } + } else if (filterValue.IsArray()) { + comparison.add(FilterComparison::Operator::In, parseValues(filterValue)); + } else { + comparison.add(FilterComparison::Operator::Equal, std::forward_list({ parseValue(filterValue) })); + } + expression.add(comparison); + } + } + } else if (value.IsArray()) { + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + expression.add(parseFilter(replaceConstant(value[i]))); + } + } else { + fprintf(stderr, "[WARNING] expression must be either an array or an object\n"); + } + + return expression; +} + +Value StyleParser::parseValue(JSVal value) { + switch (value.GetType()) { + case rapidjson::kNullType: + case rapidjson::kFalseType: + return false; + + case rapidjson::kTrueType: + return true; + + case rapidjson::kStringType: + return std::string { value.GetString(), value.GetStringLength() }; + + case rapidjson::kNumberType: + if (value.IsUint64()) return value.GetUint64(); + if (value.IsInt64()) return value.GetInt64(); + return value.GetDouble(); + + default: + return false; + } +} + +std::forward_list StyleParser::parseValues(JSVal value) { + std::forward_list values; + if (value.IsArray()) { + auto it = values.before_begin(); + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + it = values.emplace_after(it, parseValue(replaceConstant(value[i]))); + } + } else { + values.emplace_front(parseValue(value)); + } + return values; } void StyleParser::parseRender(JSVal value, std::shared_ptr &layer) { @@ -724,79 +808,4 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr &layer) { } } -//PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) { -// if (value.IsArray()) { -// // This is an expression. -// util::recursive_wrapper expression; -// for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { -// JSVal filter_item = value[i]; -// -// if (filter_item.IsString()) { -// expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() }); -// } else { -// expression.get().operands.emplace_back(parseFilterOrExpression(filter_item)); -// } -// } -// return std::move(expression); -// } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) { -// // This is a filter. -// JSVal field = value["field"]; -// JSVal val = value["value"]; -// -// if (!field.IsString()) { -// throw Style::exception("field name must be a string"); -// } -// -// const std::string field_name { field.GetString(), field.GetStringLength() }; -// const FilterOperator op = [&]{ -// if (value.HasMember("operator")) { -// JSVal op_val = value["operator"]; -// return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() }); -// } else { -// return FilterOperator::Equal; -// } -// }(); -// -// if (val.IsArray()) { -// // The filter has several values, so it's an OR sub-expression. -// util::recursive_wrapper expression; -// for (rapidjson::SizeType i = 0; i < val.Size(); ++i) { -// expression.get().operands.emplace_back(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val[i]) })); -// } -// -// return std::move(expression); -// } else { -// // The filter only has a single value, so it is a real filter. -// return std::move(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val) })); -// } -// } -// -// return std::true_type(); - -//Value StyleParser::parseValue(JSVal value) { -// switch (value.GetType()) { -// case rapidjson::kNullType: -// case rapidjson::kFalseType: -// return false; -// -// case rapidjson::kTrueType: -// return true; -// -// case rapidjson::kStringType: -// return std::string { value.GetString(), value.GetStringLength() }; -// -// case rapidjson::kNumberType: -// if (value.IsUint64()) return value.GetUint64(); -// if (value.IsInt64()) return value.GetInt64(); -// return value.GetDouble(); -// -// case rapidjson::kObjectType: -// case rapidjson::kArrayType: -// throw Style::exception("value cannot be an object or array"); -// return false; -// } -// throw Style::exception("unhandled value type in style"); -// return false; -//} - } -- cgit v1.2.1