diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/mbgl/style/conversion/filter.hpp | 144 | ||||
-rw-r--r-- | include/mbgl/style/filter.hpp | 101 | ||||
-rw-r--r-- | include/mbgl/style/filter_evaluator.hpp | 92 |
3 files changed, 287 insertions, 50 deletions
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 3ab91e5bbc..2c4eeb4ac7 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -27,9 +27,9 @@ public: } if (*op == "==") { - return convertBinaryFilter<EqualsFilter>(value); + return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value); } else if (*op == "!=") { - return convertBinaryFilter<NotEqualsFilter>(value); + return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value); } else if (*op == ">") { return convertBinaryFilter<GreaterThanFilter>(value); } else if (*op == ">=") { @@ -39,9 +39,9 @@ public: } else if (*op == "<=") { return convertBinaryFilter<LessThanEqualsFilter>(value); } else if (*op == "in") { - return convertSetFilter<InFilter>(value); + return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value); } else if (*op == "!in") { - return convertSetFilter<NotInFilter>(value); + return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value); } else if (*op == "all") { return convertCompoundFilter<AllFilter>(value); } else if (*op == "any") { @@ -49,32 +49,57 @@ public: } else if (*op == "none") { return convertCompoundFilter<NoneFilter>(value); } else if (*op == "has") { - return convertUnaryFilter<HasFilter>(value); + return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value); } else if (*op == "!has") { - return convertUnaryFilter<NotHasFilter>(value); + return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value); } return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" }; } private: - Result<Value> normalizeValue(const std::string& key, const optional<Value>& value) const { + Result<Value> normalizeValue(const optional<Value>& value) const { if (!value) { return Error { "filter expression value must be a boolean, number, or string" }; - } else if (key != "$type") { + } else { return *value; - } else if (*value == std::string("Point")) { - return Value(uint64_t(FeatureType::Point)); - } else if (*value == std::string("LineString")) { - return Value(uint64_t(FeatureType::LineString)); - } else if (*value == std::string("Polygon")) { - return Value(uint64_t(FeatureType::Polygon)); + } + } + + template <class V> + Result<FeatureType> toFeatureType(const V& value) const { + optional<std::string> type = toString(value); + if (!type) { + return Error { "value for $type filter must be a string" }; + } else if (*type == "Point") { + return FeatureType::Point; + } else if (*type == "LineString") { + return FeatureType::LineString; + } else if (*type == "Polygon") { + return FeatureType::Polygon; } else { return Error { "value for $type filter must be Point, LineString, or Polygon" }; } } - template <class FilterType, class V> + template <class V> + Result<FeatureIdentifier> toFeatureIdentifier(const V& value) const { + optional<Value> identifier = toValue(value); + if (!identifier) { + return Error { "filter expression value must be a boolean, number, or string" }; + } else { + return (*identifier).match( + [] (uint64_t t) -> Result<FeatureIdentifier> { return t; }, + [] ( int64_t t) -> Result<FeatureIdentifier> { return t; }, + [] ( double t) -> Result<FeatureIdentifier> { return t; }, + [] (const std::string& t) -> Result<FeatureIdentifier> { return t; }, + [] (const auto&) -> Result<FeatureIdentifier> { + return Error { "filter expression value must be a boolean, number, or string" }; + }); + } + } + + template <class FilterType, class IdentifierFilterType, class V> Result<Filter> convertUnaryFilter(const V& value) const { if (arrayLength(value) < 2) { return Error { "filter expression must have 2 elements" }; @@ -85,7 +110,48 @@ private: return Error { "filter expression key must be a string" }; } - return FilterType { *key }; + if (*key == "$id") { + return IdentifierFilterType {}; + } else { + return FilterType { *key }; + } + } + + template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V> + Result<Filter> convertEqualityFilter(const V& value) const { + if (arrayLength(value) < 3) { + return Error { "filter expression must have 3 elements" }; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + return Error { "filter expression key must be a string" }; + } + + if (*key == "$type") { + Result<FeatureType> filterValue = toFeatureType(arrayMember(value, 2)); + if (!filterValue) { + return filterValue.error(); + } + + return TypeFilterType { *filterValue }; + + } else if (*key == "$id") { + Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2)); + if (!filterValue) { + return filterValue.error(); + } + + return IdentifierFilterType { *filterValue }; + + } else { + Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2))); + if (!filterValue) { + return filterValue.error(); + } + + return FilterType { *key, *filterValue }; + } } template <class FilterType, class V> @@ -99,7 +165,7 @@ private: return Error { "filter expression key must be a string" }; } - Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2))); + Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2))); if (!filterValue) { return filterValue.error(); } @@ -107,7 +173,7 @@ private: return FilterType { *key, *filterValue }; } - template <class FilterType, class V> + template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V> Result<Filter> convertSetFilter(const V& value) const { if (arrayLength(value) < 2) { return Error { "filter expression must at least 2 elements" }; @@ -118,16 +184,42 @@ private: return Error { "filter expression key must be a string" }; } - std::vector<Value> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, i))); - if (!filterValue) { - return filterValue.error(); + if (*key == "$type") { + std::vector<FeatureType> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result<FeatureType> filterValue = toFeatureType(arrayMember(value, i)); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); } - values.push_back(*filterValue); - } - return FilterType { *key, std::move(values) }; + return TypeFilterType { std::move(values) }; + + } else if (*key == "$id") { + std::vector<FeatureIdentifier> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i)); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); + } + + return IdentifierFilterType { std::move(values) }; + + } else { + std::vector<Value> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, i))); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); + } + + return FilterType { *key, std::move(values) }; + } } template <class FilterType, class V> diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp index e5d8081d82..5e61adf064 100644 --- a/include/mbgl/style/filter.hpp +++ b/include/mbgl/style/filter.hpp @@ -145,6 +145,95 @@ public: } }; + +class TypeEqualsFilter { +public: + FeatureType value; + + friend bool operator==(const TypeEqualsFilter& lhs, const TypeEqualsFilter& rhs) { + return lhs.value == rhs.value; + } +}; + +class TypeNotEqualsFilter { +public: + FeatureType value; + + friend bool operator==(const TypeNotEqualsFilter& lhs, const TypeNotEqualsFilter& rhs) { + return lhs.value == rhs.value; + } +}; + +class TypeInFilter { +public: + std::vector<FeatureType> values; + + friend bool operator==(const TypeInFilter& lhs, const TypeInFilter& rhs) { + return lhs.values == rhs.values; + } +}; + +class TypeNotInFilter { +public: + std::vector<FeatureType> values; + + friend bool operator==(const TypeNotInFilter& lhs, const TypeNotInFilter& rhs) { + return lhs.values == rhs.values; + } +}; + + +class IdentifierEqualsFilter { +public: + FeatureIdentifier value; + + friend bool operator==(const IdentifierEqualsFilter& lhs, const IdentifierEqualsFilter& rhs) { + return lhs.value == rhs.value; + } +}; + +class IdentifierNotEqualsFilter { +public: + FeatureIdentifier value; + + friend bool operator==(const IdentifierNotEqualsFilter& lhs, const IdentifierNotEqualsFilter& rhs) { + return lhs.value == rhs.value; + } +}; + +class IdentifierInFilter { +public: + std::vector<FeatureIdentifier> values; + + friend bool operator==(const IdentifierInFilter& lhs, const IdentifierInFilter& rhs) { + return lhs.values == rhs.values; + } +}; + +class IdentifierNotInFilter { +public: + std::vector<FeatureIdentifier> values; + + friend bool operator==(const IdentifierNotInFilter& lhs, const IdentifierNotInFilter& rhs) { + return lhs.values == rhs.values; + } +}; + +class HasIdentifierFilter { +public: + friend bool operator==(const HasIdentifierFilter&, const HasIdentifierFilter&) { + return true; + } +}; + +class NotHasIdentifierFilter { +public: + friend bool operator==(const NotHasIdentifierFilter&, const NotHasIdentifierFilter&) { + return true; + } +}; + + using FilterBase = variant< class NullFilter, class EqualsFilter, @@ -159,7 +248,17 @@ using FilterBase = variant< class AllFilter, class NoneFilter, class HasFilter, - class NotHasFilter>; + class NotHasFilter, + class TypeEqualsFilter, + class TypeNotEqualsFilter, + class TypeInFilter, + class TypeNotInFilter, + class IdentifierEqualsFilter, + class IdentifierNotEqualsFilter, + class IdentifierInFilter, + class IdentifierNotInFilter, + class HasIdentifierFilter, + class NotHasIdentifierFilter>; class Filter : public FilterBase { public: diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp index 659f554bba..370064445a 100644 --- a/include/mbgl/style/filter_evaluator.hpp +++ b/include/mbgl/style/filter_evaluator.hpp @@ -31,37 +31,37 @@ public: } bool operator()(const EqualsFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return actual && equal(*actual, filter.value); } bool operator()(const NotEqualsFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return !actual || !equal(*actual, filter.value); } bool operator()(const LessThanFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; }); } bool operator()(const LessThanEqualsFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; }); } bool operator()(const GreaterThanFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; }); } bool operator()(const GreaterThanEqualsFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; }); } bool operator()(const InFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); if (!actual) return false; for (const auto& v: filter.values) { @@ -73,7 +73,7 @@ public: } bool operator()(const NotInFilter& filter) const { - optional<Value> actual = getValue(filter.key); + optional<Value> actual = propertyAccessor(filter.key); if (!actual) return true; for (const auto& v: filter.values) { @@ -112,30 +112,76 @@ public: } bool operator()(const HasFilter& filter) const { - return bool(getValue(filter.key)); + return bool(propertyAccessor(filter.key)); } bool operator()(const NotHasFilter& filter) const { - return !getValue(filter.key); + return !propertyAccessor(filter.key); } -private: - optional<Value> getValue(const std::string& key_) const { - if (key_ == "$type") { - return optional<Value>(uint64_t(featureType)); - } else if (key_ == "$id") { - if (featureIdentifier) { - return FeatureIdentifier::visit(*featureIdentifier, [] (auto id) { - return Value(std::move(id)); - }); - } else { - return optional<Value>(); + + bool operator()(const TypeEqualsFilter& filter) const { + return featureType == filter.value; + } + + bool operator()(const TypeNotEqualsFilter& filter) const { + return featureType != filter.value; + } + + bool operator()(const TypeInFilter& filter) const { + for (const auto& v: filter.values) { + if (featureType == v) { + return true; + } + } + return false; + } + + bool operator()(const TypeNotInFilter& filter) const { + for (const auto& v: filter.values) { + if (featureType == v) { + return false; + } + } + return true; + } + + + bool operator()(const IdentifierEqualsFilter& filter) const { + return featureIdentifier == filter.value; + } + + bool operator()(const IdentifierNotEqualsFilter& filter) const { + return featureIdentifier != filter.value; + } + + bool operator()(const IdentifierInFilter& filter) const { + for (const auto& v: filter.values) { + if (featureIdentifier == v) { + return true; + } + } + return false; + } + + bool operator()(const IdentifierNotInFilter& filter) const { + for (const auto& v: filter.values) { + if (featureIdentifier == v) { + return false; } - } else { - return propertyAccessor(key_); } + return true; } + bool operator()(const HasIdentifierFilter&) const { + return bool(featureIdentifier); + } + + bool operator()(const NotHasIdentifierFilter&) const { + return !featureIdentifier; + } + +private: template <class Op> struct Comparator { const Op& op; |