Merge pull request #303 from mapbox/expressions-pois

Expressions pois
This commit is contained in:
Nicki Dlugash
2014-06-02 19:08:25 -04:00
11 changed files with 1117 additions and 261 deletions

View File

@@ -14,8 +14,11 @@ module.exports = {
"admin_l2": {
"source": "outdoors",
"layer": "admin",
"field": "admin_level",
"value": 2,
"filter": [
"and",
{"field": "admin_level", "value": 2},
{"field": "maritime", "operator": "not", "value": 1}
],
"join": "round",
"cap": "round",
"type": "line"
@@ -23,11 +26,10 @@ module.exports = {
"admin_l3": {
"source": "outdoors",
"layer": "admin",
"field": "admin_level",
"value": [
3,
4,
5
"filter": [
"and",
{"field": "admin_level", "value": [3,4,5]},
{"field": "maritime", "operator": "not", "value": 1}
],
"join": "round",
"type": "line"
@@ -263,8 +265,11 @@ module.exports = {
"contour_label": {
"source": "outdoors",
"layer": "contour",
"field": "index",
"value": [5, 10],
"filter": [
"and",
{ "field": "index", "value": [ 5, 10 ] },
{ "field": "ele", "operator": "not", "value": 0 }
],
"path": "curve",
"text_field": "{{ele}} m",
"font": "Open Sans Regular, Arial Unicode MS Regular",
@@ -927,11 +932,36 @@ module.exports = {
"size": 12,
"type": "point"
},
"poi_4": {
"poi_4_4": {
"source": "outdoors",
"layer": "poi_label",
"icon": "maki",
"field": "scalerank",
"filter": [
"and",
{ "field": "scalerank", "value": 4 },
{ "field": "localrank", "operator": "<=", "value": 4 }
],
"size": 12,
"type": "point"
},
"poi_4_16": {
"source": "outdoors",
"layer": "poi_label",
"icon": "maki",
"filter": [
"and",
{ "field": "scalerank", "value": 4 },
{ "field": "localrank", "operator": "<=", "value": 16 },
{ "field": "localrank", "operator": ">", "value": 4 }
],
"size": 12,
"type": "point"
},
"poi_4_all": {
"source": "outdoors",
"layer": "poi_label",
"icon": "maki",
"field": "scalerank",
"value": 4,
"size": 12,
"type": "point"
@@ -972,7 +1002,7 @@ module.exports = {
"text_field": "{{name_en}}",
"path": "horizontal",
"padding": 2,
"maxWidth": 10,
"maxWidth": 8,
"verticalAlignment": "top",
"translate": [0, -1],
"font": "Open Sans Semibold, Arial Unicode MS Bold",
@@ -980,15 +1010,53 @@ module.exports = {
"feature_type": "point",
"type": "text",
},
"poi_label_4": {
"poi_label_4_4": {
"source": "outdoors",
"layer": "poi_label",
"field": "scalerank",
"filter": [
"and",
{ "field": "scalerank", "value": 4 },
{ "field": "localrank", "operator": "<=", "value": 4 }
],
"text_field": "{{name_en}}",
"path": "horizontal",
"padding": 2,
"maxWidth": 8,
"verticalAlignment": "top",
"translate": [0, -1],
"font": "Open Sans Semibold, Arial Unicode MS Bold",
"fontSize": 10,
"feature_type": "point",
"type": "text",
},
"poi_label_4_16": {
"source": "outdoors",
"layer": "poi_label",
"filter": [
"and",
{ "field": "scalerank", "value": 4 },
{ "field": "localrank", "operator": "<=", "value": 16 }
],
"text_field": "{{name_en}}",
"path": "horizontal",
"padding": 2,
"maxWidth": 8,
"verticalAlignment": "top",
"translate": [0, -1],
"font": "Open Sans Semibold, Arial Unicode MS Bold",
"fontSize": 10,
"feature_type": "point",
"type": "text",
},
"poi_label_4_all": {
"source": "outdoors",
"layer": "poi_label",
"field": "scalerank",
"value": 4,
"text_field": "{{name_en}}",
"path": "horizontal",
"padding": 2,
"maxWidth": 10,
"maxWidth": 8,
"verticalAlignment": "top",
"translate": [0, -1],
"font": "Open Sans Semibold, Arial Unicode MS Bold",
@@ -1478,10 +1546,34 @@ module.exports = {
"name": "place_label_other",
"bucket": "place_label_other"
},
{
"name": "water_label",
"bucket": "water_label"
},
{
"name": "poi_aerodrome",
"bucket": "poi_aerodrome"
},
{
"name": "poi",
"bucket": "poi"
},
{
"name": "poi_label_1-2",
"bucket": "poi_label_1-2"
},
{
"name": "road_label_1",
"bucket": "road_label_1"
},
{
"name": "poi_3",
"bucket": "poi_3"
},
{
"name": "poi_label_3",
"bucket": "poi_label_3"
},
{
"name": "road_label_2",
"bucket": "road_label_2"
@@ -1494,41 +1586,33 @@ module.exports = {
"name": "contour_label",
"bucket": "contour_label"
},
{
"name": "water_label",
"bucket": "water_label"
},
{
"name": "waterway_label",
"bucket": "waterway_label"
},
{
"name": "poi",
"bucket": "poi"
"name": "poi_4_4",
"bucket": "poi_4_4"
},
{
"name": "poi_label_1-2",
"bucket": "poi_label_1-2"
"name": "poi_label_4_4",
"bucket": "poi_label_4_4"
},
{
"name": "poi_3",
"bucket": "poi_3"
"name": "poi_4_16",
"bucket": "poi_4_16"
},
{
"name": "poi_label_3",
"bucket": "poi_label_3"
"name": "poi_label_4_16",
"bucket": "poi_label_4_16"
},
{
"name": "poi_4",
"bucket": "poi_4"
"name": "poi_4_all",
"bucket": "poi_4_all"
},
{
"name": "poi_label_4",
"bucket": "poi_label_4"
},
{
"name": "poi_aerodrome",
"bucket": "poi_aerodrome"
"name": "poi_label_4_all",
"bucket": "poi_label_4_all"
}
],
"constants": {
@@ -2586,11 +2670,19 @@ module.exports = {
"antialias": false,
"opacity": [
"stops",
{"z": 16.5, "val": 0},
{"z": 16.75, "val": 1}
{"z": 17.5, "val": 0},
{"z": 17.75, "val": 1}
]
},
"poi_4": {
"poi_4_4": {
"antialias": false,
"opacity": [
"stops",
{"z": 18, "val": 0},
{"z": 18.25, "val": 1}
]
},
"poi_4_16": {
"antialias": false,
"opacity": [
"stops",
@@ -2598,6 +2690,14 @@ module.exports = {
{"z": 18.75, "val": 1}
]
},
"poi_4_all": {
"antialias": false,
"opacity": [
"stops",
{"z": 18.75, "val": 0},
{"z": 19, "val": 1}
]
},
"poi_label_1-2": {
"color": "#444",
"size": "poi_label_1-2_size",
@@ -2613,22 +2713,46 @@ module.exports = {
"strokeBlur": 1,
"opacity": [
"stops",
{"z": 16.5, "val": 0},
{"z": 16.75, "val": 1}
{"z": 17.5, "val": 0},
{"z": 17.75, "val": 1}
]
},
"poi_label_4": {
"poi_label_4_4": {
"color": "#444",
"size": 10,
"opacity": [
"stops",
{"z": 18.5, "val": 0},
{"z": 18, "val": 0},
{"z": 17.25, "val": 1}
],
"stroke": "land",
"strokeWidth": 0.3,
"strokeBlur": 1,
},
"poi_label_4_16": {
"color": "#444",
"size": 10,
"opacity": [
"stops",
{"z": 18.25, "val": 0},
{"z": 18.75, "val": 1}
],
"stroke": "land",
"strokeWidth": 0.3,
"strokeBlur": 1,
},
"poi_label_4_all": {
"color": "#444",
"size": 10,
"opacity": [
"stops",
{"z": 18.75, "val": 0},
{"z": 19, "val": 1}
],
"stroke": "land",
"strokeWidth": 0.3,
"strokeBlur": 1,
},
"poi_aerodrome": {
"opacity": ["stops",
{"z": 13, "val": 0},
@@ -3393,11 +3517,19 @@ module.exports = {
"antialias": false,
"opacity": [
"stops",
{"z": 16.5, "val": 0},
{"z": 16.75, "val": 1}
{"z": 17.5, "val": 0},
{"z": 17.75, "val": 1}
]
},
"poi_4": {
"poi_4_4": {
"antialias": false,
"opacity": [
"stops",
{"z": 18, "val": 0},
{"z": 17.25, "val": 1}
]
},
"poi_4_16": {
"antialias": false,
"opacity": [
"stops",
@@ -3405,6 +3537,14 @@ module.exports = {
{"z": 18.75, "val": 1}
]
},
"poi_4_all": {
"antialias": false,
"opacity": [
"stops",
{"z": 18.75, "val": 0},
{"z": 19, "val": 1}
]
},
"poi_label_1-2": {
"color": "#fff",
"size": "poi_label_1-2_size",
@@ -3420,11 +3560,23 @@ module.exports = {
"strokeBlur": 1,
"opacity": [
"stops",
{"z": 16.5, "val": 0},
{"z": 16.75, "val": 1}
{"z": 17.5, "val": 0},
{"z": 17.75, "val": 1}
]
},
"poi_label_4": {
"poi_label_4_4": {
"color": "#fff",
"size": 10,
"opacity": [
"stops",
{"z": 18, "val": 0},
{"z": 18.25, "val": 1}
],
"stroke": "text2_stroke_night",
"strokeWidth": 0.3,
"strokeBlur": 1
},
"poi_label_4_16": {
"color": "#fff",
"size": 10,
"opacity": [
@@ -3436,6 +3588,18 @@ module.exports = {
"strokeWidth": 0.3,
"strokeBlur": 1
},
"poi_label_4_all": {
"color": "#fff",
"size": 10,
"opacity": [
"stops",
{"z": 18.75, "val": 0},
{"z": 19, "val": 1}
],
"stroke": "text2_stroke_night",
"strokeWidth": 0.3,
"strokeBlur": 1
},
"poi_aerodrome": {
"opacity": ["stops",
{"z": 13, "val": 0},

View File

@@ -0,0 +1,128 @@
#ifndef LLMR_MAP_FILTER_EXPRESSION
#define LLMR_MAP_FILTER_EXPRESSION
#include <llmr/style/value.hpp>
#include <llmr/util/recursive_wrapper.hpp>
#include <vector>
#include <string>
namespace llmr {
enum class FilterOperator {
Equal,
NotEqual,
Greater,
GreaterEqual,
Less,
LessEqual
};
enum class ExpressionOperator {
Or,
And
};
inline FilterOperator filterOperatorType(const std::string &op) {
if (op == "!=" || op == "not") {
return FilterOperator::NotEqual;
} else if (op == "==" || op == "eq") {
return FilterOperator::Equal;
} else if (op == ">" || op == "gt") {
return FilterOperator::Greater;
} else if (op == ">=" || op == "gte") {
return FilterOperator::GreaterEqual;
} else if (op == "<" || op == "lt") {
return FilterOperator::Less;
} else if (op == "<=" || op == "lte") {
return FilterOperator::LessEqual;
} else {
fprintf(stderr, "[WARNING] filter operator '%s' unrecognized\n", op.c_str());
return FilterOperator::Equal;
}
}
inline ExpressionOperator expressionOperatorType(const std::string &op) {
if (op == "&&" || op == "and") {
return ExpressionOperator::And;
} else if (op == "||" || op == "or") {
return ExpressionOperator::Or;
} else {
fprintf(stderr, "[WARNING] expression operator '%s' unrecognized\n", op.c_str());
return ExpressionOperator::Or;
}
}
class PropertyFilter;
class PropertyExpression;
typedef util::variant<
util::recursive_wrapper<PropertyFilter>,
util::recursive_wrapper<PropertyExpression>,
std::true_type
> PropertyFilterExpression;
class PropertyFilter {
public:
inline PropertyFilter(const std::string &field, FilterOperator op, const Value &value) : field(field), op(op), value(value) {};
inline PropertyFilter(PropertyFilter &&filter)
: field(std::move(filter.field)),
op(filter.op),
value(std::move(filter.value)) {
}
// Returns true if the filter passes, even if the key is missing.
inline bool isMissingFieldOkay() const {
switch (op) {
case FilterOperator::NotEqual:
return true;
default:
return false;
}
}
inline bool compare(const Value &other) const {
switch (op) {
case FilterOperator::Equal:
return util::relaxed_equal(other, value);
case FilterOperator::NotEqual:
return !util::relaxed_equal(other, value);
case FilterOperator::Greater:
return util::relaxed_greater(other, value);
case FilterOperator::GreaterEqual:
return util::relaxed_greater_equal(other, value);
case FilterOperator::Less:
return util::relaxed_less(other, value);
case FilterOperator::LessEqual:
return util::relaxed_less_equal(other, value);
default:
return false;
}
}
public:
std::string field;
FilterOperator op = FilterOperator::Equal;
Value value;
};
class PropertyExpression {
public:
inline PropertyExpression() {}
inline PropertyExpression(PropertyExpression &&expression)
: op(expression.op),
operands(std::move(expression.operands)) {
}
public:
ExpressionOperator op = ExpressionOperator::Or;
std::vector<PropertyFilterExpression> operands;
};
}
#endif

View File

@@ -5,8 +5,10 @@
#include <llmr/util/vec.hpp>
#include <llmr/style/value.hpp>
#include <llmr/text/glyph.hpp>
#include <llmr/map/filter_expression.hpp>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <limits>
@@ -53,7 +55,12 @@ public:
const pbf& operator*() const;
private:
const FilteredVectorTileLayer& filter;
bool matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf);
bool matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf);
bool matchesFilter(const PropertyFilter &filter, const pbf &tags_pbf);
private:
const FilteredVectorTileLayer& parent;
bool valid = false;
pbf feature;
pbf data;
@@ -68,8 +75,6 @@ public:
private:
const VectorTileLayer& layer;
const BucketDescription& bucket_desc;
int32_t key = -1;
std::set<uint32_t> values;
};
std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement);
@@ -82,6 +87,7 @@ public:
std::string name;
uint32_t extent = 4096;
std::vector<std::string> keys;
std::unordered_map<std::string, uint32_t> key_index;
std::vector<Value> values;
std::map<std::string, std::map<Value, Shaping>> shaping;
};

View File

@@ -5,8 +5,9 @@
#include <vector>
#include <cmath>
#include "value.hpp"
#include "../util/vec.hpp"
#include <llmr/util/vec.hpp>
#include <llmr/map/filter_expression.hpp>
#include <llmr/style/value.hpp>
namespace llmr {
@@ -81,6 +82,7 @@ inline float verticalAlignmentType(const std::string& alignment) {
else return 0.5;
};
class BucketGeometryDescription {
public:
CapType cap = CapType::None;
@@ -105,6 +107,7 @@ public:
bool alwaysVisible = false;
};
class BucketDescription {
public:
BucketType feature_type = BucketType::None;
@@ -113,8 +116,8 @@ public:
// Specify what data to pull into this bucket
std::string source_name;
std::string source_layer;
std::string source_field;
std::vector<Value> source_value;
PropertyFilterExpression filter = std::true_type();
// Specifies how the geometry for this bucket should be created
BucketGeometryDescription geometry;

View File

@@ -39,6 +39,8 @@ private:
RasterClass parseRasterClass(JSVal value);
CompositeClass parseCompositeClass(JSVal value);
PropertyFilterExpression parseFilterOrExpression(JSVal value);
bool parseBoolean(JSVal value);
std::string parseString(JSVal value);
JSVal replaceConstant(JSVal value);

View File

@@ -14,9 +14,11 @@ Value parseValue(pbf data);
namespace util {
namespace detail {
inline int string_to_bool(std::string str) {
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
if (str == "false" || str == "null" || !str.length()) return 0;
if (str == "0" || str == "0.0" || str == "false" || str == "null" || !str.length()) return 0;
else if (str == "true") return 1;
else return -1;
}
@@ -52,44 +54,85 @@ template <> struct string_to_number<uint64_t> {
}
};
struct relaxed_equal_visitor {
bool operator()(bool lhs, bool rhs) const { return lhs == rhs; }
template <typename Operator>
struct relaxed_operator_visitor {
bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator()(bool lhs, T rhs) const { return lhs == bool(rhs); }
bool operator()(bool lhs, T rhs) const { return Operator()(lhs, bool(rhs)); }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator()(T lhs, bool rhs) const { return bool(lhs) == rhs; }
bool operator()(T lhs, bool rhs) const { return Operator()(bool(lhs), rhs); }
bool operator()(int64_t lhs, uint64_t rhs) const { return lhs < 0 ? false : uint64_t(lhs) == rhs; }
bool operator()(uint64_t lhs, int64_t rhs) const { return rhs < 0 ? false : lhs == uint64_t(rhs); }
bool operator()(int64_t lhs, uint64_t rhs) const { return lhs < 0 ? false : Operator()(uint64_t(lhs), rhs); }
bool operator()(uint64_t lhs, int64_t rhs) const { return rhs < 0 ? false : Operator()(lhs, uint64_t(rhs)); }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator()(T lhs, const std::string &rhs) const try { return lhs == string_to_number<T>()(rhs); }
bool operator()(const std::string &lhs, T rhs) const try { return Operator()(string_to_number<T>()(lhs), rhs); }
catch(...) { return false; }
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator()(const std::string &lhs, T rhs) const try { return string_to_number<T>()(lhs) == rhs; }
bool operator()(T lhs, const std::string &rhs) const try { return Operator()(lhs, string_to_number<T>()(rhs)); }
catch(...) { return false; }
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return Operator()(lhs, rhs); }
};
struct relaxed_equal_operator {
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return lhs == rhs; }
};
struct relaxed_equal {
relaxed_equal(Value const &lhs) : lhs(lhs) {}
bool operator()(Value const &rhs) const {
return apply_visitor(lhs, rhs, relaxed_equal_visitor());
}
Value const &lhs;
struct relaxed_greater_operator {
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return lhs > rhs; }
};
struct relaxed_greater_equal_operator {
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return lhs >= rhs; }
};
struct relaxed_less_operator {
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return lhs < rhs; }
};
struct relaxed_less_equal_operator {
template <typename T0, typename T1>
bool operator()(T0 lhs, T1 rhs) const { return lhs <= rhs; }
};
} // end namespace detail
inline bool relaxed_equal(Value const &lhs, Value const &rhs) {
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_equal_operator>());
}
inline bool relaxed_greater(Value const &lhs, Value const &rhs) {
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_operator>());
}
inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) {
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>());
}
inline bool relaxed_less(Value const &lhs, Value const &rhs) {
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_operator>());
}
inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) {
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>());
}
}
template <typename T>
T toNumber(const Value &value) {
if (value.is<std::string>()) return util::string_to_number<T>()(value.get<std::string>());
if (value.is<std::string>()) return util::detail::string_to_number<T>()(value.get<std::string>());
else if (value.is<bool>()) return value.get<bool>();
else if (value.is<int64_t>()) return value.get<int64_t>();
else if (value.is<uint64_t>()) return value.get<uint64_t>();

View File

@@ -0,0 +1,132 @@
#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
#include <utility>
namespace llmr {
namespace util {
template <typename T>
class recursive_wrapper
{
public:
typedef T type;
private:
T* p_;
public:
~recursive_wrapper();
recursive_wrapper();
recursive_wrapper(recursive_wrapper const& operand);
recursive_wrapper(T const& operand);
recursive_wrapper(recursive_wrapper&& operand);
recursive_wrapper(T&& operand);
private:
void assign(const T& rhs);
public:
recursive_wrapper& operator=(const recursive_wrapper& rhs)
{
assign( rhs.get() );
return *this;
}
recursive_wrapper& operator=(const T& rhs)
{
assign( rhs );
return *this;
}
void swap(recursive_wrapper& operand) noexcept
{
T* temp = operand.p_;
operand.p_ = p_;
p_ = temp;
}
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
{
swap(rhs);
return *this;
}
recursive_wrapper& operator=(T&& rhs)
{
get() = std::move(rhs);
return *this;
}
public:
T& get() { return *get_pointer(); }
const T& get() const { return *get_pointer(); }
T* get_pointer() { return p_; }
const T* get_pointer() const { return p_; }
};
template <typename T>
recursive_wrapper<T>::~recursive_wrapper()
{
delete p_;
}
template <typename T>
recursive_wrapper<T>::recursive_wrapper()
: p_(new T)
{
}
template <typename T>
recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
: p_(new T( operand.get() ))
{
}
template <typename T>
recursive_wrapper<T>::recursive_wrapper(T const& operand)
: p_(new T(operand))
{
}
template <typename T>
recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
: p_(new T( std::move(operand.get()) ))
{
}
template <typename T>
recursive_wrapper<T>::recursive_wrapper(T&& operand)
: p_(new T( std::move(operand) ))
{
}
template <typename T>
void recursive_wrapper<T>::assign(const T& rhs)
{
this->get() = rhs;
}
template <typename T>
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
{
lhs.swap(rhs);
}
}
}
#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP

View File

@@ -91,6 +91,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) {
name = layer.string();
} else if (layer.tag == 3) { // keys
keys.emplace_back(layer.string());
key_index.emplace(keys.back(), keys.size() - 1);
} else if (layer.tag == 4) { // values
values.emplace_back(std::move(parseValue(layer.message())));
} else if (layer.tag == 5) { // extent
@@ -104,81 +105,119 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) {
FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const BucketDescription& bucket_desc)
: layer(layer),
bucket_desc(bucket_desc) {
// If we filter further by field/value, parse the key/value indices first
// because protobuf doesn't mandate a particular key order.
if (bucket_desc.source_field.size()) {
// Get the ID of the desired layer key.
auto key_it = std::find(layer.keys.begin(), layer.keys.end(), bucket_desc.source_field);
if (key_it != layer.keys.end()) {
key = (int32_t)(key_it - layer.keys.begin());
}
// Get the ID of the desired layer value(s), comparing as strings in
// order to avoid numeric type mismatches between the layer and the
// style definition.
for (const Value& source_value : bucket_desc.source_value) {
auto value_it = std::find_if(layer.values.begin(), layer.values.end(), util::relaxed_equal(source_value));
if (value_it != layer.values.end()) {
values.insert((uint32_t)(value_it - layer.values.begin()));
}
}
}
}
FilteredVectorTileLayer::iterator FilteredVectorTileLayer::begin() const {
if (bucket_desc.source_field.size() && (key < 0 || values.empty())) {
// There are no valid values that we could possibly find. Abort early.
return end();
} else {
return iterator(*this, layer.data);
}
return iterator(*this, layer.data);
}
FilteredVectorTileLayer::iterator FilteredVectorTileLayer::end() const {
return iterator(*this, pbf(layer.data.end, 0));
}
FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& filter, const pbf& data)
: filter(filter),
FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& parent, const pbf& data)
: parent(parent),
feature(pbf()),
data(data) {
operator++();
}
bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) {
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;
}
}
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;
}
}
void FilteredVectorTileLayer::iterator::operator++() {
valid = false;
const PropertyFilterExpression &expression = parent.bucket_desc.filter;
while (data.next(2)) { // feature
feature = data.message();
pbf feature_pbf = feature;
BucketType type = BucketType::None;
bool skip = false;
while (!skip && feature_pbf.next()) {
bool matched = false;
// Treat the absence of any expression filters as a match.
if (expression.is<std::true_type>()) {
matched = true;
}
while (feature_pbf.next()) {
if (feature_pbf.tag == 2) { // tags
if (filter.key < 0) {
// We want to parse the entire layer anyway
if (matched) {
// There is no filter, so we want to parse the entire layer anyway.
feature_pbf.skip();
} else {
// We only want to parse some features.
skip = true;
// tags are packed varints. They should have an even length.
pbf tags_pbf = feature_pbf.message();
while (tags_pbf) {
int32_t tag_key = tags_pbf.varint();
if (tags_pbf) {
uint32_t tag_val = tags_pbf.varint();
// Now check if the tag_key/tag_val pair is included
// in the set of key/values that we are looking for.
if (filter.key == tag_key && filter.values.find(tag_val) != filter.values.end()) {
skip = false;
break; // feature_pbf loop
}
} else {
// This should not happen; otherwise the vector tile
// is invalid.
throw std::runtime_error("uneven number of feature tag ids");
}
const pbf tags_pbf = feature_pbf.message();
matched = matchesFilterExpression(expression, tags_pbf);
if (!matched) {
break; // feature_pbf loop early
}
}
} else if (feature_pbf.tag == 3) { // geometry type
@@ -189,7 +228,8 @@ void FilteredVectorTileLayer::iterator::operator++() {
default: type = BucketType::None; break;
}
if (type != filter.bucket_desc.feature_type) {
if (type != parent.bucket_desc.feature_type) {
matched = false;
break; // feature_pbf loop early
}
} else {
@@ -197,7 +237,7 @@ void FilteredVectorTileLayer::iterator::operator++() {
}
}
if (!skip && type == filter.bucket_desc.feature_type) {
if (matched) {
valid = true;
return; // data loop
} else {

View File

@@ -2,15 +2,12 @@
#include <iostream>
std::ostream& llmr::operator<<(std::ostream& os, const BucketDescription& bucket) {
os << "Bucket:" << std::endl;
os << " - type: " << (uint32_t)bucket.type << std::endl;
os << " - source_name: " << bucket.source_name << std::endl;
os << " - source_layer: " << bucket.source_layer << std::endl;
os << " - source_field: " << bucket.source_field << std::endl;
for (const Value& value : bucket.source_value) {
os << " - source_value: " << value << std::endl;
}
os << " - cap: " << (uint32_t)bucket.geometry.cap << std::endl;
os << " - join: " << (uint32_t)bucket.geometry.join << std::endl;
os << " - font: " << bucket.geometry.font << std::endl;

View File

@@ -20,6 +20,56 @@ void StyleParser::parseBuckets(JSVal value, std::map<std::string, BucketDescript
}
}
PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) {
if (value.IsArray()) {
// This is an expression.
util::recursive_wrapper<PropertyExpression> expression;
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
JSVal filter_item = value[i];
if (filter_item.IsString()) {
expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() });
} else {
expression.get().operands.emplace_back(parseFilterOrExpression(filter_item));
}
}
return std::move(expression);
} else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) {
// This is a filter.
JSVal field = value["field"];
JSVal val = value["value"];
if (!field.IsString()) {
throw Style::exception("field name must be a string");
}
const std::string field_name { field.GetString(), field.GetStringLength() };
const FilterOperator op = [&]{
if (value.HasMember("operator")) {
JSVal op_val = value["operator"];
return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() });
} else {
return FilterOperator::Equal;
}
}();
if (val.IsArray()) {
// The filter has several values, so it's an OR sub-expression.
util::recursive_wrapper<PropertyExpression> expression;
for (rapidjson::SizeType i = 0; i < val.Size(); ++i) {
expression.get().operands.emplace_back(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val[i]) }));
}
return std::move(expression);
} else {
// The filter only has a single value, so it is a real filter.
return std::move(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val) }));
}
}
return std::true_type();
}
BucketDescription StyleParser::parseBucket(JSVal value) {
BucketDescription bucket;
@@ -52,20 +102,6 @@ BucketDescription StyleParser::parseBucket(JSVal value) {
} else {
throw Style::exception("layer name must be a string");
}
} else if (name == "field") {
if (value.IsString()) {
bucket.source_field = { value.GetString(), value.GetStringLength() };
} else {
throw Style::exception("field name must be a string");
}
} else if (name == "value") {
if (value.IsArray()) {
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
bucket.source_value.push_back(parseValue(value[i]));
}
} else {
bucket.source_value.push_back(parseValue(value));
}
} else if (name == "cap") {
if (value.IsString()) {
bucket.geometry.cap = capType({ value.GetString(), value.GetStringLength() });
@@ -167,6 +203,13 @@ BucketDescription StyleParser::parseBucket(JSVal value) {
}
if (value.HasMember("filter")) {
bucket.filter = std::move(parseFilterOrExpression(value["filter"]));
} else {
// Allow a filter triple to be specified at the bucket root as well.
bucket.filter = std::move(parseFilterOrExpression(value));
}
if (bucket.feature_type == BucketType::None) {
bucket.feature_type = bucket.type;
}

View File

@@ -20,141 +20,439 @@ TEST(Variant, toString) {
TEST(Variant, RelaxedEquality) {
// Compare to bool
EXPECT_TRUE(util::relaxed_equal(bool(true))(int64_t(386)));
EXPECT_TRUE(util::relaxed_equal(bool(true))(int64_t(-7042)));
EXPECT_TRUE(util::relaxed_equal(bool(false))(int64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true))(uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(bool(false))(uint64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true))(double(386)));
EXPECT_TRUE(util::relaxed_equal(bool(false))(double(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true))(std::string("386")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("false")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("False")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("null")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("nuLL")));
EXPECT_TRUE(util::relaxed_equal(bool(false))(std::string("NULL")));
EXPECT_TRUE(util::relaxed_equal(bool(true))(bool(true)));
EXPECT_TRUE(util::relaxed_equal(bool(false))(bool(false)));
EXPECT_TRUE(util::relaxed_equal(bool(true), int64_t(386)));
EXPECT_TRUE(util::relaxed_equal(bool(true), int64_t(-7042)));
EXPECT_TRUE(util::relaxed_equal(bool(false), int64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true), uint64_t(386)));
EXPECT_TRUE(util::relaxed_equal(bool(false), uint64_t(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true), double(386)));
EXPECT_TRUE(util::relaxed_equal(bool(false), double(0)));
EXPECT_TRUE(util::relaxed_equal(bool(true), std::string("386")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("false")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("False")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("null")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("nuLL")));
EXPECT_TRUE(util::relaxed_equal(bool(false), std::string("NULL")));
EXPECT_TRUE(util::relaxed_equal(bool(true), bool(true)));
EXPECT_TRUE(util::relaxed_equal(bool(false), bool(false)));
EXPECT_FALSE(util::relaxed_equal(bool(true))(int64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true))(uint64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true))(double(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true))(std::string("")));
EXPECT_FALSE(util::relaxed_equal(bool(true))(std::string("false")));
EXPECT_FALSE(util::relaxed_equal(bool(true))(std::string("FALSE")));
EXPECT_FALSE(util::relaxed_equal(bool(true))(std::string("null")));
EXPECT_FALSE(util::relaxed_equal(bool(true))(std::string("Null")));
EXPECT_FALSE(util::relaxed_equal(bool(false))(int64_t(-754)));
EXPECT_FALSE(util::relaxed_equal(bool(false))(uint64_t(3)));
EXPECT_FALSE(util::relaxed_equal(bool(false))(double(3.145)));
EXPECT_FALSE(util::relaxed_equal(bool(false))(std::string("test")));
EXPECT_FALSE(util::relaxed_equal(bool(true))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(bool(false))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(bool(true), int64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true), uint64_t(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true), double(0)));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("FALSE")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("null")));
EXPECT_FALSE(util::relaxed_equal(bool(true), std::string("Null")));
EXPECT_FALSE(util::relaxed_equal(bool(false), int64_t(-754)));
EXPECT_FALSE(util::relaxed_equal(bool(false), uint64_t(3)));
EXPECT_FALSE(util::relaxed_equal(bool(false), double(3.145)));
EXPECT_FALSE(util::relaxed_equal(bool(false), std::string("test")));
EXPECT_FALSE(util::relaxed_equal(bool(true), bool(false)));
EXPECT_FALSE(util::relaxed_equal(bool(false), bool(true)));
// Compare to int64_t
EXPECT_TRUE(util::relaxed_equal(int64_t(386))(int64_t(386)));
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_TRUE(util::relaxed_equal(int64_t(1))(std::string("true")));
EXPECT_TRUE(util::relaxed_equal(int64_t(0))(std::string("false")));
EXPECT_TRUE(util::relaxed_equal(int64_t(386), int64_t(386)));
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_TRUE(util::relaxed_equal(int64_t(1), std::string("true")));
EXPECT_TRUE(util::relaxed_equal(int64_t(0), std::string("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)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386))(double(387)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386))(std::string("387")));
EXPECT_FALSE(util::relaxed_equal(int64_t(1))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(int64_t(0))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(int64_t(1))(std::string("false")));
EXPECT_FALSE(util::relaxed_equal(int64_t(0))(std::string("true")));
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)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386), double(387)));
EXPECT_FALSE(util::relaxed_equal(int64_t(386), std::string("387")));
EXPECT_FALSE(util::relaxed_equal(int64_t(1), bool(false)));
EXPECT_FALSE(util::relaxed_equal(int64_t(0), bool(true)));
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_TRUE(util::relaxed_equal(uint64_t(1))(std::string("true")));
EXPECT_TRUE(util::relaxed_equal(uint64_t(0))(std::string("false")));
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_TRUE(util::relaxed_equal(uint64_t(1), std::string("true")));
EXPECT_TRUE(util::relaxed_equal(uint64_t(0), std::string("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)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386))(double(387)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386))(std::string("387")));
EXPECT_FALSE(util::relaxed_equal(uint64_t(1))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(1))(std::string("false")));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0))(std::string("true")));
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)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386), double(387)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(386), std::string("387")));
EXPECT_FALSE(util::relaxed_equal(uint64_t(1), bool(false)));
EXPECT_FALSE(util::relaxed_equal(uint64_t(0), bool(true)));
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_TRUE(util::relaxed_equal(double(1))(std::string("true")));
EXPECT_TRUE(util::relaxed_equal(double(1))(std::string("TRue")));
EXPECT_TRUE(util::relaxed_equal(double(0))(std::string("false")));
EXPECT_TRUE(util::relaxed_equal(double(0))(std::string("FALSe")));
EXPECT_TRUE(util::relaxed_equal(double(0))(std::string("null")));
EXPECT_TRUE(util::relaxed_equal(double(0))(std::string("Null")));
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_TRUE(util::relaxed_equal(double(1), std::string("true")));
EXPECT_TRUE(util::relaxed_equal(double(1), std::string("TRue")));
EXPECT_TRUE(util::relaxed_equal(double(0), std::string("false")));
EXPECT_TRUE(util::relaxed_equal(double(0), std::string("FALSe")));
EXPECT_TRUE(util::relaxed_equal(double(0), std::string("null")));
EXPECT_TRUE(util::relaxed_equal(double(0), std::string("Null")));
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)));
EXPECT_FALSE(util::relaxed_equal(double(0))(uint64_t(1)));
EXPECT_FALSE(util::relaxed_equal(double(386))(double(387)));
EXPECT_FALSE(util::relaxed_equal(double(386))(std::string("387")));
EXPECT_FALSE(util::relaxed_equal(double(1))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(double(0))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(double(1))(std::string("false")));
EXPECT_FALSE(util::relaxed_equal(double(1))(std::string("False")));
EXPECT_FALSE(util::relaxed_equal(double(1))(std::string("null")));
EXPECT_FALSE(util::relaxed_equal(double(1))(std::string("NULL")));
EXPECT_FALSE(util::relaxed_equal(double(0))(std::string("true")));
EXPECT_FALSE(util::relaxed_equal(double(0))(std::string("TRUE")));
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)));
EXPECT_FALSE(util::relaxed_equal(double(0), uint64_t(1)));
EXPECT_FALSE(util::relaxed_equal(double(386), double(387)));
EXPECT_FALSE(util::relaxed_equal(double(386), std::string("387")));
EXPECT_FALSE(util::relaxed_equal(double(1), bool(false)));
EXPECT_FALSE(util::relaxed_equal(double(0), bool(true)));
EXPECT_FALSE(util::relaxed_equal(double(1), std::string("false")));
EXPECT_FALSE(util::relaxed_equal(double(1), std::string("False")));
EXPECT_FALSE(util::relaxed_equal(double(1), std::string("null")));
EXPECT_FALSE(util::relaxed_equal(double(1), std::string("NULL")));
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("true"))(bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("True"))(bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("some string"))(bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("false"))(bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("fAlse"))(bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("null"))(bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("NULl"))(bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(""))(bool(false)));
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("true"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("True"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("some string"), bool(true)));
EXPECT_TRUE(util::relaxed_equal(std::string("false"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("fAlse"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("null"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string("NULl"), bool(false)));
EXPECT_TRUE(util::relaxed_equal(std::string(""), bool(false)));
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)));
EXPECT_FALSE(util::relaxed_equal(std::string("386"))(uint64_t(387)));
EXPECT_FALSE(util::relaxed_equal(std::string("386.36"))(double(386.37)));
EXPECT_FALSE(util::relaxed_equal(std::string("true"))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("TRUE"))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("some string"))(bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("false"))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("FALSE"))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("null"))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("NULl"))(bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(""))(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)));
EXPECT_FALSE(util::relaxed_equal(std::string("386"), uint64_t(387)));
EXPECT_FALSE(util::relaxed_equal(std::string("386.36"), double(386.37)));
EXPECT_FALSE(util::relaxed_equal(std::string("true"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("TRUE"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("some string"), bool(false)));
EXPECT_FALSE(util::relaxed_equal(std::string("false"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("FALSE"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("null"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string("NULl"), bool(true)));
EXPECT_FALSE(util::relaxed_equal(std::string(""), bool(true)));
}
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_TRUE(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_TRUE(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_TRUE(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_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(bool(true), double(false)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), std::string("388")));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater(double(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater(bool(true), std::string("388")));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater(double(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater(bool(true), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater(double(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater(bool(true), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), double(388.7)));
EXPECT_FALSE(util::relaxed_greater(uint64_t(387), double(388.7)));
EXPECT_FALSE(util::relaxed_greater(int64_t(387), double(388.7)));
EXPECT_FALSE(util::relaxed_greater(double(387), double(388.7)));
EXPECT_FALSE(util::relaxed_greater(bool(true), double(388)));
EXPECT_FALSE(util::relaxed_greater(std::string("387"), bool(true)));
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(bool(true), bool(true)));
}
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_TRUE(util::relaxed_greater_equal(std::string("387"), uint64_t(386)));
EXPECT_TRUE(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_TRUE(util::relaxed_greater_equal(std::string("387"), int64_t(386)));
EXPECT_TRUE(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_TRUE(util::relaxed_greater_equal(std::string("387"), double(386.7)));
EXPECT_TRUE(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_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_TRUE(util::relaxed_greater_equal(bool(true), bool(false)));
EXPECT_TRUE(util::relaxed_greater_equal(bool(true), bool(true)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), std::string("388")));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), std::string("388")));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), uint64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), int64_t(388)));
EXPECT_FALSE(util::relaxed_greater_equal(std::string("387"), double(388.7)));
EXPECT_FALSE(util::relaxed_greater_equal(uint64_t(387), double(388.7)));
EXPECT_FALSE(util::relaxed_greater_equal(int64_t(387), double(388.7)));
EXPECT_FALSE(util::relaxed_greater_equal(double(387), double(388.7)));
}
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_TRUE(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_TRUE(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_TRUE(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_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_TRUE(util::relaxed_less(bool(false), bool(true)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), std::string("386")));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less(int64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less(double(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less(bool(true), std::string("386")));
EXPECT_FALSE(util::relaxed_less(std::string("387"), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(int64_t(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(double(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(bool(true), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(int64_t(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(double(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(bool(true), int64_t(386)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), double(386.7)));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), double(386.7)));
EXPECT_FALSE(util::relaxed_less(int64_t(387), double(386.7)));
EXPECT_FALSE(util::relaxed_less(double(387), double(386.7)));
EXPECT_FALSE(util::relaxed_less(bool(true), double(386)));
EXPECT_FALSE(util::relaxed_less(std::string("387"), bool(true)));
EXPECT_FALSE(util::relaxed_less(uint64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_less(int64_t(387), bool(true)));
EXPECT_FALSE(util::relaxed_less(double(387), bool(true)));
EXPECT_FALSE(util::relaxed_less(bool(true), bool(true)));
}
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_TRUE(util::relaxed_less_equal(std::string("387"), uint64_t(388)));
EXPECT_TRUE(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_TRUE(util::relaxed_less_equal(std::string("387"), int64_t(388)));
EXPECT_TRUE(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_TRUE(util::relaxed_less_equal(std::string("387"), double(387.7)));
EXPECT_TRUE(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_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_TRUE(util::relaxed_less_equal(bool(false), bool(true)));
EXPECT_TRUE(util::relaxed_less_equal(bool(false), bool(false)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), std::string("386")));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less_equal(double(387), std::string("386")));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(double(387), uint64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), int64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(double(387), int64_t(386)));
EXPECT_FALSE(util::relaxed_less_equal(std::string("387"), double(386.7)));
EXPECT_FALSE(util::relaxed_less_equal(uint64_t(387), double(386.7)));
EXPECT_FALSE(util::relaxed_less_equal(int64_t(387), double(386.7)));
EXPECT_FALSE(util::relaxed_less_equal(double(387), double(386.7)));
}