Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Cherry pick expression filters #11428

Merged
merged 1 commit into from
Mar 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified benchmark/fixtures/api/cache.db
Binary file not shown.
11 changes: 4 additions & 7 deletions benchmark/parse/filter.benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/filter.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/benchmark/stub_geometry_tile_feature.hpp>

using namespace mbgl;

Expand All @@ -22,15 +23,11 @@ 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 PropertyMap properties = { { "foo", std::string("bar") } };
const StubGeometryTileFeature feature = { {}, FeatureType::Unknown , {}, {{ "foo", std::string("bar") }} };
const style::expression::EvaluationContext context = { &feature };

while (state.KeepRunning()) {
filter(FeatureType::Unknown, {}, [&] (const std::string& key) -> optional<Value> {
auto it = properties.find(key);
if (it == properties.end())
return {};
return it->second;
});
filter(context);
}
}

Expand Down
2 changes: 2 additions & 0 deletions cmake/core-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ set(MBGL_CORE_FILES
src/mbgl/style/collection.hpp
src/mbgl/style/custom_tile_loader.cpp
src/mbgl/style/custom_tile_loader.hpp
src/mbgl/style/filter.cpp
src/mbgl/style/filter_evaluator.cpp
src/mbgl/style/image.cpp
src/mbgl/style/image_impl.cpp
src/mbgl/style/image_impl.hpp
Expand Down
22 changes: 13 additions & 9 deletions include/mbgl/style/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/style/expression/expression.hpp>

#include <string>
#include <vector>
Expand Down Expand Up @@ -232,6 +233,15 @@ class NotHasIdentifierFilter {
return true;
}
};

class ExpressionFilter {
public:
std::shared_ptr<const expression::Expression> expression;

friend bool operator==(const ExpressionFilter& lhs, const ExpressionFilter& rhs) {
return *(lhs.expression) == *(rhs.expression);
}
};


using FilterBase = variant<
Expand All @@ -258,19 +268,13 @@ using FilterBase = variant<
class IdentifierInFilter,
class IdentifierNotInFilter,
class HasIdentifierFilter,
class NotHasIdentifierFilter>;
class NotHasIdentifierFilter,
class ExpressionFilter>;

class Filter : public FilterBase {
public:
using FilterBase::FilterBase;

bool operator()(const Feature&) const;

template <class GeometryTileFeature>
bool operator()(const GeometryTileFeature&) const;

template <class PropertyAccessor>
bool operator()(FeatureType type, optional<FeatureIdentifier> id, PropertyAccessor accessor) const;
bool operator()(const expression::EvaluationContext& context) const;
};

} // namespace style
Expand Down
259 changes: 27 additions & 232 deletions include/mbgl/style/filter_evaluator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,242 +19,37 @@ namespace style {
// does not match
}
*/
template <class PropertyAccessor>
class FilterEvaluator {
public:
const FeatureType featureType;
const optional<FeatureIdentifier> featureIdentifier;
const PropertyAccessor propertyAccessor;
const expression::EvaluationContext context;

bool operator()(const NullFilter&) const;
bool operator()(const EqualsFilter& filter) const;
bool operator()(const NotEqualsFilter& filter) const;
bool operator()(const LessThanFilter& filter) const;
bool operator()(const LessThanEqualsFilter& filter) const;
bool operator()(const GreaterThanFilter& filter) const;
bool operator()(const GreaterThanEqualsFilter& filter) const;
bool operator()(const InFilter& filter) const;
bool operator()(const NotInFilter& filter) const;
bool operator()(const AnyFilter& filter) const;
bool operator()(const AllFilter& filter) const;
bool operator()(const NoneFilter& filter) const;
bool operator()(const HasFilter& filter) const;
bool operator()(const NotHasFilter& filter) const;
bool operator()(const TypeEqualsFilter& filter) const;
bool operator()(const TypeNotEqualsFilter& filter) const;
bool operator()(const TypeInFilter& filter) const;
bool operator()(const TypeNotInFilter& filter) const;
bool operator()(const IdentifierEqualsFilter& filter) const;
bool operator()(const IdentifierNotEqualsFilter& filter) const;
bool operator()(const IdentifierInFilter& filter) const;
bool operator()(const IdentifierNotInFilter& filter) const;
bool operator()(const HasIdentifierFilter&) const;
bool operator()(const NotHasIdentifierFilter&) const;
bool operator()(const ExpressionFilter&) const;

bool operator()(const NullFilter&) const {
return true;
}

bool operator()(const EqualsFilter& filter) const {
optional<Value> actual = propertyAccessor(filter.key);
return actual && equal(*actual, filter.value);
}

bool operator()(const NotEqualsFilter& filter) const {
optional<Value> actual = propertyAccessor(filter.key);
return !actual || !equal(*actual, filter.value);
}

bool operator()(const LessThanFilter& filter) const {
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 = 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 = 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 = 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 = propertyAccessor(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<Value> actual = propertyAccessor(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(propertyAccessor(filter.key));
}

bool operator()(const NotHasFilter& filter) const {
return !propertyAccessor(filter.key);
}


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;
}
}
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;

template <class T>
bool operator()(const T& lhs, const T& rhs) const {
return op(lhs, rhs);
}

template <class T0, class T1>
auto operator()(const T0& lhs, const T1& rhs) const
-> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value &&
std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> {
return op(double(lhs), double(rhs));
}

template <class T0, class T1>
auto operator()(const T0&, const T1&) const
-> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value ||
!std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> {
return false;
}

bool operator()(const NullValue&,
const NullValue&) const {
// Should be unreachable; null is not currently allowed by the style specification.
assert(false);
return false;
}

bool operator()(const std::vector<Value>&,
const std::vector<Value>&) const {
// Should be unreachable; nested values are not currently allowed by the style specification.
assert(false);
return false;
}

bool operator()(const PropertyMap&,
const PropertyMap&) const {
// Should be unreachable; nested values are not currently allowed by the style specification.
assert(false);
return false;
}
};

