Merge branch 'master' of github.com:mapbox/mapbox-gl-native into android-mason

This commit is contained in:
Dane Springmeyer
2014-11-04 21:28:18 -05:00
46 changed files with 903 additions and 3593 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ enum class PropertyKey {
LineTranslateY,
LineTranslateAnchor,
LineWidth,
LineOffset,
LineGapWidth,
LineBlur,
LineDashArray, // for transitions only
LineDashLand,

View File

@@ -64,8 +64,7 @@ public:
float line_height = 1.2f * 24 /* em */;
float letter_spacing = 0.0f * 24 /* em */;
TextJustifyType justify = TextJustifyType::Center;
TextHorizontalAlignType horizontal_align = TextHorizontalAlignType::Center;
TextVerticalAlignType vertical_align = TextVerticalAlignType::Center;
TextAnchorType anchor = TextAnchorType::Center;
float max_angle = 45.0f /* degrees */;
float rotate = 0.0f;
float slant = 0.0f;

View File

@@ -49,11 +49,11 @@ private:
util::ptr<StyleLayer> createLayer(JSVal value);
void parseLayers();
void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair);
void parseStyles(JSVal value, std::map<ClassID, ClassProperties> &styles);
void parseStyle(JSVal, ClassProperties &properties);
void parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints);
void parsePaint(JSVal, ClassProperties &properties);
void parseReference(JSVal value, util::ptr<StyleLayer> &layer);
void parseBucket(JSVal value, util::ptr<StyleLayer> &layer);
void parseRender(JSVal value, util::ptr<StyleLayer> &layer);
void parseLayout(JSVal value, util::ptr<StyleLayer> &layer);
void parseSprite(JSVal value);
void parseGlyphURL(JSVal value);
@@ -85,11 +85,7 @@ private:
template <typename T>
T parseFunctionArgument(JSVal value);
FilterExpression parseFilter(JSVal, FilterExpression::Operator op);
FilterExpression parseFilter(JSVal);
Value parseValue(JSVal value);
std::vector<Value> parseValues(JSVal values);
private:
std::unordered_map<std::string, const rapidjson::Value *> constants;

View File

