add filter expressions
This commit is contained in:
@@ -4,125 +4,114 @@
|
||||
#include <llmr/style/value.hpp>
|
||||
#include <llmr/util/recursive_wrapper.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
enum class FilterOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Less,
|
||||
LessEqual
|
||||
};
|
||||
class VectorTileTagExtractor;
|
||||
|
||||
enum class ExpressionOperator {
|
||||
Or,
|
||||
And
|
||||
};
|
||||
|
||||
|
||||
inline FilterOperator filterOperatorType(const std::string &op) {
|
||||
if (op == "!=" || op == "not") {
|
||||
return FilterOperator::NotEqual;
|
||||
} else if (op == "==" || op == "eq") {
|
||||
return FilterOperator::Equal;
|
||||
} else if (op == ">" || op == "gt") {
|
||||
return FilterOperator::Greater;
|
||||
} else if (op == ">=" || op == "gte") {
|
||||
return FilterOperator::GreaterEqual;
|
||||
} else if (op == "<" || op == "lt") {
|
||||
return FilterOperator::Less;
|
||||
} else if (op == "<=" || op == "lte") {
|
||||
return FilterOperator::LessEqual;
|
||||
} else {
|
||||
fprintf(stderr, "[WARNING] filter operator '%s' unrecognized\n", op.c_str());
|
||||
return FilterOperator::Equal;
|
||||
}
|
||||
}
|
||||
|
||||
inline ExpressionOperator expressionOperatorType(const std::string &op) {
|
||||
if (op == "&&" || op == "and") {
|
||||
return ExpressionOperator::And;
|
||||
} else if (op == "||" || op == "or") {
|
||||
return ExpressionOperator::Or;
|
||||
} else {
|
||||
fprintf(stderr, "[WARNING] expression operator '%s' unrecognized\n", op.c_str());
|
||||
return ExpressionOperator::Or;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PropertyFilter;
|
||||
class PropertyExpression;
|
||||
|
||||
typedef util::variant<
|
||||
util::recursive_wrapper<PropertyFilter>,
|
||||
util::recursive_wrapper<PropertyExpression>,
|
||||
std::true_type
|
||||
> PropertyFilterExpression;
|
||||
|
||||
|
||||
class PropertyFilter {
|
||||
class FilterComparison {
|
||||
public:
|
||||
inline PropertyFilter(const std::string &field, FilterOperator op, const Value &value) : field(field), op(op), value(value) {};
|
||||
inline PropertyFilter(PropertyFilter &&filter)
|
||||
: field(std::move(filter.field)),
|
||||
op(filter.op),
|
||||
value(std::move(filter.value)) {
|
||||
}
|
||||
enum class Operator : uint8_t {
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Less,
|
||||
LessEqual,
|
||||
In,
|
||||
NotIn
|
||||
};
|
||||
|
||||
// Returns true if the filter passes, even if the key is missing.
|
||||
inline bool isMissingFieldOkay() const {
|
||||
switch (op) {
|
||||
case FilterOperator::NotEqual:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
class Instance {
|
||||
public:
|
||||
Instance(Operator op, std::forward_list<Value> &&values)
|
||||
: op(op), values(values) {}
|
||||
|
||||
inline bool compare(const Value &other) const {
|
||||
switch (op) {
|
||||
case FilterOperator::Equal:
|
||||
return util::relaxed_equal(other, value);
|
||||
case FilterOperator::NotEqual:
|
||||
return !util::relaxed_equal(other, value);
|
||||
case FilterOperator::Greater:
|
||||
return util::relaxed_greater(other, value);
|
||||
case FilterOperator::GreaterEqual:
|
||||
return util::relaxed_greater_equal(other, value);
|
||||
case FilterOperator::Less:
|
||||
return util::relaxed_less(other, value);
|
||||
case FilterOperator::LessEqual:
|
||||
return util::relaxed_less_equal(other, value);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool compare(const Value &property_value) const;
|
||||
bool compare(const std::forward_list<Value> &property_values) const;
|
||||
|
||||
private:
|
||||
template <typename Comparer> inline bool includes(const Value &property_value, const Comparer &comparer) const;
|
||||
template <typename Comparer> inline bool compare(const Value &property_value, const Comparer &comparer) const;
|
||||
template <typename Comparer> inline bool all(const std::forward_list<Value> &property_values, const Comparer &comparer) const;
|
||||
|
||||
private:
|
||||
Operator op = Operator::Equal;
|
||||
std::forward_list<Value> values;
|
||||
|
||||
friend std::ostream& operator <<(std::ostream &, const Instance &);
|
||||
};
|
||||
|
||||
public:
|
||||
FilterComparison(const std::string &field) : field(field) {};
|
||||
|
||||
const std::string &getField() const;
|
||||
inline bool compare(const VectorTileTagExtractor &extractor) const;
|
||||
|
||||
template <typename ...Args>
|
||||
inline void add(Args&& ...args) {
|
||||
instances.emplace_front(::std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string field;
|
||||
FilterOperator op = FilterOperator::Equal;
|
||||
Value value;
|
||||
std::forward_list<Instance> instances;
|
||||
|
||||
friend std::ostream& operator <<(std::ostream &, const FilterComparison &);
|
||||
};
|
||||
|
||||
class PropertyExpression {
|
||||
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);
|
||||
|
||||
|
||||
class FilterExpression {
|
||||
public:
|
||||
inline PropertyExpression() {}
|
||||
inline PropertyExpression(PropertyExpression &&expression)
|
||||
: op(expression.op),
|
||||
operands(std::move(expression.operands)) {
|
||||
}
|
||||
typedef util::recursive_wrapper<FilterExpression> Wrapper;
|
||||
|
||||
enum class Operator : uint8_t {
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Nor
|
||||
};
|
||||
|
||||
enum class GeometryType : uint8_t {
|
||||
Any,
|
||||
Point,
|
||||
Line,
|
||||
Polygon
|
||||
};
|
||||
|
||||
public:
|
||||
ExpressionOperator op = ExpressionOperator::Or;
|
||||
std::vector<PropertyFilterExpression> operands;
|
||||
FilterExpression() = default;
|
||||
FilterExpression(Operator op) : op(op) {};
|
||||
|
||||
bool empty() const;
|
||||
|
||||
bool compare(const VectorTileTagExtractor &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::forward_list<FilterComparison> comparisons;
|
||||
std::forward_list<FilterExpression::Wrapper> expressions;
|
||||
|
||||
friend std::ostream& operator <<(std::ostream &, const FilterExpression &);
|
||||
};
|
||||
|
||||
std::ostream& operator <<(std::ostream &s, const FilterExpression &expression);
|
||||
|
||||
FilterExpression::GeometryType parseGeometryType(const std::string &geometry);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,13 +42,13 @@ private:
|
||||
void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
|
||||
std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
|
||||
|
||||
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill);
|
||||
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line);
|
||||
std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon);
|
||||
std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text);
|
||||
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
|
||||
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
|
||||
std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon);
|
||||
std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text);
|
||||
|
||||
template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter);
|
||||
template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args);
|
||||
template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
|
||||
template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args);
|
||||
|
||||
private:
|
||||
const VectorTile vector_data;
|
||||
|
||||
@@ -40,6 +40,22 @@ public:
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature);
|
||||
|
||||
|
||||
class VectorTileTagExtractor {
|
||||
public:
|
||||
VectorTileTagExtractor(const VectorTileLayer &layer);
|
||||
|
||||
void setTags(const pbf &pbf);
|
||||
std::forward_list<Value> getValues(const std::string &key) const;
|
||||
void setType(FilterExpression::GeometryType type);
|
||||
FilterExpression::GeometryType getType() const;
|
||||
|
||||
private:
|
||||
const VectorTileLayer &layer_;
|
||||
pbf tags_;
|
||||
FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allows iterating over the features of a VectorTileLayer using a
|
||||
* BucketDescription as filter. Only features matching the descriptions will
|
||||
@@ -54,11 +70,6 @@ public:
|
||||
bool operator!=(const iterator& other) const;
|
||||
const pbf& operator*() const;
|
||||
|
||||
private:
|
||||
bool matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf);
|
||||
bool matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf);
|
||||
bool matchesFilter(const PropertyFilter &filter, const pbf &tags_pbf);
|
||||
|
||||
private:
|
||||
const FilteredVectorTileLayer& parent;
|
||||
bool valid = false;
|
||||
@@ -67,14 +78,14 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression);
|
||||
FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression);
|
||||
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
||||
private:
|
||||
const VectorTileLayer& layer;
|
||||
const PropertyFilterExpression& filterExpression;
|
||||
const FilterExpression& filterExpression;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement);
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
std::string source_name;
|
||||
std::string source_layer;
|
||||
|
||||
PropertyFilterExpression filter = std::true_type();
|
||||
FilterExpression filter;
|
||||
|
||||
// Specifies how the geometry for this bucket should be created
|
||||
StyleBucketRender render;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <llmr/util/variant.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <forward_list>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
@@ -73,7 +74,7 @@ public:
|
||||
std::string name;
|
||||
std::shared_ptr<Source> source;
|
||||
std::string source_layer;
|
||||
PropertyFilterExpression filter = std::true_type();
|
||||
FilterExpression filter;
|
||||
StyleBucketRender render = std::false_type();
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ private:
|
||||
void parseRasterize(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseFilter(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
|
||||
// Parses optional properties into a render bucket.
|
||||
@@ -54,9 +53,11 @@ private:
|
||||
template <typename T>
|
||||
bool parseStyleProperty(const char *property_name, const std::vector<ClassPropertyKey> &keys, ClassProperties &klass, JSVal value);
|
||||
|
||||
// PropertyFilterExpression parseFilterOrExpression(JSVal value);
|
||||
// Value parseValue(JSVal value);
|
||||
//
|
||||
|
||||
FilterExpression parseFilter(JSVal, FilterExpression::Operator op);
|
||||
FilterExpression parseFilter(JSVal);
|
||||
Value parseValue(JSVal value);
|
||||
std::forward_list<Value> parseValues(JSVal values);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, const rapidjson::Value *> constants;
|
||||
|
||||
@@ -62,6 +62,8 @@ template <> struct string_to_number<uint64_t> {
|
||||
|
||||
template <typename Operator>
|
||||
struct relaxed_operator_visitor {
|
||||
typedef bool result_type;
|
||||
|
||||
bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); }
|
||||
|
||||
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||
@@ -114,23 +116,23 @@ struct relaxed_less_equal_operator {
|
||||
} // end namespace detail
|
||||
|
||||
inline bool relaxed_equal(Value const &lhs, Value const &rhs) {
|
||||
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_equal_operator>());
|
||||
return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_equal_operator>(), lhs, rhs);
|
||||
}
|
||||
|
||||
inline bool relaxed_greater(Value const &lhs, Value const &rhs) {
|
||||
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_operator>());
|
||||
return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_operator>(), lhs, rhs);
|
||||
}
|
||||
|
||||
inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) {
|
||||
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>());
|
||||
return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>(), lhs, rhs);
|
||||
}
|
||||
|
||||
inline bool relaxed_less(Value const &lhs, Value const &rhs) {
|
||||
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_operator>());
|
||||
return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_operator>(), lhs, rhs);
|
||||
}
|
||||
|
||||
inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) {
|
||||
return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>());
|
||||
return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>(), lhs, rhs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
namespace util {
|
||||
namespace llmr { namespace util {
|
||||
|
||||
template <typename T>
|
||||
class recursive_wrapper
|
||||
{
|
||||
public:
|
||||
|
||||
typedef T type;
|
||||
|
||||
using type = T;
|
||||
private:
|
||||
|
||||
T* p_;
|
||||
@@ -34,19 +30,19 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
recursive_wrapper& operator=(const recursive_wrapper& rhs)
|
||||
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
|
||||
{
|
||||
assign( rhs.get() );
|
||||
return *this;
|
||||
}
|
||||
|
||||
recursive_wrapper& operator=(const T& rhs)
|
||||
inline recursive_wrapper& operator=(T const& rhs)
|
||||
{
|
||||
assign( rhs );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(recursive_wrapper& operand) noexcept
|
||||
inline void swap(recursive_wrapper& operand) noexcept
|
||||
{
|
||||
T* temp = operand.p_;
|
||||
operand.p_ = p_;
|
||||
@@ -71,10 +67,10 @@ public:
|
||||
|
||||
T& get() { return *get_pointer(); }
|
||||
const T& get() const { return *get_pointer(); }
|
||||
|
||||
T* get_pointer() { return p_; }
|
||||
const T* get_pointer() const { return p_; }
|
||||
|
||||
operator T const&() const { return this->get(); }
|
||||
operator T&() { return this->get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -103,8 +99,9 @@ recursive_wrapper<T>::recursive_wrapper(T const& operand)
|
||||
|
||||
template <typename T>
|
||||
recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
|
||||
: p_(new T( std::move(operand.get()) ))
|
||||
: p_(operand.p_)
|
||||
{
|
||||
operand.p_ = nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -125,8 +122,6 @@ inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
}
|
||||
|
||||
#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef UTIL_VARIANT_HPP
|
||||
#define UTIL_VARIANT_HPP
|
||||
#ifndef MAPBOX_UTIL_VARIANT_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_HPP
|
||||
|
||||
#include <utility>
|
||||
#include <typeinfo>
|
||||
@@ -9,50 +9,119 @@
|
||||
#include <new> // operator new
|
||||
#include <cstddef> // size_t
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define VARIANT_INLINE inline __attribute__((always_inline))
|
||||
#include "recursive_wrapper.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
|
||||
#ifdef NDEBUG
|
||||
#define VARIANT_INLINE __forceinline
|
||||
#else
|
||||
#define VARIANT_INLINE __declspec(noinline)
|
||||
#endif
|
||||
#else
|
||||
#define VARIANT_INLINE __attribute__((noinline))
|
||||
#ifdef NDEBUG
|
||||
#define VARIANT_INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
#define VARIANT_INLINE __attribute__((noinline))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace llmr {
|
||||
#define VARIANT_MAJOR_VERSION 0
|
||||
#define VARIANT_MINOR_VERSION 1
|
||||
#define VARIANT_PATCH_VERSION 0
|
||||
|
||||
namespace util {
|
||||
// translates to 100
|
||||
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
|
||||
|
||||
namespace detail {
|
||||
namespace llmr { namespace util { namespace detail {
|
||||
|
||||
static constexpr std::size_t invalid_value = std::size_t(-1);
|
||||
|
||||
template <typename T, typename...Types>
|
||||
struct type_traits;
|
||||
struct direct_type;
|
||||
|
||||
template <typename T, typename First, typename...Types>
|
||||
struct type_traits<T, First, Types...>
|
||||
struct direct_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t id = std::is_same<T, First>::value ? sizeof...(Types) : type_traits<T, Types...>::id;
|
||||
static constexpr std::size_t index = std::is_same<T, First>::value
|
||||
? sizeof...(Types) : direct_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct type_traits<T>
|
||||
struct direct_type<T>
|
||||
{
|
||||
static constexpr std::size_t id = invalid_value;
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
template <typename T, typename...Types>
|
||||
struct convertible_type;
|
||||
|
||||
template <typename T, typename First, typename...Types>
|
||||
struct convertible_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t index = std::is_convertible<T, First>::value
|
||||
? sizeof...(Types) : convertible_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct convertible_type<T>
|
||||
{
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
template <typename T, typename...Types>
|
||||
struct value_traits
|
||||
{
|
||||
static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
|
||||
static constexpr std::size_t index =
|
||||
(direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
|
||||
};
|
||||
|
||||
template <typename T, typename...Types>
|
||||
struct is_valid_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct is_valid_type<T,First,Types...>
|
||||
struct is_valid_type<T, First, Types...>
|
||||
{
|
||||
static constexpr bool value = std::is_same<T,First>::value
|
||||
|| is_valid_type<T,Types...>::value;
|
||||
static constexpr bool value = std::is_convertible<T, First>::value
|
||||
|| is_valid_type<T, Types...>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_valid_type<T> : std::false_type {};
|
||||
|
||||
}
|
||||
template <std::size_t N, typename ... Types>
|
||||
struct select_type
|
||||
{
|
||||
static_assert(N < sizeof...(Types), "index out of bounds");
|
||||
};
|
||||
|
||||
template <std::size_t N, typename T, typename ... Types>
|
||||
struct select_type<N, T, Types...>
|
||||
{
|
||||
using type = typename select_type<N - 1, Types...>::type;
|
||||
};
|
||||
|
||||
template <typename T, typename ... Types>
|
||||
struct select_type<0, T, Types...>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// static visitor
|
||||
template <typename R = void>
|
||||
struct static_visitor
|
||||
{
|
||||
using result_type = R;
|
||||
protected:
|
||||
static_visitor() {}
|
||||
~static_visitor() {}
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t arg1, std::size_t ... others>
|
||||
struct static_max;
|
||||
@@ -125,37 +194,77 @@ template<> struct variant_helper<>
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper
|
||||
{
|
||||
T const& operator() (T const& obj) const
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
||||
T& operator() (T & obj) const
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper<recursive_wrapper<T>>
|
||||
{
|
||||
auto operator() (recursive_wrapper<T> const& obj) const
|
||||
-> typename recursive_wrapper<T>::type const&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename F, typename V, typename...Types>
|
||||
struct dispatcher;
|
||||
|
||||
template <typename F, typename V, typename T, typename...Types>
|
||||
struct dispatcher<F,V,T,Types...>
|
||||
struct dispatcher<F, V, T, Types...>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&)>::type result_type;
|
||||
|
||||
VARIANT_INLINE static result_type apply(V const& v, F f)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const& v, F f)
|
||||
{
|
||||
if (v.get_type_id() == sizeof...(Types))
|
||||
if (v.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
return f(v. template get<T>());
|
||||
return f(unwrapper<T>()(v. template get<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F,V,Types...>::apply(v, f);
|
||||
return dispatcher<F, V, Types...>::apply_const(v, f);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V & v, F f)
|
||||
{
|
||||
if (v.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
return f(unwrapper<T>()(v. template get<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F, V, Types...>::apply(v, f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F,typename V>
|
||||
struct dispatcher<F,V>
|
||||
template<typename F, typename V>
|
||||
struct dispatcher<F, V>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&)>::type result_type;
|
||||
|
||||
VARIANT_INLINE static result_type apply(V const&, F)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const&, F)
|
||||
{
|
||||
throw std::runtime_error("unary dispatch: FAIL");
|
||||
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V &, F)
|
||||
{
|
||||
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -163,28 +272,46 @@ template <typename F, typename V, typename T, typename...Types>
|
||||
struct binary_dispatcher_rhs;
|
||||
|
||||
template <typename F, typename V, typename T0, typename T1, typename...Types>
|
||||
struct binary_dispatcher_rhs<F,V,T0,T1,Types...>
|
||||
struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type result_type;
|
||||
VARIANT_INLINE static result_type apply(V const& lhs, V const& rhs, F f)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
|
||||
{
|
||||
if (rhs.get_type_id() == sizeof...(Types)) // call binary functor
|
||||
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
|
||||
{
|
||||
return f(lhs. template get<T0>(), rhs. template get<T1>());
|
||||
return f(unwrapper<T0>()(lhs. template get<T0>()),
|
||||
unwrapper<T1>()(rhs. template get<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F,V,T0,Types...>::apply(lhs, rhs, f);
|
||||
return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
|
||||
{
|
||||
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>()(lhs. template get<T0>()),
|
||||
unwrapper<T1>()(rhs. template get<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename F,typename V, typename T>
|
||||
struct binary_dispatcher_rhs<F,V,T>
|
||||
template<typename F, typename V, typename T>
|
||||
struct binary_dispatcher_rhs<F, V, T>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type result_type;
|
||||
|
||||
VARIANT_INLINE static result_type apply(V const&, V const&, F)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
VARIANT_INLINE static result_type apply(V &, V &, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
@@ -195,28 +322,45 @@ template <typename F, typename V, typename T, typename...Types>
|
||||
struct binary_dispatcher_lhs;
|
||||
|
||||
template <typename F, typename V, typename T0, typename T1, typename...Types>
|
||||
struct binary_dispatcher_lhs<F,V,T0,T1,Types...>
|
||||
struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type;
|
||||
VARIANT_INLINE static binary_result_type apply(V const& lhs, V const& rhs, F f)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
|
||||
{
|
||||
if (lhs.get_type_id() == sizeof...(Types)) // call binary functor
|
||||
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
|
||||
{
|
||||
return f(lhs. template get<T1>(), rhs. template get<T0>());
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F,V,T0,Types...>::apply(lhs, rhs, f);
|
||||
return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
|
||||
{
|
||||
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
|
||||
{
|
||||
return f(lhs. template get<T1>(), rhs. template get<T0>());
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename F,typename V, typename T>
|
||||
struct binary_dispatcher_lhs<F,V,T>
|
||||
template<typename F, typename V, typename T>
|
||||
struct binary_dispatcher_lhs<F, V, T>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type result_type;
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V const&, V const&, F)
|
||||
VARIANT_INLINE static result_type apply(V &, V &, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
@@ -226,37 +370,60 @@ template <typename F, typename V, typename...Types>
|
||||
struct binary_dispatcher;
|
||||
|
||||
template <typename F, typename V, typename T, typename...Types>
|
||||
struct binary_dispatcher<F,V,T,Types...>
|
||||
struct binary_dispatcher<F, V, T, Types...>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type;
|
||||
|
||||
VARIANT_INLINE static binary_result_type apply(V const& v0, V const& v1, F f)
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
|
||||
{
|
||||
if (v0.get_type_id() == sizeof...(Types))
|
||||
if (v0.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
if (v0.get_type_id() == v1.get_type_id())
|
||||
if (v0.get_type_index() == v1.get_type_index())
|
||||
{
|
||||
return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F,V,T,Types...>::apply(v0, v1, f);
|
||||
return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f);
|
||||
}
|
||||
}
|
||||
else if (v1.get_type_id() == sizeof...(Types))
|
||||
else if (v1.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
return binary_dispatcher_lhs<F,V,T,Types...>::apply(v0, v1, f);
|
||||
return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f);
|
||||
}
|
||||
return binary_dispatcher<F,V,Types...>::apply(v0, v1, f);
|
||||
return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
|
||||
}
|
||||
|
||||
VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
|
||||
{
|
||||
if (v0.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
if (v0.get_type_index() == v1.get_type_index())
|
||||
{
|
||||
return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f);
|
||||
}
|
||||
}
|
||||
else if (v1.get_type_index() == sizeof...(Types))
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f);
|
||||
}
|
||||
return binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F,typename V>
|
||||
struct binary_dispatcher<F,V>
|
||||
template<typename F, typename V>
|
||||
struct binary_dispatcher<F, V>
|
||||
{
|
||||
typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type;
|
||||
using result_type = typename F::result_type;
|
||||
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
|
||||
VARIANT_INLINE static binary_result_type apply(V const&, V const&, F)
|
||||
VARIANT_INLINE static result_type apply(V &, V &, F)
|
||||
{
|
||||
throw std::runtime_error("binary dispatch: FAIL");
|
||||
}
|
||||
@@ -275,19 +442,19 @@ struct equal_comp
|
||||
struct less_comp
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(const T& lhs, const T& rhs) const
|
||||
bool operator()(T const& lhs, T const& rhs) const
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Variant, typename Comp>
|
||||
class comparer
|
||||
class comparer : public static_visitor<bool>
|
||||
{
|
||||
public:
|
||||
explicit comparer(Variant const& lhs) noexcept
|
||||
: lhs_(lhs) {}
|
||||
comparer& operator=(const comparer&) = delete;
|
||||
comparer& operator=(comparer const&) = delete;
|
||||
// visitor
|
||||
template<typename T>
|
||||
bool operator()(T const& rhs_content) const
|
||||
@@ -301,16 +468,16 @@ private:
|
||||
|
||||
// operator<< helper
|
||||
template <typename Out>
|
||||
class printer
|
||||
class printer : public static_visitor<>
|
||||
{
|
||||
public:
|
||||
explicit printer(Out & out)
|
||||
: out_(out) {}
|
||||
printer& operator=(printer const &) = delete;
|
||||
printer& operator=(printer const&) = delete;
|
||||
|
||||
// visitor
|
||||
template <typename T>
|
||||
void operator()( T const & operand) const
|
||||
void operator()(T const& operand) const
|
||||
{
|
||||
out_ << operand;
|
||||
}
|
||||
@@ -318,7 +485,7 @@ private:
|
||||
Out & out_;
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // namespace detail
|
||||
|
||||
template<typename... Types>
|
||||
class variant
|
||||
@@ -329,81 +496,106 @@ private:
|
||||
static const std::size_t data_align = static_max<alignof(Types)...>::value;
|
||||
|
||||
using data_type = typename std::aligned_storage<data_size, data_align>::type;
|
||||
|
||||
using helper_type = variant_helper<Types...>;
|
||||
|
||||
std::size_t type_id;
|
||||
std::size_t type_index;
|
||||
data_type data;
|
||||
|
||||
public:
|
||||
|
||||
VARIANT_INLINE variant()
|
||||
: type_id(detail::invalid_value) {}
|
||||
|
||||
template <typename T>
|
||||
VARIANT_INLINE explicit variant(T const& val) noexcept
|
||||
: type_id(detail::type_traits<T, Types...>::id)
|
||||
: type_index(sizeof...(Types) - 1)
|
||||
{
|
||||
static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
|
||||
new (&data) T(val);
|
||||
new (&data) typename detail::select_type<0, Types...>::type();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant(T && val) noexcept
|
||||
: type_id(detail::type_traits<T,Types...>::id)
|
||||
template <typename T, class = typename std::enable_if<
|
||||
detail::is_valid_type<T, Types...>::value>::type>
|
||||
VARIANT_INLINE explicit variant(T const& val) noexcept
|
||||
: type_index(detail::value_traits<T, Types...>::index)
|
||||
{
|
||||
static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant");
|
||||
new (&data) T(std::forward<T>(val)); // nothrow
|
||||
constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1;
|
||||
using target_type = typename detail::select_type<index, Types...>::type;
|
||||
new (&data) target_type(val);
|
||||
}
|
||||
|
||||
template <typename T, class = typename std::enable_if<
|
||||
detail::is_valid_type<T, Types...>::value>::type>
|
||||
VARIANT_INLINE variant(T && val) noexcept
|
||||
: type_index(detail::value_traits<T, Types...>::index)
|
||||
{
|
||||
constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1;
|
||||
using target_type = typename detail::select_type<index, Types...>::type;
|
||||
new (&data) target_type(std::forward<T>(val)); // nothrow
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...> const& old)
|
||||
: type_id(old.type_id)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::copy(old.type_id, &old.data, &data);
|
||||
helper_type::copy(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...>&& old) noexcept
|
||||
: type_id(old.type_id)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::move(old.type_id, &old.data, &data);
|
||||
helper_type::move(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
friend void swap(variant<Types...> & first, variant<Types...> & second)
|
||||
{
|
||||
using std::swap; //enable ADL
|
||||
swap(first.type_id, second.type_id);
|
||||
swap(first.type_index, second.type_index);
|
||||
swap(first.data, second.data);
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant<Types...>& operator= (variant<Types...> other)
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other)
|
||||
{
|
||||
swap(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// conversions
|
||||
// move-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
|
||||
{
|
||||
variant<Types...> temp(std::move(rhs));
|
||||
swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// copy-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
|
||||
{
|
||||
variant<Types...> temp(rhs);
|
||||
swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
VARIANT_INLINE bool is() const
|
||||
{
|
||||
return (type_id == detail::type_traits<T, Types...>::id);
|
||||
return (type_index == detail::direct_type<T, Types...>::index);
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool valid() const
|
||||
{
|
||||
return (type_id != detail::invalid_value);
|
||||
return (type_index != detail::invalid_value);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
VARIANT_INLINE void set(Args&&... args)
|
||||
{
|
||||
helper_type::destroy(type_id, &data);
|
||||
helper_type::destroy(type_index, &data);
|
||||
new (&data) T(std::forward<Args>(args)...);
|
||||
type_id = detail::type_traits<T,Types...>::id;
|
||||
type_index = detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_id == detail::type_traits<T,Types...>::id)
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
}
|
||||
@@ -416,7 +608,7 @@ public:
|
||||
template<typename T>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_id == detail::type_traits<T,Types...>::id)
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T const*>(&data);
|
||||
}
|
||||
@@ -426,37 +618,57 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE std::size_t get_type_id() const
|
||||
VARIANT_INLINE std::size_t get_type_index() const
|
||||
{
|
||||
return type_id;
|
||||
return type_index;
|
||||
}
|
||||
|
||||
// visitor
|
||||
// unary
|
||||
template <typename F, typename V>
|
||||
typename std::result_of<F(V const&)>::type
|
||||
VARIANT_INLINE static visit(V const& v, F f)
|
||||
auto VARIANT_INLINE
|
||||
static visit(V const& v, F f)
|
||||
-> decltype(detail::dispatcher<F, V, Types...>::apply_const(v, f))
|
||||
{
|
||||
return detail::dispatcher<F, V, Types...>::apply_const(v, f);
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE
|
||||
static visit(V & v, F f)
|
||||
-> decltype(detail::dispatcher<F, V, Types...>::apply(v, f))
|
||||
{
|
||||
return detail::dispatcher<F, V, Types...>::apply(v, f);
|
||||
}
|
||||
|
||||
// binary
|
||||
// const
|
||||
template <typename F, typename V>
|
||||
typename std::result_of<F(V const&, V const& )>::type
|
||||
VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F f)
|
||||
auto VARIANT_INLINE
|
||||
static binary_visit(V const& v0, V const& v1, F f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f);
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE
|
||||
static binary_visit(V& v0, V& v1, F f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f);
|
||||
}
|
||||
|
||||
~variant() noexcept
|
||||
{
|
||||
helper_type::destroy(type_id, &data);
|
||||
helper_type::destroy(type_index, &data);
|
||||
}
|
||||
|
||||
// comparison operators
|
||||
// equality
|
||||
VARIANT_INLINE bool operator==(variant const& rhs) const
|
||||
{
|
||||
if (this->get_type_id() != rhs.get_type_id())
|
||||
if (this->get_type_index() != rhs.get_type_index())
|
||||
return false;
|
||||
detail::comparer<variant, detail::equal_comp> visitor(*this);
|
||||
return visit(rhs, visitor);
|
||||
@@ -464,9 +676,9 @@ public:
|
||||
// less than
|
||||
VARIANT_INLINE bool operator<(variant const& rhs) const
|
||||
{
|
||||
if (this->get_type_id() != rhs.get_type_id())
|
||||
if (this->get_type_index() != rhs.get_type_index())
|
||||
{
|
||||
return this->get_type_id() < rhs.get_type_id();
|
||||
return this->get_type_index() < rhs.get_type_index();
|
||||
// ^^ borrowed from boost::variant
|
||||
}
|
||||
detail::comparer<variant, detail::less_comp> visitor(*this);
|
||||
@@ -475,17 +687,30 @@ public:
|
||||
};
|
||||
|
||||
// unary visitor interface
|
||||
|
||||
// const
|
||||
template <typename V, typename F>
|
||||
typename std::result_of<F(V const&)>::type
|
||||
VARIANT_INLINE static apply_visitor(V const& v, F f)
|
||||
auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
|
||||
{
|
||||
return V::visit(v,f);
|
||||
return V::visit(v, f);
|
||||
}
|
||||
// non-const
|
||||
template <typename V, typename F>
|
||||
auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
|
||||
{
|
||||
return V::visit(v, f);
|
||||
}
|
||||
|
||||
// binary visitor interface
|
||||
// const
|
||||
template <typename V, typename F>
|
||||
typename std::result_of<F(V const&, V const&)>::type
|
||||
VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f)
|
||||
auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
|
||||
{
|
||||
return V::binary_visit(v0, v1, f);
|
||||
}
|
||||
// non-const
|
||||
template <typename V, typename F>
|
||||
auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
|
||||
{
|
||||
return V::binary_visit(v0, v1, f);
|
||||
}
|
||||
@@ -493,14 +718,14 @@ VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f)
|
||||
|
||||
// operator<<
|
||||
template <typename charT, typename traits, typename Variant>
|
||||
VARIANT_INLINE std::basic_ostream<charT,traits>&
|
||||
operator<< (std::basic_ostream<charT,traits>& out, Variant const& rhs)
|
||||
VARIANT_INLINE std::basic_ostream<charT, traits>&
|
||||
operator<< (std::basic_ostream<charT, traits>& out, Variant const& rhs)
|
||||
{
|
||||
detail::printer<std::basic_ostream<charT,traits> > visitor(out);
|
||||
apply_visitor(rhs, visitor);
|
||||
detail::printer<std::basic_ostream<charT, traits>> visitor(out);
|
||||
apply_visitor(visitor, rhs);
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif // UTIL_VARIANT_HPP
|
||||
}}
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_HPP
|
||||
|
||||
282
src/map/filter_expression.cpp
Normal file
282
src/map/filter_expression.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
#include <llmr/map/filter_expression.hpp>
|
||||
#include <llmr/map/vector_tile.hpp>
|
||||
|
||||
namespace llmr {
|
||||
|
||||
|
||||
template <typename Comparer>
|
||||
inline bool FilterComparison::Instance::includes(const Value &property_value, const Comparer &comparer) const {
|
||||
for (const Value &filter_value : values) {
|
||||
if (comparer(property_value, filter_value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Comparer>
|
||||
inline bool FilterComparison::Instance::compare(const Value &property_value, const Comparer &comparer) const {
|
||||
for (const Value &filter_value : values) {
|
||||
if (!comparer(property_value, filter_value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Comparer>
|
||||
inline bool FilterComparison::Instance::all(const std::forward_list<Value> &property_values, const Comparer &comparer) const {
|
||||
for (const Value &property_value : property_values) {
|
||||
if (!compare(property_value, comparer)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FilterComparison::Instance::compare(const Value &property_value) const {
|
||||
switch (op) {
|
||||
case Operator::Equal:
|
||||
case Operator::In:
|
||||
return includes(property_value, util::relaxed_equal);
|
||||
case Operator::NotEqual:
|
||||
case Operator::NotIn:
|
||||
return !includes(property_value, util::relaxed_equal);
|
||||
case Operator::Greater:
|
||||
return compare(property_value, util::relaxed_greater);
|
||||
case Operator::GreaterEqual:
|
||||
return compare(property_value, util::relaxed_greater_equal);
|
||||
case Operator::Less:
|
||||
return compare(property_value, util::relaxed_less);
|
||||
case Operator::LessEqual:
|
||||
return compare(property_value, util::relaxed_less_equal);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FilterComparison::Instance::compare(const std::forward_list<Value> &property_values) const {
|
||||
switch (op) {
|
||||
case Operator::Equal:
|
||||
for (const Value &property_value : property_values) {
|
||||
if (!includes(property_value, util::relaxed_equal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case Operator::NotEqual:
|
||||
for (const Value &property_value : property_values) {
|
||||
if (includes(property_value, util::relaxed_equal)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case Operator::In:
|
||||
for (const Value &property_value : property_values) {
|
||||
if (includes(property_value, util::relaxed_equal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case Operator::NotIn:
|
||||
for (const Value &property_value : property_values) {
|
||||
if (!includes(property_value, util::relaxed_equal)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case Operator::Greater:
|
||||
return all(property_values, util::relaxed_greater);
|
||||
case Operator::GreaterEqual:
|
||||
return all(property_values, util::relaxed_greater_equal);
|
||||
case Operator::Less:
|
||||
return all(property_values, util::relaxed_less);
|
||||
case Operator::LessEqual:
|
||||
return all(property_values, util::relaxed_less_equal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::string &FilterComparison::getField() const {
|
||||
return field;
|
||||
}
|
||||
|
||||
inline bool FilterComparison::compare(const VectorTileTagExtractor &extractor) const {
|
||||
const std::forward_list<Value> values = extractor.getValues(field);
|
||||
|
||||
// All instances are ANDed together.
|
||||
for (const Instance &instance : instances) {
|
||||
if (!instance.compare(values)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) {
|
||||
switch (type) {
|
||||
case FilterExpression::GeometryType::Point: s << "point"; break;
|
||||
case FilterExpression::GeometryType::Line: s << "line"; break;
|
||||
case FilterExpression::GeometryType::Polygon: s << "polygon"; break;
|
||||
case FilterExpression::GeometryType::Any: s << "any"; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FilterExpression::compare(const VectorTileTagExtractor &extractor) const {
|
||||
if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case Operator::Xor: {
|
||||
int count = 0;
|
||||
for (const FilterComparison &comparison : comparisons) {
|
||||
count += comparison.compare(extractor);
|
||||
if (count > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FilterExpression::empty() const {
|
||||
return type == GeometryType::Any && comparisons.empty() && expressions.empty();
|
||||
}
|
||||
|
||||
void FilterExpression::add(const FilterComparison &comparison) {
|
||||
comparisons.emplace_front(comparison);
|
||||
}
|
||||
|
||||
void FilterExpression::add(const FilterExpression &expression) {
|
||||
expressions.emplace_front(expression);
|
||||
}
|
||||
|
||||
void FilterExpression::setGeometryType(GeometryType g) {
|
||||
type = g;
|
||||
}
|
||||
|
||||
FilterExpression::GeometryType parseGeometryType(const std::string &geometry) {
|
||||
if (geometry == "point") return FilterExpression::GeometryType::Point;
|
||||
if (geometry == "line") return FilterExpression::GeometryType::Line;
|
||||
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;
|
||||
}
|
||||
s << "end expression" << std::endl;
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -169,8 +169,6 @@ void Map::setup() {
|
||||
view.make_active();
|
||||
|
||||
painter.setup();
|
||||
|
||||
setStyleJSON(styleJSON);
|
||||
}
|
||||
|
||||
void Map::setStyleJSON(std::string newStyleJSON) {
|
||||
|
||||
@@ -132,7 +132,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
|
||||
}
|
||||
|
||||
template <class Bucket>
|
||||
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) {
|
||||
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) {
|
||||
FilteredVectorTileLayer filtered_layer(layer, filter);
|
||||
for (pbf feature : filtered_layer) {
|
||||
if (obsolete())
|
||||
@@ -150,7 +150,7 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer,
|
||||
}
|
||||
|
||||
template <class Bucket, typename... Args>
|
||||
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) {
|
||||
void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) {
|
||||
FilteredVectorTileLayer filtered_layer(layer, filter);
|
||||
for (const pbf &feature_pbf : filtered_layer) {
|
||||
if (obsolete()) {
|
||||
@@ -161,25 +161,25 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer,
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) {
|
||||
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill) {
|
||||
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill);
|
||||
addBucketFeatures(bucket, layer, filter);
|
||||
return obsolete() ? nullptr : std::move(bucket);
|
||||
}
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line) {
|
||||
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line) {
|
||||
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line);
|
||||
addBucketFeatures(bucket, layer, filter);
|
||||
return obsolete() ? nullptr : std::move(bucket);
|
||||
}
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon) {
|
||||
std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon) {
|
||||
std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(tile.iconVertexBuffer, icon);
|
||||
addBucketFeatures(bucket, layer, filter, *spriteAtlas);
|
||||
return obsolete() ? nullptr : std::move(bucket);
|
||||
}
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) {
|
||||
std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) {
|
||||
|
||||
const StyleBucketText &properties = text;
|
||||
|
||||
@@ -235,9 +235,3 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& laye
|
||||
|
||||
return std::move(bucket);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//typedef std::pair<uint16_t, uint16_t> GlyphRange;
|
||||
//
|
||||
|
||||
@@ -102,7 +102,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) {
|
||||
}
|
||||
}
|
||||
|
||||
FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression)
|
||||
FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression)
|
||||
: layer(layer),
|
||||
filterExpression(filterExpression) {
|
||||
}
|
||||
@@ -122,120 +122,167 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren
|
||||
operator++();
|
||||
}
|
||||
|
||||
bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) {
|
||||
if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) {
|
||||
return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf);
|
||||
} else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) {
|
||||
return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf);
|
||||
} else if (filterExpression.is<std::true_type>()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
//bool FilteredVectorTileLayer::iterator::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) {}
|
||||
|
||||
|
||||
void VectorTileTagExtractor::setTags(const pbf &pbf) {
|
||||
tags_ = pbf;
|
||||
}
|
||||
|
||||
std::forward_list<Value> VectorTileTagExtractor::getValues(const std::string &key) const {
|
||||
std::forward_list<Value> values;
|
||||
|
||||
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()) {
|
||||
auto field_it = layer_.key_index.find(key);
|
||||
if (field_it != layer_.key_index.end()) {
|
||||
auto it = values.before_begin();
|
||||
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;
|
||||
pbf tags_pbf = tags_;
|
||||
uint32_t tag_key, tag_val;
|
||||
while (tags_pbf) {
|
||||
uint32_t tag_key = tags_pbf.varint();
|
||||
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");
|
||||
// This should not happen; otherwise the vector tile is invalid.
|
||||
fprintf(stderr, "[WARNING] uneven number of feature tag ids\n");
|
||||
return values;
|
||||
}
|
||||
uint32_t tag_val = tags_pbf.varint();
|
||||
// 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 (parent.layer.values.size() > tag_val) {
|
||||
const Value &value = parent.layer.values[tag_val];
|
||||
return filter.compare(value);
|
||||
if (layer_.values.size() > tag_val) {
|
||||
it = values.emplace_after(it, layer_.values[tag_val]);
|
||||
} else {
|
||||
throw std::runtime_error("feature references out of range value");
|
||||
fprintf(stderr, "[WARNING] feature references out of range value\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
return values;
|
||||
}
|
||||
|
||||
bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) {
|
||||
if (expression.op == ExpressionOperator::Or) {
|
||||
for (const PropertyFilterExpression &filterExpression : expression.operands) {
|
||||
if (matchesFilterExpression(filterExpression, tags_pbf)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (expression.op == ExpressionOperator::And) {
|
||||
for (const PropertyFilterExpression &filterExpression : expression.operands) {
|
||||
if (!matchesFilterExpression(filterExpression, tags_pbf)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) {
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
|
||||
FilterExpression::GeometryType VectorTileTagExtractor::getType() const {
|
||||
return type_;
|
||||
}
|
||||
|
||||
void FilteredVectorTileLayer::iterator::operator++() {
|
||||
valid = false;
|
||||
|
||||
const PropertyFilterExpression &expression = parent.filterExpression;
|
||||
const FilterExpression &expression = parent.filterExpression;
|
||||
|
||||
while (data.next(2)) { // feature
|
||||
feature = data.message();
|
||||
pbf feature_pbf = feature;
|
||||
BucketType type = BucketType::None;
|
||||
|
||||
bool matched = false;
|
||||
|
||||
// Treat the absence of any expression filters as a match.
|
||||
if (!expression.valid() || expression.is<std::true_type>()) {
|
||||
if (expression.empty()) {
|
||||
matched = true;
|
||||
}
|
||||
|
||||
while (feature_pbf.next()) {
|
||||
if (feature_pbf.tag == 2) { // tags
|
||||
if (matched) {
|
||||
// There is no filter, so we want to parse the entire layer anyway.
|
||||
feature_pbf.skip();
|
||||
} else {
|
||||
// We only want to parse some features.
|
||||
const pbf tags_pbf = feature_pbf.message();
|
||||
matched = matchesFilterExpression(expression, tags_pbf);
|
||||
if (!matched) {
|
||||
break; // feature_pbf loop early
|
||||
}
|
||||
}
|
||||
} else if (feature_pbf.tag == 3) { // geometry type
|
||||
switch (feature_pbf.varint()) {
|
||||
case 1 /* Point */: type = BucketType::Icon; break;
|
||||
case 2 /* LineString */: type = BucketType::Line; break;
|
||||
case 3 /* Polygon */: type = BucketType::Fill; break;
|
||||
default: type = BucketType::None; break;
|
||||
}
|
||||
if (!matched) {
|
||||
VectorTileTagExtractor extractor(parent.layer);
|
||||
|
||||
// TODO: Parse feature type
|
||||
// if (type != parent.bucket_desc.feature_type) {
|
||||
// matched = false;
|
||||
// break; // feature_pbf loop early
|
||||
// }
|
||||
} 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
|
||||
switch (FeatureType(feature_pbf.varint())) {
|
||||
case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break;
|
||||
case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break;
|
||||
case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break;
|
||||
default: break;
|
||||
}
|
||||
} else {
|
||||
feature_pbf.skip();
|
||||
}
|
||||
}
|
||||
|
||||
matched = expression.compare(extractor);
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
|
||||
@@ -622,7 +622,7 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) {
|
||||
|
||||
if (value.HasMember("filter")) {
|
||||
JSVal value_filter = replaceConstant(value["filter"]);
|
||||
parseFilter(value_filter, layer);
|
||||
layer->bucket->filter = parseFilter(value_filter);
|
||||
}
|
||||
|
||||
if (value.HasMember("render")) {
|
||||
@@ -631,8 +631,92 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) {
|
||||
}
|
||||
}
|
||||
|
||||
void StyleParser::parseFilter(JSVal value, std::shared_ptr<StyleLayer> &layer) {
|
||||
// TODO
|
||||
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 itr = filterValue.MemberBegin();
|
||||
for (; itr != filterValue.MemberEnd(); ++itr) {
|
||||
comparison.add(
|
||||
parseFilterComparisonOperator({ itr->name.GetString(), itr->name.GetStringLength() }),
|
||||
parseValues(replaceConstant(itr->value))
|
||||
);
|
||||
}
|
||||
} else if (filterValue.IsArray()) {
|
||||
comparison.add(FilterComparison::Operator::In, parseValues(filterValue));
|
||||
} else {
|
||||
comparison.add(FilterComparison::Operator::Equal, std::forward_list<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 {
|
||||
fprintf(stderr, "[WARNING] expression must be either an array or an object\n");
|
||||
}
|
||||
|
||||
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::forward_list<Value> StyleParser::parseValues(JSVal value) {
|
||||
std::forward_list<Value> values;
|
||||
if (value.IsArray()) {
|
||||
auto it = values.before_begin();
|
||||
for (rapidjson::SizeType i = 0; i < value.Size(); i++) {
|
||||
it = values.emplace_after(it, parseValue(replaceConstant(value[i])));
|
||||
}
|
||||
} else {
|
||||
values.emplace_front(parseValue(value));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
|
||||
@@ -724,79 +808,4 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
|
||||
}
|
||||
}
|
||||
|
||||
//PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) {
|
||||
// if (value.IsArray()) {
|
||||
// // This is an expression.
|
||||
// util::recursive_wrapper<PropertyExpression> expression;
|
||||
// for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
|
||||
// JSVal filter_item = value[i];
|
||||
//
|
||||
// if (filter_item.IsString()) {
|
||||
// expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() });
|
||||
// } else {
|
||||
// expression.get().operands.emplace_back(parseFilterOrExpression(filter_item));
|
||||
// }
|
||||
// }
|
||||
// return std::move(expression);
|
||||
// } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) {
|
||||
// // This is a filter.
|
||||
// JSVal field = value["field"];
|
||||
// JSVal val = value["value"];
|
||||
//
|
||||
// if (!field.IsString()) {
|
||||
// throw Style::exception("field name must be a string");
|
||||
// }
|
||||
//
|
||||
// const std::string field_name { field.GetString(), field.GetStringLength() };
|
||||
// const FilterOperator op = [&]{
|
||||
// if (value.HasMember("operator")) {
|
||||
// JSVal op_val = value["operator"];
|
||||
// return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() });
|
||||
// } else {
|
||||
// return FilterOperator::Equal;
|
||||
// }
|
||||
// }();
|
||||
//
|
||||
// if (val.IsArray()) {
|
||||
// // The filter has several values, so it's an OR sub-expression.
|
||||
// util::recursive_wrapper<PropertyExpression> expression;
|
||||
// for (rapidjson::SizeType i = 0; i < val.Size(); ++i) {
|
||||
// expression.get().operands.emplace_back(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val[i]) }));
|
||||
// }
|
||||
//
|
||||
// return std::move(expression);
|
||||
// } else {
|
||||
// // The filter only has a single value, so it is a real filter.
|
||||
// return std::move(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val) }));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return std::true_type();
|
||||
|
||||
//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();
|
||||
//
|
||||
// case rapidjson::kObjectType:
|
||||
// case rapidjson::kArrayType:
|
||||
// throw Style::exception("value cannot be an object or array");
|
||||
// return false;
|
||||
// }
|
||||
// throw Style::exception("unhandled value type in style");
|
||||
// return false;
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user