template <class Op>
bool compare(const Value& lhs, const Value& rhs, const Op& op) const {
return Value::binary_visit(lhs, rhs, Comparator<Op> { op });
}

bool equal(const Value& lhs, const Value& rhs) const {
return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; });
}
};

inline bool Filter::operator()(const Feature& feature) const {
return operator()(apply_visitor(ToFeatureType(), feature.geometry), feature.id, [&] (const std::string& key) -> optional<Value> {
auto it = feature.properties.find(key);
if (it == feature.properties.end())
return {};
return it->second;
});
}

template <class GeometryTileFeature>
bool Filter::operator()(const GeometryTileFeature& feature) const {
return operator()(feature.getType(), feature.getID(), [&] (const auto& key) { return feature.getValue(key); });
}

template <class PropertyAccessor>
bool Filter::operator()(FeatureType type, optional<FeatureIdentifier> id, PropertyAccessor accessor) const {
return FilterBase::visit(*this, FilterEvaluator<PropertyAccessor> { type, id, accessor });
}

} // namespace style
} // namespace mbgl
6 changes: 6 additions & 0 deletions platform/darwin/src/NSPredicate+MGLAdditions.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "NSPredicate+MGLAdditions.h"

#import "MGLValueEvaluator.h"
#import "MGLStyleValue_Private.h"

class FilterEvaluator {
public:
Expand Down Expand Up @@ -194,6 +195,11 @@
NSPredicate *operator()(mbgl::style::NotHasIdentifierFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == nil", @"$id"];
}

NSPredicate *operator()(mbgl::style::ExpressionFilter filter) {
id jsonObject = MGLJSONObjectFromMBGLExpression(*filter.expression);
return [NSPredicate mgl_predicateWithJSONObject:jsonObject];
}
};

@implementation NSPredicate (MGLAdditions)
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/geometry/feature_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ void FeatureIndex::addFeature(
continue;
}

if (options.filter && !(*options.filter)(*geometryTileFeature)) {
if (options.filter && !(*options.filter)(style::expression::EvaluationContext { static_cast<float>(tileID.z), geometryTileFeature.get() })) {
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/layout/symbol_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
const size_t featureCount = sourceLayer->featureCount();
for (size_t i = 0; i < featureCount; ++i) {
auto feature = sourceLayer->getFeature(i);
if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
if (!leader.filter(expression::EvaluationContext { this->zoom, feature.get() }))
continue;

SymbolFeature ft(std::move(feature));
Expand Down
Loading