@@ -34,7 +34,7 @@ struct LineProperties {
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
float width = 1;
float offset = 0;
float gap_width = 0;
float blur = 0;
std::array<float, 2> dash_array = {{ 1, -1 }};
std::string image;

View File

@@ -152,30 +152,28 @@ MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
// -------------------------------------------------------------------------------------------------
enum class TextHorizontalAlignType : uint8_t {
enum class TextAnchorType : uint8_t {
Center,
Left,
Center,
Right,
};
MBGL_DEFINE_ENUM_CLASS(TextHorizontalAlignTypeClass, TextHorizontalAlignType, {
{ TextHorizontalAlignType::Left, "left" },
{ TextHorizontalAlignType::Center, "center" },
{ TextHorizontalAlignType::Right, "right" },
});
// -------------------------------------------------------------------------------------------------
enum class TextVerticalAlignType : uint8_t {
Top,
Center,
Bottom,
TopLeft,
TopRight,
BottomLeft,
BottomRight
};
MBGL_DEFINE_ENUM_CLASS(TextVerticalAlignTypeClass, TextVerticalAlignType, {
{ TextVerticalAlignType::Top, "top" },
{ TextVerticalAlignType::Center, "center" },
{ TextVerticalAlignType::Bottom, "bottom" },
MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, {
{ TextAnchorType::Center, "center" },
{ TextAnchorType::Left, "left" },
{ TextAnchorType::Right, "right" },
{ TextAnchorType::Top, "top" },
{ TextAnchorType::Bottom, "bottom" },
{ TextAnchorType::TopLeft, "top-left" },
{ TextAnchorType::TopRight, "top-right" },
{ TextAnchorType::BottomLeft, "bottom-left" },
{ TextAnchorType::BottomRight, "bottom-right" }
});
// -------------------------------------------------------------------------------------------------

View File

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

View File

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

View File

@@ -1,7 +1,9 @@
#ifndef MBGL_UTIL_TIME
#define MBGL_UTIL_TIME
#include <string>
#include <cstdint>
#include <ctime>
namespace mbgl {
@@ -15,6 +17,10 @@ namespace util {
// comparisons between different timestamps produce meaningful values.
timestamp now();
// Returns the RFC1123 formatted date. E.g. "Tue, 04 Nov 2014 02:13:24 GMT"
std::string rfc1123(std::time_t time);
}
// used for time conversions

View File

@@ -11,8 +11,7 @@ namespace util {
class utf8_to_utf32 {
public:
explicit utf8_to_utf32() {}
std::u32string convert(std::string const& utf8)
static std::u32string convert(std::string const& utf8)
{
boost::u8_to_u32_iterator<std::string::const_iterator> begin(utf8.begin());
boost::u8_to_u32_iterator<std::string::const_iterator> end(utf8.end());

View File

@@ -11,7 +11,6 @@
#include <sstream>
GLFWView *view = nullptr;
void quit_handler(int) {
@@ -28,16 +27,32 @@ int main(int argc, char *argv[]) {
mbgl::Log::Set<mbgl::StderrLogBackend>();
int fullscreen_flag = 0;
std::string style;
const struct option long_options[] = {
{"fullscreen", no_argument, &fullscreen_flag, 1},
{"fullscreen", no_argument, &fullscreen_flag, 'f'},
{"style", required_argument, 0, 's'},
{0, 0, 0, 0}
};
while (true) {
int option_index = 0;
int c = getopt_long(argc, argv, "f", long_options, &option_index);
if (c == -1) break;
int opt = getopt_long(argc, argv, "fs:", long_options, &option_index);
if (opt == -1) break;
switch (opt)
{
case 0:
if (long_options[option_index].flag != 0)
break;
case 'f':
// handle fullscreen_flag
break;
case 's':
style = std::string("file://") + std::string(optarg);
default:
break;
}
}
// sigint handling
@@ -65,7 +80,9 @@ int main(int argc, char *argv[]) {
}
// Load style
const std::string style = std::string("file://") + uv::cwd() + std::string("/../../styles/styles/bright-v5.json");
if (style.empty())
style = std::string("file://") + uv::cwd() + std::string("/../../styles/styles/bright-v6.json");
map.setStyleURL(style);
int ret = view->run();

View File

@@ -100,7 +100,7 @@ int main() {
if (accessToken) map.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]);
// Load style
const std::string path([[[NSBundle mainBundle] pathForResource:@"bright-v5" ofType:@"json" inDirectory:@"styles/"] UTF8String]);
const std::string path([[[NSBundle mainBundle] pathForResource:@"bright-v6" ofType:@"json" inDirectory:@"styles/"] UTF8String]);
map.setStyleURL(std::string("file://") + path);

View File

@@ -1,14 +1,13 @@
#include <mbgl/storage/http_request_baton.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/parsedate.h>
#include <mbgl/util/time.hpp>
#include <uv.h>
#include <mbgl/util/uv.hpp>
#import <Foundation/Foundation.h>
#include <ctime>
#include <xlocale.h>
namespace mbgl {
@@ -21,9 +20,6 @@ void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
// Starts the request.
util::ptr<HTTPRequestBaton> baton = ptr;
// Create a C locale
static locale_t locale = newlocale(LC_ALL_MASK, nullptr, nullptr);
dispatch_once(&request_initialize, ^{
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForResource = 30;
@@ -39,11 +35,8 @@ void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
if (!baton->response->etag.empty()) {
[request addValue:@(baton->response->etag.c_str()) forHTTPHeaderField:@"If-None-Match"];
} else if (baton->response->modified) {
const time_t modified = baton->response->modified;
struct tm *timeinfo = std::gmtime(&modified);
char buffer[32];
strftime_l(buffer, 32, "%a, %d %b %Y %H:%M:%S GMT", timeinfo, locale);
[request addValue:@(buffer) forHTTPHeaderField:@"If-Modified-Since"];
const std::string time = util::rfc1123(baton->response->modified);
[request addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"];
}
}

View File

@@ -2,6 +2,7 @@
#include <mbgl/util/uv-messenger.h>
#include <mbgl/util/std.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/time.hpp>
#include <uv.h>
#include <curl/curl.h>
@@ -9,8 +10,6 @@
#include <queue>
#include <cassert>
#include <cstring>
#include <ctime>
#include <xlocale.h>
// This file contains code from http://curl.haxx.se/libcurl/c/multi-uv.html:
@@ -369,9 +368,6 @@ void start_request(void *const ptr) {
util::ptr<HTTPRequestBaton> &baton = *baton_guard.get();
assert(baton);
// Create a C locale
static locale_t locale = newlocale(LC_ALL_MASK, nullptr, nullptr);
CURL *handle = nullptr;
if (!handles.empty()) {
handle = handles.front();
@@ -390,11 +386,9 @@ void start_request(void *const ptr) {
const std::string header = std::string("If-None-Match: ") + baton->response->etag;
context->headers = curl_slist_append(context->headers, header.c_str());
} else if (baton->response->modified) {
const time_t modified = baton->response->modified;
struct tm *timeinfo = std::gmtime(&modified);
char buffer[64];
strftime_l(buffer, 64, "If-Modified-Since: %a, %d %b %Y %H:%M:%S GMT", timeinfo, locale);
context->headers = curl_slist_append(context->headers, buffer);
const std::string time = std::string("If-Modified-Since: ") +
util::rfc1123(baton->response->modified);
context->headers = curl_slist_append(context->headers, time.c_str());
}
}

View File

@@ -1,6 +1,5 @@
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/style/filter_expression_private.hpp>
#include <mbgl/style/filter_comparison_private.hpp>
#include <algorithm>
#include <iostream>
@@ -123,81 +122,6 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren
operator++();
}
//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) {
// if (filterExpression.empty()) {
// return true;
// }
//
//
//
//
// if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) {
// return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf);
// } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) {
// return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf);
// } else if (filterExpression.is<std::true_type>()) {
// return true;
// } else {
// return false;
// }
// return true;
//}
//
//bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) {
// auto field_it = parent.layer.key_index.find(filter.field);
// if (field_it != parent.layer.key_index.end()) {
// const uint32_t filter_key = field_it->second;
//
// // Now loop through all the key/value pair tags.
// // tags are packed varints. They should have an even length.
// pbf tags_pbf = const_tags_pbf;
// while (tags_pbf) {
// uint32_t tag_key = tags_pbf.varint();
// if (!tags_pbf) {
// // This should not happen; otherwise the vector tile
// // is invalid.
// throw std::runtime_error("uneven number of feature tag ids");
// }
// uint32_t tag_val = tags_pbf.varint();
//
// if (tag_key == filter_key) {
// if (parent.layer.values.size() > tag_val) {
// const Value &value = parent.layer.values[tag_val];
// return filter.compare(value);
// } else {
// throw std::runtime_error("feature references out of range value");
// }
// }
// }
// }
//
// // The feature doesn't contain the field that we're looking to compare.
// // Depending on the filter, this may still be okay.
// return filter.isMissingFieldOkay();
//}
//
//bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) {
// if (expression.op == ExpressionOperator::Or) {
// for (const PropertyFilterExpression &filterExpression : expression.operands) {
// if (matchesFilterExpression(filterExpression, tags_pbf)) {
// return true;
// }
// }
// return false;
// } else if (expression.op == ExpressionOperator::And) {
// for (const PropertyFilterExpression &filterExpression : expression.operands) {
// if (!matchesFilterExpression(filterExpression, tags_pbf)) {
// return false;
// }
// }
// return true;
// } else {
// return false;
// }
//}
//
VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {}
@@ -205,8 +129,12 @@ void VectorTileTagExtractor::setTags(const pbf &pbf) {
tags_ = pbf;
}
std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) const {
std::vector<Value> values;
mapbox::util::optional<Value> VectorTileTagExtractor::getValue(const std::string &key) const {
if (key == "$type") {
return Value(uint64_t(type_));
}
mapbox::util::optional<Value> value;
auto field_it = layer_.key_index.find(key);
if (field_it != layer_.key_index.end()) {
@@ -221,14 +149,14 @@ std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) con
if (!tags_pbf) {
// This should not happen; otherwise the vector tile is invalid.
fprintf(stderr, "[WARNING] uneven number of feature tag ids\n");
return values;
return value;
}
// Note: We need to run this command in all cases, even if the keys don't match.
tag_val = tags_pbf.varint();
if (tag_key == filter_key) {
if (layer_.values.size() > tag_val) {
values.emplace_back(layer_.values[tag_val]);
value = layer_.values[tag_val];
} else {
fprintf(stderr, "[WARNING] feature references out of range value\n");
break;
@@ -237,16 +165,14 @@ std::vector<Value> VectorTileTagExtractor::getValues(const std::string &key) con
}
}
return values;
return value;
}
void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) {
void VectorTileTagExtractor::setType(FeatureType type) {
type_ = type;
}
FilterExpression::GeometryType VectorTileTagExtractor::getType() const {
return type_;
}
template bool mbgl::evaluate(const FilterExpression&, const VectorTileTagExtractor&);
void FilteredVectorTileLayer::iterator::operator++() {
valid = false;
@@ -256,36 +182,21 @@ void FilteredVectorTileLayer::iterator::operator++() {
while (data.next(2)) { // feature
feature = data.message();
pbf feature_pbf = feature;
bool matched = false;
// Treat the absence of any expression filters as a match.
if (expression.empty()) {
matched = true;
}
VectorTileTagExtractor extractor(parent.layer);
if (!matched) {
VectorTileTagExtractor extractor(parent.layer);
// Retrieve the basic information
while (feature_pbf.next()) {
if (feature_pbf.tag == 2) { // tags
extractor.setTags(feature_pbf.message());
} else if (feature_pbf.tag == 3) { // geometry type
switch (FeatureType(feature_pbf.varint())) {
case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break;
case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::LineString); break;
case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break;
default: break;
}
} else {
feature_pbf.skip();
}
// Retrieve the basic information
while (feature_pbf.next()) {
if (feature_pbf.tag == 2) { // tags
extractor.setTags(feature_pbf.message());
} else if (feature_pbf.tag == 3) { // geometry type
extractor.setType(FeatureType(feature_pbf.varint()));
} else {
feature_pbf.skip();
}
matched = expression.compare(extractor);
}
if (matched) {
if (evaluate(expression, extractor)) {
valid = true;
return; // data loop
} else {

View File

@@ -17,11 +17,9 @@ void Painter::renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, c
float antialiasing = 1 / state.getPixelRatio();
float width = properties.width;
float offset = properties.offset / 2;
float offset = properties.gap_width == 0 ? 0 : (properties.gap_width + width) / 2;
float blur = properties.blur + antialiasing;
// These are the radii of the line. We are limiting it to 16, which will result
// in a point size of 64 on retina.
float inset = std::fmin((std::fmax(-1, offset - width / 2 - antialiasing / 2) + 1), 16.0f);
float outset = std::fmin(offset + width / 2 + antialiasing / 2, 16.0f);

View File

@@ -52,8 +52,6 @@ std::vector<SymbolFeature> SymbolBucket::processFeatures(const VectorTileLayer &
return features;
}
util::utf8_to_utf32 ucs4conv;
// Determine and load glyph ranges
std::set<GlyphRange> ranges;
@@ -72,7 +70,7 @@ std::vector<SymbolFeature> SymbolBucket::processFeatures(const VectorTileLayer &
u8string = platform::lowercase(u8string);
}
ft.label = ucs4conv.convert(u8string);
ft.label = util::utf8_to_utf32::convert(u8string);
if (ft.label.size()) {
// Loop through all characters of this text and collect unique codepoints.
@@ -105,16 +103,41 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
const std::vector<SymbolFeature> features = processFeatures(layer, filter, glyphStore, sprite);
float horizontalAlign = 0.5;
if (properties.text.horizontal_align == TextHorizontalAlignType::Right)
horizontalAlign = 1;
else if (properties.text.horizontal_align == TextHorizontalAlignType::Left)
horizontalAlign = 0;
float verticalAlign = 0.5;
if (properties.text.vertical_align == TextVerticalAlignType::Bottom)
verticalAlign = 1;
else if (properties.text.vertical_align == TextVerticalAlignType::Top)
verticalAlign = 0;
switch (properties.text.anchor) {
case TextAnchorType::Top:
case TextAnchorType::Bottom:
case TextAnchorType::Center:
break;
case TextAnchorType::Right:
case TextAnchorType::TopRight:
case TextAnchorType::BottomRight:
horizontalAlign = 1;
break;
case TextAnchorType::Left:
case TextAnchorType::TopLeft:
case TextAnchorType::BottomLeft:
horizontalAlign = 0;
break;
}
switch (properties.text.anchor) {
case TextAnchorType::Left:
case TextAnchorType::Right:
case TextAnchorType::Center:
break;
case TextAnchorType::Bottom:
case TextAnchorType::BottomLeft:
case TextAnchorType::BottomRight:
verticalAlign = 1;
break;
case TextAnchorType::Top:
case TextAnchorType::TopLeft:
case TextAnchorType::TopRight:
verticalAlign = 0;
break;
}
float justify = 0.5;
if (properties.text.justify == TextJustifyType::Right) justify = 1;

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::LineTranslateY, defaultStyleProperties<LineProperties>().translate[1] },
{ PropertyKey::LineTranslateAnchor, defaultStyleProperties<LineProperties>().translateAnchor },
{ PropertyKey::LineWidth, defaultStyleProperties<LineProperties>().width },
{ PropertyKey::LineOffset, defaultStyleProperties<LineProperties>().offset },
{ PropertyKey::LineGapWidth, defaultStyleProperties<LineProperties>().gap_width },
{ PropertyKey::LineBlur, defaultStyleProperties<LineProperties>().blur },
{ PropertyKey::LineDashLand, defaultStyleProperties<LineProperties>().dash_array[0] },
{ PropertyKey::LineDashGap, defaultStyleProperties<LineProperties>().dash_array[1] },

View File

@@ -183,7 +183,7 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const times
applyTransitionedStyleProperty(PropertyKey::LineTranslateY, line.translate[1], z, now);
applyStyleProperty(PropertyKey::LineTranslateAnchor, line.translateAnchor, z, now);
applyTransitionedStyleProperty(PropertyKey::LineWidth, line.width, z, now);
applyTransitionedStyleProperty(PropertyKey::LineOffset, line.offset, z, now);
applyTransitionedStyleProperty(PropertyKey::LineGapWidth, line.gap_width, z, now);
applyTransitionedStyleProperty(PropertyKey::LineBlur, line.blur, z, now);
applyTransitionedStyleProperty(PropertyKey::LineDashLand, line.dash_array[0], z, now);
applyTransitionedStyleProperty(PropertyKey::LineDashGap, line.dash_array[1], z, now);

View File

@@ -485,12 +485,12 @@ util::ptr<StyleLayer> StyleParser::createLayer(JSVal value) {
return nullptr;
}
// Parse styles already, as they can't be inherited anyway.
std::map<ClassID, ClassProperties> styles;
parseStyles(value, styles);
// Parse paints already, as they can't be inherited anyway.
std::map<ClassID, ClassProperties> paints;
parsePaints(value, paints);
util::ptr<StyleLayer> layer = std::make_shared<StyleLayer>(
layer_id, std::move(styles));
layer_id, std::move(paints));
if (value.HasMember("layers")) {
layer->layers = createLayers(value["layers"]);
@@ -548,21 +548,21 @@ void StyleParser::parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair) {
#pragma mark - Parse Styles
void StyleParser::parseStyles(JSVal value, std::map<ClassID, ClassProperties> &styles) {
void StyleParser::parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints) {
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
for (; itr != value.MemberEnd(); ++itr) {
const std::string name { itr->name.GetString(), itr->name.GetStringLength() };
if (name == "style") {
parseStyle(replaceConstant(itr->value), styles[ClassID::Default]);
} else if (name.compare(0, 6, "style.") == 0 && name.length() > 6) {
if (name == "paint") {
parsePaint(replaceConstant(itr->value), paints[ClassID::Default]);
} else if (name.compare(0, 6, "paint.") == 0 && name.length() > 6) {
const ClassID class_id = ClassDictionary::Get().lookup(name.substr(6));
parseStyle(replaceConstant(itr->value), styles[class_id]);
parsePaint(replaceConstant(itr->value), paints[class_id]);
}
}
}
void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
void StyleParser::parsePaint(JSVal value, ClassProperties &klass) {
using Key = PropertyKey;
parseOptionalProperty<Function<bool>>("fill-antialias", Key::FillAntialias, klass, value);
@@ -586,8 +586,8 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<TranslateAnchorType>("line-translate-anchor", Key::LineTranslateAnchor, klass, value);
parseOptionalProperty<Function<float>>("line-width", Key::LineWidth, klass, value);
parseOptionalProperty<PropertyTransition>("line-width-transition", Key::LineWidth, klass, value);
parseOptionalProperty<Function<float>>("line-offset", Key::LineOffset, klass, value);
parseOptionalProperty<PropertyTransition>("line-offset-transition", Key::LineOffset, klass, value);
parseOptionalProperty<Function<float>>("line-gap-width", Key::LineGapWidth, klass, value);
parseOptionalProperty<PropertyTransition>("line-gap-width-transition", Key::LineGapWidth, klass, value);
parseOptionalProperty<Function<float>>("line-blur", Key::LineBlur, klass, value);
parseOptionalProperty<PropertyTransition>("line-blur-transition", Key::LineBlur, klass, value);
parseOptionalProperty<Function<float>>("line-dasharray", { Key::LineDashLand, Key::LineDashGap }, klass, value);
@@ -711,123 +711,36 @@ void StyleParser::parseBucket(JSVal value, util::ptr<StyleLayer> &layer) {
if (value.HasMember("filter")) {
JSVal value_filter = replaceConstant(value["filter"]);
layer->bucket->filter = parseFilter(value_filter);
layer->bucket->filter = parseFilterExpression(value_filter);
}
if (value.HasMember("render")) {
JSVal value_render = replaceConstant(value["render"]);
parseRender(value_render, layer);
if (value.HasMember("layout")) {
JSVal value_render = replaceConstant(value["layout"]);
parseLayout(value_render, layer);
}
if (value.HasMember("min-zoom")) {
JSVal min_zoom = value["min-zoom"];
if (value.HasMember("minzoom")) {
JSVal min_zoom = value["minzoom"];
if (min_zoom.IsNumber()) {
layer->bucket->min_zoom = min_zoom.GetDouble();
} else {
Log::Warning(Event::ParseStyle, "min-zoom of layer %s must be numeric", layer->id.c_str());
Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", layer->id.c_str());
}
}
if (value.HasMember("max-zoom")) {
JSVal max_zoom = value["max-zoom"];
if (value.HasMember("maxzoom")) {
JSVal max_zoom = value["maxzoom"];
if (max_zoom.IsNumber()) {
layer->bucket->min_zoom = max_zoom.GetDouble();
} else {
Log::Warning(Event::ParseStyle, "max-zoom of layer %s must be numeric", layer->id.c_str());
Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", layer->id.c_str());
}
}
}
FilterExpression StyleParser::parseFilter(JSVal value) {
return parseFilter(value, value.IsArray() ? FilterExpression::Operator::Or : FilterExpression::Operator::And);
}
FilterExpression StyleParser::parseFilter(JSVal value, FilterExpression::Operator op) {
FilterExpression expression(op);
if (value.IsObject()) {
rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
for (; itr != value.MemberEnd(); ++itr) {
const std::string name { itr->name.GetString(), itr->name.GetStringLength() };
if (name == "&") {
expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::And));
} else if (name == "|") {
expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Or));
} else if (name == "^") {
expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Xor));
} else if (name == "!") {
expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Nor));
} else if (name == "$type") {
JSVal type = replaceConstant(itr->value);
if (type.IsString()) {
expression.setGeometryType(parseGeometryType({ type.GetString(), type.GetStringLength() }));
}
} else {
FilterComparison comparison(name);
JSVal filterValue = replaceConstant(itr->value);
if (filterValue.IsObject()) {
rapidjson::Value::ConstMemberIterator filter_itr = filterValue.MemberBegin();
for (; filter_itr != filterValue.MemberEnd(); ++filter_itr) {
comparison.add(
parseFilterComparisonOperator({ filter_itr->name.GetString(), filter_itr->name.GetStringLength() }),
parseValues(replaceConstant(filter_itr->value))
);
}
} else if (filterValue.IsArray()) {
comparison.add(FilterComparison::Operator::In, parseValues(filterValue));
} else {
comparison.add(FilterComparison::Operator::Equal, std::vector<Value>({ parseValue(filterValue) }));
}
expression.add(comparison);
}
}
} else if (value.IsArray()) {
for (rapidjson::SizeType i = 0; i < value.Size(); i++) {
expression.add(parseFilter(replaceConstant(value[i])));
}
} else {
Log::Warning(Event::ParseStyle, "expression must be either an array or an object");
}
return expression;
}
Value StyleParser::parseValue(JSVal value) {
switch (value.GetType()) {
case rapidjson::kNullType:
case rapidjson::kFalseType:
return false;
case rapidjson::kTrueType:
return true;
case rapidjson::kStringType:
return std::string { value.GetString(), value.GetStringLength() };
case rapidjson::kNumberType:
if (value.IsUint64()) return value.GetUint64();
if (value.IsInt64()) return value.GetInt64();
return value.GetDouble();
default:
return false;
}
}
std::vector<Value> StyleParser::parseValues(JSVal value) {
std::vector<Value> values;
if (value.IsArray()) {
for (rapidjson::SizeType i = 0; i < value.Size(); i++) {
values.emplace_back(parseValue(replaceConstant(value[i])));
}
} else {
values.emplace_back(parseValue(value));
}
return values;
}
void StyleParser::parseRender(JSVal value, util::ptr<StyleLayer> &layer) {
void StyleParser::parseLayout(JSVal value, util::ptr<StyleLayer> &layer) {
if (!value.IsObject()) {
Log::Warning(Event::ParseStyle, "render property of layer '%s' must be an object", layer->id.c_str());
Log::Warning(Event::ParseStyle, "layout property of layer '%s' must be an object", layer->id.c_str());
return;
}
@@ -888,8 +801,7 @@ void StyleParser::parseRender(JSVal value, util::ptr<StyleLayer> &layer) {
render.text.letter_spacing *= 24; // em
}
parseRenderProperty<TextJustifyTypeClass>(value, render.text.justify, "text-justify");
parseRenderProperty<TextHorizontalAlignTypeClass>(value, render.text.horizontal_align, "text-horizontal-align");
parseRenderProperty<TextVerticalAlignTypeClass>(value, render.text.vertical_align, "text-vertical-align");
parseRenderProperty<TextAnchorTypeClass>(value, render.text.anchor, "text-anchor");
parseRenderProperty(value, render.text.max_angle, "text-max-angle");
parseRenderProperty(value, render.text.rotate, "text-rotate");
parseRenderProperty(value, render.text.slant, "text-slant");

View File

@@ -42,3 +42,25 @@ std::string mbgl::toString(const mbgl::Value& value) {
else if (value.is<double>()) return boost::lexical_cast<std::string>(value.get<double>());
else return "null";
}
mbgl::Value mbgl::parseValue(const rapidjson::Value& value) {
switch (value.GetType()) {
case rapidjson::kNullType:
case rapidjson::kFalseType:
return false;
case rapidjson::kTrueType:
return true;
case rapidjson::kStringType:
return std::string { value.GetString(), value.GetStringLength() };
case rapidjson::kNumberType:
if (value.IsUint64()) return value.GetUint64();
if (value.IsInt64()) return value.GetInt64();
return value.GetDouble();
default:
return false;
}
}

View File

@@ -8,5 +8,18 @@ timestamp now() {
return uv_hrtime();
}
static const char *week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
std::string rfc1123(std::time_t time) {
std::tm info;
gmtime_r(&time, &info);
char buffer[30];
snprintf(buffer, 30, "%s, %02d %s %4d %02d:%02d:%02d GMT", week[info.tm_wday], info.tm_mday,
months[info.tm_mon], 1900 + info.tm_year, info.tm_hour, info.tm_min, info.tm_sec);
return buffer;
}
}
}

2
styles

Submodule styles updated: 65dc5c9b7e...225f78f428

View File

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

View File

@@ -1,72 +0,0 @@
#include <mbgl/storage/http_request_baton.hpp>
#include <mbgl/storage/file_request_baton.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/url.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/platform/log.hpp>
#include <iostream>
#include <uv.h>
#include <cassert>
const std::string base_directory = []{
std::string fn = __FILE__;
fn.erase(fn.find_last_of("/"));
fn.erase(fn.find_last_of("/"));
fn.erase(fn.find_last_of("/"));
return fn + "/test/suite/";
}();
namespace mbgl {
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &baton) {
assert(uv_thread_self() == baton->thread_id);
std::string clean_url = util::percentDecode(baton->path);
if (clean_url.find("local://") == 0) {
clean_url = base_directory + clean_url.substr(8);
}
baton->response = std::make_unique<Response>();
FILE *file = fopen(clean_url.c_str(),"rb");
if (file != NULL) {
fseek(file, 0, SEEK_END);
const size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
baton->response->data.resize(size);
const size_t read = fread(&baton->response->data[0], 1, size, file);
fclose(file);
if (read == size) {
baton->response->code = 200;
baton->type = HTTPResponseType::Successful;
} else {
baton->response->code = 500;
baton->type = HTTPResponseType::PermanentError;
baton->response->message = "Read bytes differed from file size";
}
} else {
baton->type = HTTPResponseType::PermanentError;
baton->response->code = 404;
}
uv_async_send(baton->async);
}
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &/*baton*/) {
fprintf(stderr, "HTTP request cannot be canceled because it is answered immediately");
abort();
}
namespace platform {
std::string defaultCacheDatabase() {
// Disables the cache.
return "";
}
}
}

View File

@@ -1,39 +1,39 @@
{
"version": 3,
"version": 6,
"constants": {
"@land": "r44,239,225)",
"@snow": "f4f8foNGbjf#",
"@crop": "#eerLznieed4"
},
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"constants": {
"@land":"r44,239,225)",
"@snow":"f4f8foNGbjf#",
"@crop":"#eerLznieed4"
},
"layers": [{
"id": "background",
"type": "background",
"style": {
"paint": {
"background-color": "@land"
}
}, {
"id": "landcover_snow",
"type": "fill",
"source": "mapbox",
"source-layer": "landcover",
"filter": { "class": "snow" },
"type": "fill",
"style": {
"filter": ["==", "class", "snow"],
"paint": {
"fill-color": "@snow"
}
}, {
"id": "landcover_crop",
"type": "fill",
"source": "mapbox",
"source-layer": "landcover",
"filter": { "class": "crop" },
"type": "fill",
"style": {
"filter": ["==", "class", "crop"],
"paint": {
"fill-color": "@crop"
}
}]

View File

@@ -1,6 +0,0 @@
{
"default": {
"log": [
]
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "waterway_river_canal",
"type": "line",
"source": "mapbox",
"source-layer": "waterway",
"filter": { "type": ["river", "canal"] },
"type": "line",
"style": {
"filter": ["in", "type", "river", "canal"],
"paint": {
"line-width": {
"stops": [0]
}

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "waterway_river_canal",
"type": "line",
"source": "mapbox",
"source-layer": "waterway",
"filter": { "type": ["river", "canal"] },
"type": "line",
"style": {
"filter": ["in", "type", "river", "canal"],
"paint": {
"line-width": {}
}
}]

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "contour_line_loud",
"type": "line",
"source": "mapbox",
"source-layer": "contour",
"filter": { "index": 5 },
"type": "line",
"style": {
"filter": ["==", "index", 5],
"paint": {
"line-color": "#008",
"line-width": 0.9,
"line-opacity": null

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "waterway_river_canal",
"type": "line",
"source": "mapbox",
"source-layer": "waterway",
"filter": { "type": ["river", "canal"] },
"type": "line",
"style": {
"filter": ["in", "type", "river", "canal"],
"paint": {
"line-width": null
}
}]

View File

@@ -1,41 +1,41 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "landcover_grass",
"type": "fill",
"source": "mapbox",
"source-layer": "landcover",
"filter": { "class": "grass" },
"type": "fill",
"style": {
"filter": ["==", "class", "grass"],
"paint": {
"fill-opacity": {
"stops": []
}
}
}, {
"id": "landcover_scrub",
"type": "fill",
"source": "mapbox",
"source-layer": "landcover",
"filter": { "class": "scrub" },
"type": "fill",
"style": {
"filter": ["==", "class", "scrub"],
"paint": {
"fill-opacity": {
"stops": [[12]]
}
}
}, {
"id": "landcover_wood",
"type": "fill",
"source": "mapbox",
"source-layer": "landcover",
"filter": { "class": "wood" },
"type": "fill",
"style": {
"filter": ["==", "class", "wood"],
"paint": {
"fill-color": "@wood",
"fill-opacity": {
"stops": [[12, 1], [13, 0.8], [16, 0.2]]

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "waterway_river_canal",
"type": "line",
"source": "mapbox",
"source-layer": "waterway",
"filter": { "type": ["river", "canal"] },
"type": "line",
"style": {
"filter": ["in", "type", "river", "canal"],
"paint": {
"line-width": {
"stops": null
}

View File

@@ -1,19 +1,19 @@
{
"version": 3,
"version": 6,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxZoom": 14
"maxzoom": 14
}
},
"layers": [{
"id": "country_label",
"type": "text",
"source": "mapbox",
"source-layer": "country_label",
"filter": { "$type": "Point" },
"type": "text",
"style": {
"filter": ["==", "$type", "Point"],
"paint": {
"text-size": null
}
}]

View File

@@ -15,26 +15,72 @@
#include "./fixtures/fixture_log.hpp"
#include <dirent.h>
#include <signal.h>
#include <libgen.h>
const std::string base_directory = []{
std::string fn = __FILE__;
fn.erase(fn.find_last_of("/"));
fn.erase(fn.find_last_of("/"));
return fn + "/test/suite/";
}();
std::string base_directory;
auto display_ = std::make_shared<mbgl::HeadlessDisplay>();
class ServerEnvironment : public ::testing::Environment {
public:
virtual void SetUp() {
pid = fork();
if (pid < 0) {
throw std::runtime_error("Cannot create web server");
} else if (pid == 0) {
char *arg[] = { nullptr };
int ret = execv((base_directory + "bin/server.py").c_str(), arg);
// This call should not return. In case execve failed, we exit anyway.
if (ret < 0) {
fprintf(stderr, "Failed to start server: %s\n", strerror(errno));
}
exit(0);
} else {
display = std::make_shared<mbgl::HeadlessDisplay>();
}
}
virtual void TearDown() {
ASSERT_TRUE(pid);
kill(pid, SIGHUP);
}
std::shared_ptr<mbgl::HeadlessDisplay> display;
private:
pid_t pid = 0;
};
ServerEnvironment* env = nullptr;
GTEST_API_ int main(int argc, char *argv[]) {
// Note: glibc's dirname() **modifies** the argument and can't handle static strings.
std::string argv0 { argv[0] }; argv0 = dirname(const_cast<char *>(argv0.c_str()));
std::string file { __FILE__ }; file = dirname(const_cast<char *>(file.c_str()));
base_directory = argv0 + "/" + file + "/suite/";
testing::InitGoogleTest(&argc, argv);
env = new ServerEnvironment();
::testing::AddGlobalTestEnvironment(env);
return RUN_ALL_TESTS();
}
class HeadlessTest : public ::testing::TestWithParam<std::string> {};
TEST_P(HeadlessTest, render) {
using namespace mbgl;
const std::string &base = GetParam();
const std::string& base = GetParam();
std::string style = util::read_file(base_directory + "tests/" + base + "/style.json");
std::string info = util::read_file(base_directory + "tests/" + base + "/info.json");
std::size_t pos = 0;
while ((pos = style.find("local://", pos)) != std::string::npos) {
style.replace(pos, 8, "http://localhost:2900/");
}
// Parse style.
rapidjson::Document styleDoc;
styleDoc.Parse<0>((const char *const)style.c_str());
@@ -55,8 +101,10 @@ TEST_P(HeadlessTest, render) {
Log::Set<FixtureLogBackend>();
for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) {
const std::string name { it->name.GetString(), it->name.GetStringLength() };
const rapidjson::Value &value = it->value;
const std::string name {
it->name.GetString(), it->name.GetStringLength()
};
const rapidjson::Value& value = it->value;
ASSERT_TRUE(value.IsObject());
if (value.HasMember("center")) ASSERT_TRUE(value["center"].IsArray());
@@ -72,16 +120,16 @@ TEST_P(HeadlessTest, render) {
std::vector<std::string> classes;
if (value.HasMember("classes")) {
const rapidjson::Value &js_classes = value["classes"];
const rapidjson::Value& js_classes = value["classes"];
ASSERT_TRUE(js_classes.IsArray());
for (rapidjson::SizeType i = 0; i < js_classes.Size(); i++) {
const rapidjson::Value &js_class = js_classes[i];
const rapidjson::Value& js_class = js_classes[i];
ASSERT_TRUE(js_class.IsString());
classes.push_back({ js_class.GetString(), js_class.GetStringLength() });
}
}
HeadlessView view(display_);
HeadlessView view(env->display);
Map map(view);
map.setStyleJSON(style, base_directory);

View File

@@ -42,7 +42,7 @@
'../mapboxgl.gyp:mbgl-standalone',
],
'conditions': [
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)'] }
}, {
'libraries': [ '<@(ldflags)' ],
}]
@@ -60,7 +60,7 @@
'../mapboxgl.gyp:mbgl-standalone',
],
'conditions': [
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)'] }
}, {
'libraries': [ '<@(ldflags)' ],
}]
@@ -162,9 +162,7 @@
'product_name': 'test_headless',
'type': 'executable',
'sources': [
'./main.cpp',
'./headless.cpp',
'./fixtures/fixture_request.cpp',
'./fixtures/fixture_log.cpp',
],
'conditions': [
@@ -188,7 +186,25 @@
'<(platform_library)',
]
},
{ 'target_name': 'text_conversions',
'product_name': 'test_text_conversions',
'type': 'executable',
'sources': [
'./main.cpp',
'./text_conversions.cpp',
],
'dependencies': [
'../deps/gtest/gtest.gyp:gtest',
'../mapboxgl.gyp:mbgl-standalone',
'<(platform_library)',
],
'conditions': [
['OS == "mac"', { 'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)', '-framework Foundation' ] }
}, {
'libraries': [ '<@(ldflags)'],
}]
]
},
# Build all targets
{ 'target_name': 'test',
'type': 'none',
@@ -202,6 +218,7 @@
'headless',
'style_parser',
'comparisons',
'text_conversions',
],
}
]

37
test/text_conversions.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include <iostream>
#include "gtest/gtest.h"
#include <mbgl/util/utf.hpp>
#include <mbgl/platform/platform.hpp>
using namespace mbgl;
TEST(TextConversions, to_upper) {
EXPECT_EQ(std::string("STREET"), platform::uppercase("strEEt")); // EN
EXPECT_EQ(std::string("ROAD"), platform::uppercase("rOAd")); // EN
EXPECT_EQ(std::string("STRASSE"), platform::uppercase("straße")); // DE
EXPECT_EQ(std::string("MASSE"), platform::uppercase("maße")); // DE
EXPECT_EQ(std::string("WEISSKOPFSEEADLER"), platform::uppercase("weißkopfseeadler")); // DE
EXPECT_EQ(std::string("AZƏRBAYCAN"), platform::uppercase("Azərbaycan")); // AZ
EXPECT_EQ(std::string("ὈΔΥΣΣΕΎΣ"), platform::uppercase("Ὀδυσσεύς")); // GR
}
TEST(TextConversions, to_lower) {
EXPECT_EQ(std::string("street"), platform::lowercase("strEEt")); // EN
EXPECT_EQ(std::string("road"), platform::lowercase("rOAd")); // EN
EXPECT_EQ(std::string("straße"), platform::lowercase("Straße")); // DE
EXPECT_EQ(std::string("strasse"), platform::lowercase("STRASSE")); // DE
EXPECT_EQ(std::string("masse"), platform::lowercase("MASSE")); // DE
EXPECT_EQ(std::string("weisskopfseeadler"), platform::lowercase("weiSSkopfseeadler")); // DE
EXPECT_EQ(std::string("azərbaycan"), platform::lowercase("AZƏRBAYCAN")); // AZ
//EXPECT_EQ(std::string("ὀδυσσεύσ"), platform::lowercase("ὈΔΥΣΣΕΎΣ")); // GR
// nunicode can't map last Σ to word-ending ς
}

View File

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