Implement v6 filters

This commit is contained in:
John Firebaugh
2014-10-28 11:17:03 -04:00
parent f25cf70689
commit c151f12997
15 changed files with 592 additions and 1101 deletions

View File

@@ -5,6 +5,7 @@
#include <mbgl/style/value.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/pbf.hpp>
#include <mbgl/util/optional.hpp>
#include <cstdint>
#include <iosfwd>
@@ -44,14 +45,14 @@ public:
VectorTileTagExtractor(const VectorTileLayer &layer);
void setTags(const pbf &pbf);
std::vector<Value> getValues(const std::string &key) const;
void setType(FilterExpression::GeometryType type);
FilterExpression::GeometryType getType() const;
mapbox::util::optional<Value> getValue(const std::string &key) const;
void setType(FeatureType type);
FeatureType getType() const;
private:
const VectorTileLayer &layer_;
pbf tags_;
FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any;
FeatureType type_ = FeatureType::Unknown;
};
/*

View File

@@ -1,65 +0,0 @@
#ifndef MBGL_STYLE_FILTER_COMPARISON
#define MBGL_STYLE_FILTER_COMPARISON
#include <mbgl/style/value.hpp>
#include <vector>
#include <string>
#include <iosfwd>
namespace mbgl {
class FilterComparison {
public:
enum class Operator : uint8_t {
Equal,
NotEqual,
Greater,
GreaterEqual,
Less,
LessEqual,
In,
NotIn
};
class Instance {
public:
Instance(Operator op_, std::vector<Value> &&values_)
: op(op_), values(values_) {}
bool compare(const std::vector<Value> &property_values) const;
private:
Operator op = Operator::Equal;
std::vector<Value> values;
friend std::ostream& operator <<(std::ostream &, const Instance &);
};
public:
FilterComparison(const std::string &field_) : field(field_) {};
const std::string &getField() const;
template <typename Extractor> inline bool compare(const Extractor &extractor) const;
template <typename ...Args>
inline void add(Args&& ...args) {
instances.emplace_back(::std::forward<Args>(args)...);
}
private:
std::string field;
std::vector<Instance> instances;
friend std::ostream& operator <<(std::ostream &, const FilterComparison &);
};
std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison);
std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance);
FilterComparison::Operator parseFilterComparisonOperator(const std::string &op);
}
#endif

View File

@@ -1,23 +0,0 @@
#ifndef MBGL_STYLE_FILTER_COMPARISON_PRIVATE
#define MBGL_STYLE_FILTER_COMPARISON_PRIVATE
#include "filter_comparison.hpp"
namespace mbgl {
template <typename Extractor>
inline bool FilterComparison::compare(const Extractor &extractor) const {
const std::vector<Value> values = extractor.getValues(field);
// All instances are ANDed together.
for (const Instance &instance : instances) {
if (!instance.compare(values)) {
return false;
}
}
return true;
}
}
#endif

View File

@@ -1,54 +1,125 @@
#ifndef MBGL_STYLE_FILTER_EXPRESSION
#define MBGL_STYLE_FILTER_EXPRESSION
#include <mbgl/style/filter_comparison.hpp>
#include <mbgl/util/recursive_wrapper.hpp>
#include <mbgl/style/value.hpp>
#include <iosfwd>
#include <rapidjson/document.h>
#include <string>
#include <vector>
namespace mbgl {
class FilterExpression {
public:
typedef mapbox::util::recursive_wrapper<FilterExpression> Wrapper;
typedef mapbox::util::variant<
struct NullExpression,
struct EqualsExpression,
struct NotEqualsExpression,
struct LessThanExpression,
struct LessThanEqualsExpression,
struct GreaterThanExpression,
struct GreaterThanEqualsExpression,
struct InExpression,
struct NotInExpression,
struct AnyExpression,
struct AllExpression,
struct NoneExpression
> FilterExpression;
enum class Operator : uint8_t {
And,
Or,
Xor,
Nor
};
FilterExpression parseFilterExpression(const rapidjson::Value&);
enum class GeometryType : uint8_t {
Any,
Point,
LineString,
Polygon
};
template <class Extractor>
bool evaluate(const FilterExpression&, const Extractor&);
public:
FilterExpression() = default;
FilterExpression(Operator op_) : op(op_) {};
bool empty() const;
template <typename Extractor> bool compare(const Extractor &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::vector<FilterComparison> comparisons;
std::vector<FilterExpression::Wrapper> expressions;
friend std::ostream& operator <<(std::ostream &, const FilterExpression &);
struct NullExpression {
template <class Extractor>
bool evaluate(const Extractor&) const { return true; }
};
std::ostream& operator <<(std::ostream &s, const FilterExpression &expression);
struct EqualsExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct NotEqualsExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct LessThanExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct LessThanEqualsExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct GreaterThanExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct GreaterThanEqualsExpression {
std::string key;
Value value;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct InExpression {
std::string key;
std::vector<Value> values;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct NotInExpression {
std::string key;
std::vector<Value> values;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct AnyExpression {
std::vector<FilterExpression> expressions;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct AllExpression {
std::vector<FilterExpression> expressions;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
struct NoneExpression {
std::vector<FilterExpression> expressions;
template <class Extractor>
bool evaluate(const Extractor&) const;
};
FilterExpression::GeometryType parseGeometryType(const std::string &geometry);
}
#endif

View File

@@ -1,75 +1,118 @@
#ifndef MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
#define MBGL_STYLE_FILTER_EXPRESSION_PRIVATE
#include "filter_expression.hpp"
#include "filter_comparison_private.hpp"
#include <mbgl/util/optional.hpp>
#include <mbgl/style/value_comparison.hpp>
namespace mbgl {
template <typename Extractor>
bool FilterExpression::compare(const Extractor &extractor) const {
if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) {
return false;
}
template <class Extractor>
struct Evaluator : public mapbox::util::static_visitor<bool>
{
const Extractor& extractor;
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;
}
}
Evaluator(const Extractor& extractor_)
: extractor(extractor_) {}
template <class E>
bool operator()(const E& e) const { return e.evaluate(extractor); }
};
template <class Extractor>
bool evaluate(const FilterExpression& expression, const Extractor& extractor) {
return mapbox::util::apply_visitor(Evaluator<Extractor>(extractor), expression);
};
template <class Extractor>
bool EqualsExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return actual && util::relaxed_equal(*actual, value);
}
template <class Extractor>
bool NotEqualsExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return !actual || util::relaxed_not_equal(*actual, value);
}
template <class Extractor>
bool LessThanExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return actual && util::relaxed_less(*actual, value);
}
template <class Extractor>
bool LessThanEqualsExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return actual && util::relaxed_less_equal(*actual, value);
}
template <class Extractor>
bool GreaterThanExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return actual && util::relaxed_greater(*actual, value);
}
template <class Extractor>
bool GreaterThanEqualsExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
return actual && util::relaxed_greater_equal(*actual, value);
}
template <class Extractor>
bool InExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
if (!actual)
return false;
case Operator::Xor: {
int count = 0;
for (const FilterComparison &comparison : comparisons) {
count += comparison.compare(extractor);
if (count > 1) {
return false;
}
for (const auto& v: values) {
if (util::relaxed_equal(*actual, v)) {
return true;
}
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 false;
}
template <class Extractor>
bool NotInExpression::evaluate(const Extractor& extractor) const {
mapbox::util::optional<Value> actual = extractor.getValue(key);
if (!actual)
return true;
for (const auto& v: values) {
if (util::relaxed_equal(*actual, v)) {
return false;
}
}
return true;
}
template <class Extractor>
bool AnyExpression::evaluate(const Extractor& extractor) const {
Evaluator<Extractor> evaluator(extractor);
for (const auto& e: expressions) {
if (mapbox::util::apply_visitor(evaluator, e)) {
return true;
}
}
return false;
}
template <class Extractor>
bool AllExpression::evaluate(const Extractor& extractor) const {
Evaluator<Extractor> evaluator(extractor);
for (const auto& e: expressions) {
if (!mapbox::util::apply_visitor(evaluator, e)) {
return false;
}
}
return true;
}
template <class Extractor>
bool NoneExpression::evaluate(const Extractor& extractor) const {
Evaluator<Extractor> evaluator(extractor);
for (const auto& e: expressions) {
if (mapbox::util::apply_visitor(evaluator, e)) {
return false;
}
}
return true;
}
}
#endif

View File

@@ -85,11 +85,7 @@ private:
template <typename T>
T parseFunctionArgument(JSVal value);
FilterExpression parseFilter(JSVal, FilterExpression::Operator op);
FilterExpression parseFilter(JSVal);
Value parseValue(JSVal value);
std::vector<Value> parseValues(JSVal values);
private:
std::unordered_map<std::string, const rapidjson::Value *> constants;

View File

@@ -3,6 +3,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/pbf.hpp>
#include <rapidjson/document.h>
#include <cstdlib>
#include <cerrno>
@@ -14,6 +15,7 @@ typedef mapbox::util::variant<bool, int64_t, uint64_t, double, std::string> Valu
std::string toString(const Value &value);
Value parseValue(pbf data);
Value parseValue(const rapidjson::Value&);
namespace util {
inline bool parseNumericString(const std::string &str, double &result) {

View File

@@ -15,35 +15,35 @@ template <typename Operator>
struct relaxed_operator_visitor {
typedef bool result_type;
inline bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); }
template <typename T0, typename T1>
inline bool operator()(T0, T1) const { return false; }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
inline bool operator()(bool lhs, T rhs) const { return Operator()(T(lhs), rhs); }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
inline bool operator()(T lhs, bool rhs) const { return Operator()(lhs, T(rhs)); }
template <typename T>
inline bool operator()(T lhs, T rhs) const { return Operator()(lhs, rhs); }
inline bool operator()(int64_t lhs, uint64_t rhs) const {
return lhs < 0 ? false : Operator()(uint64_t(lhs), rhs);
return Operator()(double(lhs), double(rhs));
}
inline bool operator()(int64_t lhs, double rhs) const {
return Operator()(double(lhs), rhs);
}
inline bool operator()(uint64_t lhs, int64_t rhs) const {
return rhs < 0 ? false : Operator()(lhs, uint64_t(rhs));
return Operator()(double(lhs), double(rhs));
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
inline bool operator()(const std::string &lhs, T rhs) const {
double value;
return parseNumericString(lhs, value) ? Operator()(value, double(rhs)) : false;
inline bool operator()(uint64_t lhs, double rhs) const {
return Operator()(double(lhs), rhs);
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
inline bool operator()(T lhs, const std::string &rhs) const {
double value;
return parseNumericString(rhs, value) ? Operator()(double(lhs), value) : false;
inline bool operator()(double lhs, uint64_t rhs) const {
return Operator()(lhs, double(rhs));
}
template <typename T0, typename T1>
inline bool operator()(T0 lhs, T1 rhs) const { return Operator()(lhs, rhs); }
inline bool operator()(double lhs, int64_t rhs) const {
return Operator()(lhs, double(rhs));
}
};
struct relaxed_equal_operator {

View File

@@ -1,6 +1,5 @@
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/filter_expression_private.hpp>
#include <mbgl/style/filter_comparison_private.hpp>
#include <algorithm>
#include <iostream>
@@ -123,81 +122,6 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren
operator++();
}
//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) {
// if (filterExpression.empty()) {
// return true;
// }
//
//
//
//
// if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) {
// return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf);
// } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) {
// return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf);
// } else if (filterExpression.is<std::true_type>()) {
// 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) {}
@@ -205,8 +129,12 @@ void VectorTileTagExtractor::setTags(const pbf &pbf) {
tags_ = pbf;
}
std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) const {
std::vector<Value> values;
mapbox::util::optional<Value> VectorTileTagExtractor::getValue(const std::string &key) const {
if (key == "$type") {
return Value(uint64_t(type_));
}
mapbox::util::optional<Value> value;
auto field_it = layer_.key_index.find(key);
if (field_it != layer_.key_index.end()) {
@@ -221,14 +149,14 @@ std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) con
if (!tags_pbf) {
// This should not happen; otherwise the vector tile is invalid.
fprintf(stderr, "[WARNING] uneven number of feature tag ids\n");
return values;
return value;
}
// 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 (layer_.values.size() > tag_val) {
values.emplace_back(layer_.values[tag_val]);
value = layer_.values[tag_val];
} else {
fprintf(stderr, "[WARNING] feature references out of range value\n");
break;
@@ -237,16 +165,14 @@ std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) con
}
}
return values;
return value;
}
void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) {
void VectorTileTagExtractor::setType(FeatureType type) {
type_ = type;
}
FilterExpression::GeometryType VectorTileTagExtractor::getType() const {
return type_;
}
template bool mbgl::evaluate(const FilterExpression&, const VectorTileTagExtractor&);
void FilteredVectorTileLayer::iterator::operator++() {
valid = false;
@@ -256,36 +182,21 @@ void FilteredVectorTileLayer::iterator::operator++() {
while (data.next(2)) { // feature
feature = data.message();
pbf feature_pbf = feature;
bool matched = false;
// Treat the absence of any expression filters as a match.
if (expression.empty()) {
matched = true;
}
VectorTileTagExtractor extractor(parent.layer);
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::LineString); break;
case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break;
default: break;
}
} else {
feature_pbf.skip();
}
// 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
extractor.setType(FeatureType(feature_pbf.varint()));
} else {
feature_pbf.skip();
}
matched = expression.compare(extractor);
}
if (matched) {
if (evaluate(expression, extractor)) {
valid = true;
return; // data loop
} else {

View File

@@ -1,143 +0,0 @@
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/filter_comparison_private.hpp>
#include <mbgl/style/value_comparison.hpp>
#include <ostream>
namespace mbgl {
inline bool includes(const Value &property_value, const std::vector<Value> &filter_values) {
for (const Value &filter_value : filter_values) {
if (util::relaxed_equal(property_value, filter_value)) {
return true;
}
}
return false;
}
template <typename Comparer>
inline bool compare(const Value &property_value, const std::vector<Value> &filter_values, const Comparer &comparer) {
for (const Value &filter_value : filter_values) {
if (!comparer(property_value, filter_value)) {
return false;
}
}
return true;
}
template <typename Comparer>
inline bool all(const std::vector<Value> &property_values, const std::vector<Value> &filter_values, const Comparer &comparer) {
for (const Value &property_value : property_values) {
if (!compare(property_value, filter_values, comparer)) {
return false;
}
}
return true;
}
inline bool set_equal(const std::vector<Value> &property_values, const std::vector<Value> &filter_values) {
for (const Value &property_value : property_values) {
if (!includes(property_value, filter_values)) {
return false;
}
}
if (property_values.size() == filter_values.size()) {
// Optimization: When the count is the same, the set is guaranteed to be identical.
return true;
}
// Otherwise, check again for identical reverse-mapped values.
for (const Value &filter_value : filter_values) {
if (!includes(filter_value, property_values)) {
return false;
}
}
return true;
}
bool FilterComparison::Instance::compare(const std::vector<Value> &property_values) const {
switch (op) {
case Operator::Equal:
return set_equal(property_values, values);
case Operator::NotEqual:
return !set_equal(property_values, values);
case Operator::In:
for (const Value &property_value : property_values) {
if (includes(property_value, values)) {
return true;
}
}
return false;
case Operator::NotIn:
for (const Value &property_value : property_values) {
if (!includes(property_value, values)) {
return true;
}
}
return false;
case Operator::Greater:
return all(property_values, values, util::relaxed_greater);
case Operator::GreaterEqual:
return all(property_values, values, util::relaxed_greater_equal);
case Operator::Less:
return all(property_values, values, util::relaxed_less);
case Operator::LessEqual:
return all(property_values, values, util::relaxed_less_equal);
default:
return false;
}
}
const std::string &FilterComparison::getField() const {
return field;
}
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;
}
template bool FilterComparison::compare(const VectorTileTagExtractor &extractor) const;
}

View File

@@ -1,66 +1,123 @@
#include <mbgl/style/filter_expression_private.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/value_comparison.hpp>
#include <ostream>
#include <mbgl/platform/log.hpp>
namespace mbgl {
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;
Value parseFeatureType(const Value& value) {
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));
} else {
Log::Warning(Event::ParseStyle, "value for $type filter must be Point, LineString, or Polygon");
return Value(uint64_t(FeatureType::Unknown));
}
return s;
}
template <class Expression>
FilterExpression parseBinaryFilter(const rapidjson::Value& value) {
FilterExpression empty;
std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) {
switch (type) {
case FilterExpression::GeometryType::Point: s << "Point"; break;
case FilterExpression::GeometryType::LineString: s << "LineString"; break;
case FilterExpression::GeometryType::Polygon: s << "Polygon"; break;
case FilterExpression::GeometryType::Any: s << "<Any>"; break;
if (value.Size() < 3) {
Log::Warning(Event::ParseStyle, "filter expression must have 3 elements");
return empty;
}
return s;
}
bool FilterExpression::empty() const {
return type == GeometryType::Any && comparisons.empty() && expressions.empty();
}
void FilterExpression::add(const FilterComparison &comparison) {
comparisons.emplace_back(comparison);
}
void FilterExpression::add(const FilterExpression &expression) {
expressions.emplace_back(expression);
}
void FilterExpression::setGeometryType(GeometryType g) {
type = g;
}
FilterExpression::GeometryType parseGeometryType(const std::string &geometry) {
if (geometry == "Point") return FilterExpression::GeometryType::Point;
if (geometry == "LineString") return FilterExpression::GeometryType::LineString;
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;
if (!value[1u].IsString()) {
Log::Warning(Event::ParseStyle, "filter expression key must be a string");
return empty;
}
s << "end expression" << std::endl;
return s;
Expression expression;
expression.key = { value[1u].GetString(), value[1u].GetStringLength() };
expression.value = parseValue(value[2u]);
if (expression.key == "$type") {
expression.value = parseFeatureType(expression.value);
}
return expression;
}
template bool FilterExpression::compare(const VectorTileTagExtractor &extractor) const;
template <class Expression>
FilterExpression parseSetFilter(const rapidjson::Value& value) {
FilterExpression empty;
if (value.Size() < 2) {
Log::Warning(Event::ParseStyle, "filter expression must at least 2 elements");
return empty;
}
if (!value[1u].IsString()) {
Log::Warning(Event::ParseStyle, "filter expression key must be a string");
return empty;
}
Expression expression;
expression.key = { value[1u].GetString(), value[1u].GetStringLength() };
for (rapidjson::SizeType i = 2; i < value.Size(); ++i) {
expression.values.push_back(parseValue(value[i]));
}
return expression;
}
template <class Expression>
FilterExpression parseCompoundFilter(const rapidjson::Value& value) {
Expression expression;
for (rapidjson::SizeType i = 1; i < value.Size(); ++i) {
expression.expressions.push_back(parseFilterExpression(value[i]));
}
return expression;
}
FilterExpression parseFilterExpression(const rapidjson::Value& value) {
FilterExpression empty;
if (!value.IsArray()) {
Log::Warning(Event::ParseStyle, "filter expression must be an array");
return empty;
}
if (value.Size() < 1) {
Log::Warning(Event::ParseStyle, "filter expression must have at least 1 element");
return empty;
}
if (!value[0u].IsString()) {
Log::Warning(Event::ParseStyle, "filter operator must be a string");
return empty;
}
std::string op = { value[0u].GetString(), value[0u].GetStringLength() };
if (op == "==") {
return parseBinaryFilter<EqualsExpression>(value);
} else if (op == "!=") {
return parseBinaryFilter<NotEqualsExpression>(value);
} else if (op == ">") {
return parseBinaryFilter<GreaterThanExpression>(value);
} else if (op == ">=") {
return parseBinaryFilter<GreaterThanEqualsExpression>(value);
} else if (op == "<") {
return parseBinaryFilter<LessThanExpression>(value);
} else if (op == "<=") {
return parseBinaryFilter<LessThanEqualsExpression>(value);
} else if (op == "in") {
return parseSetFilter<InExpression>(value);
} else if (op == "!in") {
return parseSetFilter<NotInExpression>(value);
} else if (op == "all") {
return parseCompoundFilter<AllExpression>(value);
} else if (op == "any") {
return parseCompoundFilter<AnyExpression>(value);
} else if (op == "none") {
return parseCompoundFilter<NoneExpression>(value);
} else {
Log::Warning(Event::ParseStyle, "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\"");
return empty;
}
}
}

View File

@@ -711,7 +711,7 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
if (value.HasMember("filter")) {
JSVal value_filter = replaceConstant(value["filter"]);
layer->bucket->filter = parseFilter(value_filter);
layer->bucket->filter = parseFilterExpression(value_filter);
}
if (value.HasMember("render")) {
@@ -738,93 +738,6 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
}
}
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 filter_itr = filterValue.MemberBegin();
for (; filter_itr != filterValue.MemberEnd(); ++filter_itr) {
comparison.add(
parseFilterComparisonOperator({ filter_itr->name.GetString(), filter_itr->name.GetStringLength() }),
parseValues(replaceConstant(filter_itr->value))
);
}
} else if (filterValue.IsArray()) {
comparison.add(FilterComparison::Operator::In, parseValues(filterValue));
} else {
comparison.add(FilterComparison::Operator::Equal, std::vector<Value>({ 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 {
Log::Warning(Event::ParseStyle, "expression must be either an array or an object");
}
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::vector<Value> StyleParser::parseValues(JSVal value) {
std::vector<Value> values;
if (value.IsArray()) {
for (rapidjson::SizeType i = 0; i < value.Size(); i++) {
values.emplace_back(parseValue(replaceConstant(value[i])));
}
} else {
values.emplace_back(parseValue(value));
}
return values;
}
void StyleParser::parseRender(JSVal value, util::ptr<StyleLayer> &layer) {
if (!value.IsObject()) {
Log::Warning(Event::ParseStyle, "render property of layer '%s' must be an object", layer->id.c_str());

View File

@@ -42,3 +42,25 @@ std::string mbgl::toString(const mbgl::Value& value) {
else if (value.is<double>()) return boost::lexical_cast<std::string>(value.get<double>());
else return "null";
}
mbgl::Value mbgl::parseValue(const rapidjson::Value& 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;
}
}

View File

@@ -1,306 +1,103 @@
#include <iostream>
#include "gtest/gtest.h"
#include <mbgl/style/filter_comparison_private.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/filter_expression_private.hpp>
#include <map>
using namespace mbgl;
typedef std::multimap<std::string, mbgl::Value> Properties;
class MockExtractor {
class Extractor {
public:
inline MockExtractor(const std::multimap<std::string, mbgl::Value> &values_) : values(values_) {}
inline MockExtractor() {}
inline Extractor(const Properties& properties_, FeatureType type_)
: properties(properties_)
, type(type_)
{}
inline std::vector<mbgl::Value> getValues(const std::string &key) const {
std::vector<mbgl::Value> result;
// Find all values with the requested key.
const auto ret = values.equal_range(key);
for (auto it = ret.first; it != ret.second; it++) {
// Append the newly found value to the forward list.
result.emplace_back(it->second);
}
return result;
mapbox::util::optional<Value> getValue(const std::string &key) const {
if (key == "$type")
return Value(uint64_t(type));
auto it = properties.find(key);
if (it == properties.end())
return mapbox::util::optional<Value>();
return it->second;
}
FeatureType getType() const {
return type;
}
private:
const std::multimap<std::string, mbgl::Value> values;
const Properties properties;
FeatureType type;
};
TEST(FilterComparison, EqualsSingleStringValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { std::string("bar") });
// comparison is { "test": { "==": "bar" } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor()));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("barst") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(32.8) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
FilterExpression parse(const char * expression) {
rapidjson::Document doc;
doc.Parse<0>(expression);
return parseFilterExpression(doc);
}
TEST(FilterComparison, EqualsSingleDoubleValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { double(32.8) });
// comparison is { "test": { "==": 32.8 } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(32.8) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("32.8") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", double(32.8) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(32.8) }, { "test", std::string("booz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", double(32.8) }})));
ASSERT_FALSE(comparison.compare(MockExtractor()));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(32.9) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
bool evaluate(const FilterExpression& expression, const Properties& properties, FeatureType type = FeatureType::Unknown) {
return mbgl::evaluate(expression, Extractor(properties, type));
}
TEST(FilterComparison, EqualsSingleUintValue) {
using namespace mbgl;
TEST(FilterComparison, EqualsString) {
FilterExpression f = parse("[\"==\", \"foo\", \"bar\"]");
ASSERT_TRUE(evaluate(f, {{ "foo", std::string("bar") }}));
ASSERT_FALSE(evaluate(f, {{ "foo", std::string("baz") }}));
};
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { uint64_t(42) });
// comparison is { "test": { "==": 42 } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("42") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", uint64_t(42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(42) }, { "test", std::string("booz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", uint64_t(42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor()));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(43) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
TEST(FilterComparison, EqualsNumber) {
FilterExpression f = parse("[\"==\", \"foo\", 0]");
ASSERT_TRUE(evaluate(f, {{ "foo", int64_t(0) }}));
ASSERT_TRUE(evaluate(f, {{ "foo", uint64_t(0) }}));
ASSERT_TRUE(evaluate(f, {{ "foo", double(0) }}));
ASSERT_FALSE(evaluate(f, {{ "foo", int64_t(1) }}));
ASSERT_FALSE(evaluate(f, {{ "foo", uint64_t(1) }}));
ASSERT_FALSE(evaluate(f, {{ "foo", double(1) }}));
ASSERT_FALSE(evaluate(f, {{ "foo", std::string("0") }}));
ASSERT_FALSE(evaluate(f, {{ "foo", false }}));
ASSERT_FALSE(evaluate(f, {{ "foo", true }}));
ASSERT_FALSE(evaluate(f, {{}}));
}
TEST(FilterComparison, EqualsSingleIntValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { int64_t(-42) });
// comparison is { "test": { "==": -42 } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(-42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("-42") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", int64_t(-42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-42) }, { "test", std::string("booz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", int64_t(-42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor()));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-43) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(-43) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(-42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
TEST(FilterComparison, EqualsType) {
FilterExpression f = parse("[\"==\", \"$type\", \"LineString\"]");
ASSERT_FALSE(evaluate(f, {{}}, FeatureType::Point));
ASSERT_TRUE(evaluate(f, {{}}, FeatureType::LineString));
}
TEST(FilterComparison, EqualsSingleBoolValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { bool(true) });
// comparison is { "test": { "==": true } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(1) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(1) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(1) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("1") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", bool(true) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }, { "test", std::string("booz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", bool(true) }})));
ASSERT_FALSE(comparison.compare(MockExtractor()));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
TEST(FilterComparison, Any) {
ASSERT_FALSE(evaluate(parse("[\"any\"]"), {{}}));
ASSERT_TRUE(evaluate(parse("[\"any\", [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_FALSE(evaluate(parse("[\"any\", [\"==\", \"foo\", 0]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_TRUE(evaluate(parse("[\"any\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
}
TEST(FilterComparison, EqualsMultipleStringValues) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { std::string("bar"), std::string("baz") });
// comparison is { "test": { "==": ["bar", "baz"]̇ } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("baz") }, { "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("baz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }, { "test", std::string("boo") }})));
TEST(FilterComparison, All) {
ASSERT_TRUE(evaluate(parse("[\"all\"]"), {{}}));
ASSERT_TRUE(evaluate(parse("[\"all\", [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_FALSE(evaluate(parse("[\"all\", [\"==\", \"foo\", 0]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_FALSE(evaluate(parse("[\"all\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
}
TEST(FilterComparison, EqualsMultipleIdenticalStringValues) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::Equal, std::vector<Value> { std::string("bar"), std::string("bar") });
// comparison is { "test": { "==": ["bar", "bar"]̇ } }
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("baz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }})));
}
TEST(FilterComparison, NotEqualsSingleStringValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { std::string("bar") });
// comparison is { "test": { "!=": "bar" } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor()));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("barst") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(32.8) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
}
TEST(FilterComparison, NotEqualsSingleDoubleValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { double(32.8) });
// comparison is { "test": { "!=": 32.8 } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(32.8) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("32.8") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", double(32.8) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(32.8) }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", double(32.8) }})));
ASSERT_TRUE(comparison.compare(MockExtractor()));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(32.9) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
}
TEST(FilterComparison, NotEqualsSingleUintValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { uint64_t(42) });
// comparison is { "test": { "!=": 42 } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("42") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", uint64_t(42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(42) }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", uint64_t(42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor()));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(43) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
}
TEST(FilterComparison, NotEqualsSingleIntValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { int64_t(-42) });
// comparison is { "test": { "!=": -42 } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(-42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(-42) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("-42") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", int64_t(-42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-42) }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", int64_t(-42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor()));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-43) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", double(-43) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(-42) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
}
TEST(FilterComparison, NotEqualsSingleBoolValue) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { bool(true) });
// comparison is { "test": { "!=": true } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", bool(true) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", int64_t(1) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", uint64_t(1) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", double(1) }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("1") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "other", std::string("bar") }, { "test", bool(true) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(true) }, { "test", std::string("booz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "other", bool(true) }})));
ASSERT_TRUE(comparison.compare(MockExtractor()));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", bool(false) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", int64_t(-18932) }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", uint64_t(18932) }})));
}
TEST(FilterComparison, NotEqualsMultipleStringValues) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { std::string("bar"), std::string("baz") });
// comparison is { "test": { "!=": ["bar", "baz"]̇ } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("baz") }, { "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("baz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }, { "test", std::string("boo") }})));
}
TEST(FilterComparison, NotEqualsMultipleIdenticalStringValues) {
using namespace mbgl;
FilterComparison comparison("test");
comparison.add(FilterComparison::Operator::NotEqual, std::vector<Value> { std::string("bar"), std::string("bar") });
// comparison is { "test": { "!=": ["bar", "bar"]̇ } }
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }})));
ASSERT_FALSE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("bar") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("baz") }})));
ASSERT_TRUE(comparison.compare(MockExtractor({{ "test", std::string("bar") }, { "test", std::string("baz") }})));
TEST(FilterComparison, None) {
ASSERT_TRUE(evaluate(parse("[\"none\"]"), {{}}));
ASSERT_FALSE(evaluate(parse("[\"none\", [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_TRUE(evaluate(parse("[\"none\", [\"==\", \"foo\", 0]]"),
{{ std::string("foo"), int64_t(1) }}));
ASSERT_FALSE(evaluate(parse("[\"none\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]"),
{{ std::string("foo"), int64_t(1) }}));
}

View File

@@ -17,110 +17,26 @@ TEST(Variant, toString) {
EXPECT_EQ("false", toString( false ));
}
TEST(Variant, RelaxedEqualityStringToBool) {
// 1-ish values are true
EXPECT_TRUE(util::relaxed_equal(std::string("1"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("1.0"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 1"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0x1"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0X1"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 1.0"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 1 "), bool(true)));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string("1")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string("1.0")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string(" 1")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string(" 0x1")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string(" 0X1")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string(" 1.0")));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string(" 1 ")));
// 0-ish values are false
EXPECT_TRUE(util::relaxed_equal(std::string("0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("0.0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0x0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0X0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0.0"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" 0 "), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(""), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(" "), bool(false)));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("0.0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" 0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" 0x0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" 0X0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" 0.0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" 0 ")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string(" ")));
// other string values are neither true nor false
EXPECT_FALSE(util::relaxed_equal(std::string(" 1.0 g"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("foo"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("true"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("false"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(" inf "), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(" inFINITY "), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(" nan "), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(" NAN "), bool(true)));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string(" 1.0 g")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("foo")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("true")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string(" inf ")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string(" inFINITY ")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string(" nan ")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string(" NAN ")));
EXPECT_FALSE(util::relaxed_equal(std::string(" 1.0 g"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("foo"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("true"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("false"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string(" inf "), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string(" inFINITY "), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string(" nan "), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string(" NAN "), bool(false)));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string(" 1.0 g")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("foo")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("true")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string(" inf ")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string(" inFINITY ")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string(" nan ")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string(" NAN ")));
}
TEST(Variant, RelaxedEquality) {
// Compare to bool
EXPECT_TRUE(util::relaxed_equal(bool(false), bool(false)));
EXPECT_TRUE(util::relaxed_equal(bool(false), int64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(false), uint64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(false), double(0)));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("0")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("")));
EXPECT_TRUE(util::relaxed_equal(bool(true), bool(true)));
EXPECT_TRUE(util::relaxed_equal(bool(true), int64_t(1)));
EXPECT_TRUE(util::relaxed_equal(bool(true), uint64_t(1)));
EXPECT_TRUE(util::relaxed_equal(bool(true), double(1)));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string("1")));
EXPECT_FALSE(util::relaxed_equal(bool(false), bool(true)));
EXPECT_FALSE(util::relaxed_equal(bool(false), int64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(false), uint64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(false), double(0)));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("0")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("")));
EXPECT_FALSE(util::relaxed_equal(bool(false), int64_t(386)));
EXPECT_FALSE(util::relaxed_equal(bool(false), int64_t(-7042)));
EXPECT_FALSE(util::relaxed_equal(bool(false), uint64_t(386)));
EXPECT_FALSE(util::relaxed_equal(bool(false), double(3.145)));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("386")));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("test")));
EXPECT_FALSE(util::relaxed_equal(bool(true), int64_t(1)));
EXPECT_FALSE(util::relaxed_equal(bool(true), uint64_t(1)));
EXPECT_FALSE(util::relaxed_equal(bool(true), double(1)));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("1")));
EXPECT_FALSE(util::relaxed_equal(bool(true), bool(false)));
EXPECT_FALSE(util::relaxed_equal(bool(true), int64_t(386)));
EXPECT_FALSE(util::relaxed_equal(bool(true), int64_t(-7042)));
@@ -135,10 +51,9 @@ TEST(Variant, RelaxedEquality) {
EXPECT_TRUE(util::relaxed_equal(int64_t(-7042), int64_t(-7042)));
EXPECT_TRUE(util::relaxed_equal(int64_t(386), uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(int64_t(386), double(386)));
EXPECT_TRUE(util::relaxed_equal(int64_t(386), std::string("386")));
EXPECT_TRUE(util::relaxed_equal(int64_t(1), bool(true)));
EXPECT_TRUE(util::relaxed_equal(int64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386), std::string("386")));
EXPECT_FALSE(util::relaxed_equal(int64_t(1), bool(true)));
EXPECT_FALSE(util::relaxed_equal(int64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386), int64_t(387)));
EXPECT_FALSE(util::relaxed_equal(int64_t(-7042), int64_t(-7043)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386), uint64_t(387)));
@@ -151,16 +66,14 @@ TEST(Variant, RelaxedEquality) {
EXPECT_FALSE(util::relaxed_equal(int64_t(1), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(int64_t(0), std::string("true")));
// Compare to uint64_t
EXPECT_TRUE(util::relaxed_equal(uint64_t(386), int64_t(386)));
EXPECT_TRUE(util::relaxed_equal(uint64_t(386), uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(uint64_t(0), uint64_t(0)));
EXPECT_TRUE(util::relaxed_equal(uint64_t(386), double(386)));
EXPECT_TRUE(util::relaxed_equal(uint64_t(386), std::string("386")));
EXPECT_TRUE(util::relaxed_equal(uint64_t(1), bool(true)));
EXPECT_TRUE(util::relaxed_equal(uint64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386), std::string("386")));
EXPECT_FALSE(util::relaxed_equal(uint64_t(1), bool(true)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386), int64_t(387)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386), uint64_t(387)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0), uint64_t(1)));
@@ -173,17 +86,15 @@ TEST(Variant, RelaxedEquality) {
EXPECT_FALSE(util::relaxed_equal(uint64_t(1), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0), std::string("true")));
// Compare to double
EXPECT_TRUE(util::relaxed_equal(double(3.159385), double(3.159385)));
EXPECT_TRUE(util::relaxed_equal(double(386), int64_t(386)));
EXPECT_TRUE(util::relaxed_equal(double(386), uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(double(0), uint64_t(0)));
EXPECT_TRUE(util::relaxed_equal(double(386), double(386)));
EXPECT_TRUE(util::relaxed_equal(double(386), std::string("386")));
EXPECT_TRUE(util::relaxed_equal(double(1), bool(true)));
EXPECT_TRUE(util::relaxed_equal(double(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(double(386), std::string("386")));
EXPECT_FALSE(util::relaxed_equal(double(1), bool(true)));
EXPECT_FALSE(util::relaxed_equal(double(0), bool(false)));
EXPECT_FALSE(util::relaxed_equal(double(3.159385), double(3.159383)));
EXPECT_FALSE(util::relaxed_equal(double(386), int64_t(387)));
EXPECT_FALSE(util::relaxed_equal(double(386), uint64_t(387)));
@@ -205,16 +116,14 @@ TEST(Variant, RelaxedEquality) {
EXPECT_FALSE(util::relaxed_equal(double(0), std::string("true")));
EXPECT_FALSE(util::relaxed_equal(double(0), std::string("TRUE")));
// Compare to string
EXPECT_TRUE(util::relaxed_equal(std::string("lord"), std::string("lord")));
EXPECT_TRUE(util::relaxed_equal(std::string("386"), int64_t(386)));
EXPECT_TRUE(util::relaxed_equal(std::string("-386"), int64_t(-386)));
EXPECT_TRUE(util::relaxed_equal(std::string("386"), uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(std::string("386.36"), double(386.36)));
EXPECT_TRUE(util::relaxed_equal(std::string(""), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("1"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("386"), int64_t(386)));
EXPECT_FALSE(util::relaxed_equal(std::string("-386"), int64_t(-386)));
EXPECT_FALSE(util::relaxed_equal(std::string("386"), uint64_t(386)));
EXPECT_FALSE(util::relaxed_equal(std::string("386.36"), double(386.36)));
EXPECT_FALSE(util::relaxed_equal(std::string(""), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("1"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("lord"), std::string("baron")));
EXPECT_FALSE(util::relaxed_equal(std::string("386"), int64_t(387)));
EXPECT_FALSE(util::relaxed_equal(std::string("-386"), int64_t(-387)));
@@ -239,46 +148,46 @@ TEST(Variant, RelaxedEquality) {
TEST(Variant, RelaxedGreater) {
EXPECT_TRUE(util::relaxed_greater(std::string("387"), std::string("386")));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater(double(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater(bool(true), std::string("0")));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater(double(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater(bool(true), std::string("0")));
EXPECT_TRUE(util::relaxed_greater(std::string("387"), uint64_t(386)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater(double(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater(bool(true), uint64_t(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), uint64_t(0)));
EXPECT_TRUE(util::relaxed_greater(std::string("387"), int64_t(386)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater(double(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater(bool(true), int64_t(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), int64_t(0)));
EXPECT_TRUE(util::relaxed_greater(std::string("387"), double(386.7)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), double(386.7)));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater(double(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater(bool(true), double(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), double(0)));
EXPECT_TRUE(util::relaxed_greater(std::string("387"), bool(true)));
EXPECT_TRUE(util::relaxed_greater(std::string("387"), bool(false)));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater(double(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater(double(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater(uint64_t(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater(int64_t(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater(double(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater(double(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), bool(true)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), bool(false)));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater(double(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater(double(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater(double(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater(double(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater(bool(true), double(0)));
EXPECT_TRUE(util::relaxed_greater(bool(true), double(0.5)));
EXPECT_TRUE(util::relaxed_greater(bool(true), bool(false)));
EXPECT_TRUE(util::relaxed_greater(bool(true), int64_t(0)));
EXPECT_TRUE(util::relaxed_greater(bool(true), uint64_t(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), double(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), double(0.5)));
EXPECT_TRUE(util::relaxed_greater(bool(true), bool(false)));
EXPECT_FALSE(util::relaxed_greater(bool(true), bool(true)));
EXPECT_FALSE(util::relaxed_greater(bool(true), int64_t(0)));
EXPECT_FALSE(util::relaxed_greater(bool(true), uint64_t(0)));
@@ -315,52 +224,52 @@ TEST(Variant, RelaxedGreater) {
TEST(Variant, RelaxedGreaterEqual) {
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), std::string("386")));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), std::string("387")));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), std::string("387")));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), std::string("387")));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), std::string("386")));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), std::string("387")));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), std::string("0")));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), std::string("387")));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), std::string("387")));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), std::string("386")));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), std::string("387")));
EXPECT_FALSE(util::relaxed_greater_equal(bool(true), std::string("0")));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), uint64_t(387)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), uint64_t(386)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), uint64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), uint64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), uint64_t(0)));
EXPECT_FALSE(util::relaxed_greater_equal(bool(true), uint64_t(0)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), int64_t(387)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), int64_t(386)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), int64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), int64_t(386)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), int64_t(0)));
EXPECT_FALSE(util::relaxed_greater_equal(bool(true), int64_t(0)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), double(386.7)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), double(387)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), double(386.7)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), double(387)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), double(387)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), double(387)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), double(386.7)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), double(387)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), double(0)));
EXPECT_FALSE(util::relaxed_greater_equal(bool(true), double(0)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(std::string("387"), bool(true)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(uint64_t(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(int64_t(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(double(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), bool(false)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), bool(true)));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), bool(false)));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), bool(true)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), bool(true)));
@@ -391,43 +300,43 @@ TEST(Variant, RelaxedGreaterEqual) {
TEST(Variant, RelaxedLess) {
EXPECT_TRUE(util::relaxed_less(std::string("387"), std::string("388")));
EXPECT_TRUE(util::relaxed_less(uint64_t(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less(int64_t(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less(double(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less(bool(false), std::string("388")));
EXPECT_TRUE(util::relaxed_less(bool(false), std::string("1")));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less(int64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less(double(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less(bool(false), std::string("388")));
EXPECT_FALSE(util::relaxed_less(bool(false), std::string("1")));
EXPECT_TRUE(util::relaxed_less(std::string("387"), uint64_t(388)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less(uint64_t(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less(int64_t(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less(double(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less(bool(false), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less(bool(false), uint64_t(1)));
EXPECT_FALSE(util::relaxed_less(bool(false), uint64_t(388)));
EXPECT_FALSE(util::relaxed_less(bool(false), uint64_t(1)));
EXPECT_TRUE(util::relaxed_less(std::string("387"), int64_t(388)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), int64_t(388)));
EXPECT_TRUE(util::relaxed_less(uint64_t(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less(int64_t(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less(double(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less(bool(false), int64_t(388)));
EXPECT_TRUE(util::relaxed_less(bool(false), int64_t(1)));
EXPECT_FALSE(util::relaxed_less(bool(false), int64_t(388)));
EXPECT_FALSE(util::relaxed_less(bool(false), int64_t(1)));
EXPECT_TRUE(util::relaxed_less(std::string("387"), double(387.7)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), double(387.7)));
EXPECT_TRUE(util::relaxed_less(uint64_t(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less(int64_t(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less(double(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less(bool(false), double(387)));
EXPECT_TRUE(util::relaxed_less(bool(false), double(1)));
EXPECT_FALSE(util::relaxed_less(bool(false), double(387)));
EXPECT_FALSE(util::relaxed_less(bool(false), double(1)));
EXPECT_TRUE(util::relaxed_less(std::string("0"), bool(true)));
EXPECT_TRUE(util::relaxed_less(uint64_t(0), bool(true)));
EXPECT_TRUE(util::relaxed_less(int64_t(0), bool(true)));
EXPECT_TRUE(util::relaxed_less(double(0), bool(true)));
EXPECT_FALSE(util::relaxed_less(std::string("0"), bool(true)));
EXPECT_FALSE(util::relaxed_less(uint64_t(0), bool(true)));
EXPECT_FALSE(util::relaxed_less(int64_t(0), bool(true)));
EXPECT_FALSE(util::relaxed_less(double(0), bool(true)));
EXPECT_TRUE(util::relaxed_less(bool(false), bool(true)));
EXPECT_TRUE(util::relaxed_less(bool(true), std::string("386")));
EXPECT_TRUE(util::relaxed_less(bool(true), uint64_t(386)));
EXPECT_TRUE(util::relaxed_less(bool(true), int64_t(386)));
EXPECT_TRUE(util::relaxed_less(bool(true), double(386)));
EXPECT_FALSE(util::relaxed_less(bool(true), std::string("386")));
EXPECT_FALSE(util::relaxed_less(bool(true), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(bool(true), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(bool(true), double(386)));
@@ -464,60 +373,60 @@ TEST(Variant, RelaxedLess) {
TEST(Variant, RelaxedLessEqual) {
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), std::string("388")));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), std::string("387")));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), std::string("387")));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), std::string("387")));
EXPECT_TRUE(util::relaxed_less_equal(double(387), std::string("388")));
EXPECT_TRUE(util::relaxed_less_equal(double(387), std::string("387")));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), std::string("388")));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), std::string("1")));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), std::string("0")));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), std::string("387")));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), std::string("387")));
EXPECT_FALSE(util::relaxed_less_equal(double(387), std::string("388")));
EXPECT_FALSE(util::relaxed_less_equal(double(387), std::string("387")));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), std::string("388")));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), std::string("1")));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), std::string("0")));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), uint64_t(387)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), uint64_t(388)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), uint64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), uint64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), uint64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), uint64_t(1)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), uint64_t(0)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), uint64_t(388)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), uint64_t(1)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), uint64_t(0)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), int64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), int64_t(387)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), int64_t(388)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), int64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), int64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), int64_t(387)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), int64_t(388)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), int64_t(1)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), int64_t(0)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), int64_t(388)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), int64_t(1)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), int64_t(0)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), double(387.7)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("387"), double(387)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), double(387.7)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), double(387)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(387), double(387)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(387), double(387)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), double(387.7)));
EXPECT_TRUE(util::relaxed_less_equal(double(387), double(387)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), double(387)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), double(1)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), double(0)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), double(387)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), double(1)));
EXPECT_FALSE(util::relaxed_less_equal(bool(false), double(0)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("0"), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(std::string("0"), bool(false)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(0), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(uint64_t(0), bool(false)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(0), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(int64_t(0), bool(false)));
EXPECT_TRUE(util::relaxed_less_equal(double(0), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(double(0), bool(false)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("0"), bool(true)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("0"), bool(false)));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(0), bool(true)));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(0), bool(true)));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(0), bool(false)));
EXPECT_FALSE(util::relaxed_less_equal(double(0), bool(true)));
EXPECT_FALSE(util::relaxed_less_equal(double(0), bool(false)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), bool(false)));