diff --git a/bin/style.js b/bin/style.js index eb055196f..4157e1e8f 100644 --- a/bin/style.js +++ b/bin/style.js @@ -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}, diff --git a/include/llmr/map/filter_expression.hpp b/include/llmr/map/filter_expression.hpp new file mode 100644 index 000000000..50e6ce1d7 --- /dev/null +++ b/include/llmr/map/filter_expression.hpp @@ -0,0 +1,128 @@ +#ifndef LLMR_MAP_FILTER_EXPRESSION +#define LLMR_MAP_FILTER_EXPRESSION + +#include +#include + +#include +#include + +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, + util::recursive_wrapper, + 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 operands; +}; + + +} + +#endif diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index 1e809556e..904cc9a2e 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -5,8 +5,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -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 values; }; std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement); @@ -82,6 +87,7 @@ public: std::string name; uint32_t extent = 4096; std::vector keys; + std::unordered_map key_index; std::vector values; std::map> shaping; }; diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 3b6fc4313..f77ff5170 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -5,8 +5,9 @@ #include #include -#include "value.hpp" -#include "../util/vec.hpp" +#include +#include +#include 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 source_value; + + PropertyFilterExpression filter = std::true_type(); // Specifies how the geometry for this bucket should be created BucketGeometryDescription geometry; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index c00c49677..10f367475 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -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); diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp index f29590363..c6d6f50b9 100644 --- a/include/llmr/style/value.hpp +++ b/include/llmr/style/value.hpp @@ -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 { } }; -struct relaxed_equal_visitor { - bool operator()(bool lhs, bool rhs) const { return lhs == rhs; } +template +struct relaxed_operator_visitor { + bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); } template ::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 ::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 ::value>::type> - bool operator()(T lhs, const std::string &rhs) const try { return lhs == string_to_number()(rhs); } + bool operator()(const std::string &lhs, T rhs) const try { return Operator()(string_to_number()(lhs), rhs); } catch(...) { return false; } template ::value>::type> - bool operator()(const std::string &lhs, T rhs) const try { return string_to_number()(lhs) == rhs; } + bool operator()(T lhs, const std::string &rhs) const try { return Operator()(lhs, string_to_number()(rhs)); } catch(...) { return false; } + template + bool operator()(T0 lhs, T1 rhs) const { return Operator()(lhs, rhs); } +}; + +struct relaxed_equal_operator { template 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 + bool operator()(T0 lhs, T1 rhs) const { return lhs > rhs; } }; + +struct relaxed_greater_equal_operator { + template + bool operator()(T0 lhs, T1 rhs) const { return lhs >= rhs; } +}; + +struct relaxed_less_operator { + template + bool operator()(T0 lhs, T1 rhs) const { return lhs < rhs; } +}; + +struct relaxed_less_equal_operator { + template + 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()); +} + +inline bool relaxed_greater(Value const &lhs, Value const &rhs) { + return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); +} + +inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) { + return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); +} + +inline bool relaxed_less(Value const &lhs, Value const &rhs) { + return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); +} + +inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) { + return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor()); +} + } template T toNumber(const Value &value) { - if (value.is()) return util::string_to_number()(value.get()); + if (value.is()) return util::detail::string_to_number()(value.get()); else if (value.is()) return value.get(); else if (value.is()) return value.get(); else if (value.is()) return value.get(); diff --git a/include/llmr/util/recursive_wrapper.hpp b/include/llmr/util/recursive_wrapper.hpp new file mode 100644 index 000000000..557b576c0 --- /dev/null +++ b/include/llmr/util/recursive_wrapper.hpp @@ -0,0 +1,132 @@ +#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP + +#include + +namespace llmr { + +namespace util { + +template +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 +recursive_wrapper::~recursive_wrapper() +{ + delete p_; +} + +template +recursive_wrapper::recursive_wrapper() + : p_(new T) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper const& operand) + : p_(new T( operand.get() )) +{ +} + +template +recursive_wrapper::recursive_wrapper(T const& operand) + : p_(new T(operand)) +{ +} + +template +recursive_wrapper::recursive_wrapper(recursive_wrapper&& operand) + : p_(new T( std::move(operand.get()) )) +{ +} + +template +recursive_wrapper::recursive_wrapper(T&& operand) + : p_(new T( std::move(operand) )) +{ +} + +template +void recursive_wrapper::assign(const T& rhs) +{ + this->get() = rhs; +} + +template +inline void swap(recursive_wrapper& lhs, recursive_wrapper& rhs) noexcept +{ + lhs.swap(rhs); +} + +} + +} + +#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index f0f5a85cd..97adec277 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -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>()) { + return matchesFilter(filterExpression.get>().get(), tags_pbf); + } else if (filterExpression.is>()) { + return matchesExpression(filterExpression.get>().get(), tags_pbf); + } else if (filterExpression.is()) { + return true; + } else { + return false; + } +} + + +bool FilteredVectorTileLayer::iterator::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()) { + 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 { diff --git a/src/style/bucket_description.cpp b/src/style/bucket_description.cpp index 864603e31..b154c3a17 100644 --- a/src/style/bucket_description.cpp +++ b/src/style/bucket_description.cpp @@ -2,15 +2,12 @@ #include + 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; diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 2b6c0e3f2..b686c0ec5 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -20,6 +20,56 @@ void StyleParser::parseBuckets(JSVal value, std::map expression; + for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { + JSVal filter_item = value[i]; + + if (filter_item.IsString()) { + expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() }); + } else { + expression.get().operands.emplace_back(parseFilterOrExpression(filter_item)); + } + } + return std::move(expression); + } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) { + // This is a filter. + JSVal field = value["field"]; + JSVal val = value["value"]; + + if (!field.IsString()) { + throw Style::exception("field name must be a string"); + } + + const std::string field_name { field.GetString(), field.GetStringLength() }; + const FilterOperator op = [&]{ + if (value.HasMember("operator")) { + JSVal op_val = value["operator"]; + return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() }); + } else { + return FilterOperator::Equal; + } + }(); + + if (val.IsArray()) { + // The filter has several values, so it's an OR sub-expression. + util::recursive_wrapper expression; + for (rapidjson::SizeType i = 0; i < val.Size(); ++i) { + expression.get().operands.emplace_back(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val[i]) })); + } + + return std::move(expression); + } else { + // The filter only has a single value, so it is a real filter. + return std::move(util::recursive_wrapper(PropertyFilter { field_name, op, parseValue(val) })); + } + } + + return std::true_type(); +} + 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; } diff --git a/test/variant.cpp b/test/variant.cpp index 9a855d15c..6512b398f 100644 --- a/test/variant.cpp +++ b/test/variant.cpp @@ -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))); }