diff options
author | Anand Thakker <github@anandthakker.net> | 2017-07-09 17:00:52 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-07-09 17:00:52 -0400 |
commit | 945cdebe9b37c3de764d382cf216d55ee0b7fce6 (patch) | |
tree | 8f144b4b2d24f0d8fc26538c3fea189cf60782fe | |
parent | 8f7bfb80c401447758229a92d6b268783089f23c (diff) | |
download | qtlocation-mapboxgl-945cdebe9b37c3de764d382cf216d55ee0b7fce6.tar.gz |
Wrap EvaluationParameters and return an <Error, Value> variant
-rw-r--r-- | include/mbgl/style/expression/expression.hpp | 72 | ||||
-rw-r--r-- | platform/node/src/node_expression.cpp | 85 | ||||
-rw-r--r-- | platform/node/src/node_expression.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/function/expression.cpp | 10 |
4 files changed, 113 insertions, 56 deletions
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index e35a302f00..a3e69e4bb3 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -4,12 +4,14 @@ #include <vector> #include <memory> #include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> #include <mbgl/util/color.hpp> #include <mbgl/style/function/type.hpp> #include <mbgl/util/feature.hpp> #include <mbgl/style/expression/parsing_context.hpp> #include <mbgl/style/conversion.hpp> + namespace mbgl { class GeometryTileFeature; @@ -18,31 +20,40 @@ class GeometryTileFeature; namespace style { namespace expression { -using OutputValue = variant< +struct Value; +using ValueBase = variant< + NullValue, float, std::string, mbgl::Color, - std::array<float, 2>, - std::array<float, 4>>; + mapbox::util::recursive_wrapper<std::vector<Value>>, + mapbox::util::recursive_wrapper<std::unordered_map<std::string, Value>>>; +struct Value : ValueBase { + using ValueBase::ValueBase; +}; + +constexpr NullValue Null = NullValue(); struct EvaluationError { std::string message; }; -struct CompileError { - std::string message; - std::string key; +struct EvaluationParameters { + float zoom; + const GeometryTileFeature& feature; }; +using EvaluationResult = variant<EvaluationError, Value>; + class Expression { public: Expression(std::string key_, type::Type type_) : key(key_), type(type_) {} virtual ~Expression() {} - virtual optional<OutputValue> evaluate(float, const GeometryTileFeature&, EvaluationError& e) const = 0; + virtual EvaluationResult evaluate(const EvaluationParameters&) const = 0; // Exposed for use with pure Feature objects (e.g. beyond the context of tiled map data). - optional<OutputValue> evaluate(float, const Feature&, EvaluationError&) const; + EvaluationResult evaluate(float, const Feature&) const; type::Type getType() const { return type; @@ -70,6 +81,10 @@ private: type::Type type; }; +struct CompileError { + std::string message; + std::string key; +}; using ParseResult = variant<CompileError, std::unique_ptr<Expression>>; template <class V> ParseResult parseExpression(const V& value, const ParsingContext& context); @@ -81,16 +96,16 @@ public: LiteralExpression(std::string key, float value_) : Expression(key, type::Primitive::Number), value(value_) {} LiteralExpression(std::string key, const std::string& value_) : Expression(key, type::Primitive::String), value(value_) {} LiteralExpression(std::string key, const mbgl::Color& value_) : Expression(key, type::Primitive::Color), value(value_) {} - LiteralExpression(std::string key) : Expression(key, type::Primitive::Null) {} - - optional<OutputValue> evaluate(float, const GeometryTileFeature&, EvaluationError&) const override { + LiteralExpression(std::string key, const NullValue&) : Expression(key, type::Primitive::Null), value(Null) {} + + EvaluationResult evaluate(const EvaluationParameters&) const override { return value; } template <class V> static ParseResult parse(const V& value, const ParsingContext& ctx) { if (isUndefined(value)) - return std::make_unique<LiteralExpression>(ctx.key()); + return std::make_unique<LiteralExpression>(ctx.key(), Null); if (isObject(value)) { return CompileError {ctx.key(), "Unimplemented: object literals"}; @@ -114,7 +129,7 @@ public: } private: - optional<OutputValue> value; + Value value; }; class LambdaExpression : public Expression { @@ -154,19 +169,20 @@ private: }; template <typename T, typename Rfunc> -optional<OutputValue> evaluateBinaryOperator(float z, - const GeometryTileFeature& f, - EvaluationError& e, +EvaluationResult evaluateBinaryOperator(const EvaluationParameters& params, const LambdaExpression::Args& args, optional<T> initial, Rfunc reduce) { optional<T> memo = initial; for(const auto& arg : args) { - auto argValue = arg->evaluate(z, f, e); - if (!argValue) return {}; - if (!memo) memo = {argValue->get<T>()}; - else memo = reduce(*memo, argValue->get<T>()); + auto argValue = arg->evaluate(params); + if (argValue.is<EvaluationError>()) { + return argValue.get<EvaluationError>(); + } + T value = argValue.get<Value>().get<T>(); + if (!memo) memo = {value}; + else memo = reduce(*memo, value); } return {*memo}; } @@ -178,8 +194,8 @@ public: {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}}) {} - optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override { - return evaluateBinaryOperator<float>(zoom, feature, error, args, + EvaluationResult evaluate(const EvaluationParameters& params) const override { + return evaluateBinaryOperator<float>(params, args, {}, [](float memo, float next) { return memo + next; }); } }; @@ -191,8 +207,8 @@ public: {type::Primitive::Number, {type::NArgs({type::Primitive::Number})}}) {} - optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override { - return evaluateBinaryOperator<float>(zoom, feature, error, args, + EvaluationResult evaluate(const EvaluationParameters& params) const override { + return evaluateBinaryOperator<float>(params, args, {}, [](float memo, float next) { return memo * next; }); } }; @@ -204,8 +220,8 @@ public: {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}}) {} - optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override { - return evaluateBinaryOperator<float>(zoom, feature, error, args, + EvaluationResult evaluate(const EvaluationParameters& params) const override { + return evaluateBinaryOperator<float>(params, args, {}, [](float memo, float next) { return memo - next; }); } }; @@ -217,8 +233,8 @@ public: {type::Primitive::Number, {type::Primitive::Number, type::Primitive::Number}}) {} - optional<OutputValue> evaluate(float zoom, const GeometryTileFeature& feature, EvaluationError& error) const override { - return evaluateBinaryOperator<float>(zoom, feature, error, args, + EvaluationResult evaluate(const EvaluationParameters& params) const override { + return evaluateBinaryOperator<float>(params, args, {}, [](float memo, float next) { return memo / next; }); } }; diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index c6c2a04bfb..0c03d05902 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -73,6 +73,55 @@ void NodeExpression::New(const Nan::FunctionCallbackInfo<v8::Value>& info) { info.GetReturnValue().Set(info.This()); } +struct ToValue { + v8::Local<v8::Value> operator()(mbgl::NullValue) { + Nan::EscapableHandleScope scope; + return scope.Escape(Nan::Null()); + } + + v8::Local<v8::Value> operator()(bool t) { + Nan::EscapableHandleScope scope; + return scope.Escape(Nan::New(t)); + } + + v8::Local<v8::Value> operator()(float t) { + Nan::EscapableHandleScope scope; + return scope.Escape(Nan::New(t)); + } + + v8::Local<v8::Value> operator()(const std::string& t) { + Nan::EscapableHandleScope scope; + return scope.Escape(Nan::New(t).ToLocalChecked()); + } + + v8::Local<v8::Value> operator()(const std::vector<Value>& array) { + Nan::EscapableHandleScope scope; + v8::Local<v8::Array> result = Nan::New<v8::Array>(); + for (unsigned int i = 0; i < array.size(); i++) { + result->Set(i, toJS(array[i])); + } + return scope.Escape(result); + } + + v8::Local<v8::Value> operator()(const mbgl::Color& color) { + return operator()(color.stringify().c_str()); + } + + v8::Local<v8::Value> operator()(const std::unordered_map<std::string, Value>& map) { + Nan::EscapableHandleScope scope; + v8::Local<v8::Object> result = Nan::New<v8::Object>(); + for (const auto& entry : map) { + Nan::Set(result, Nan::New(entry.first).ToLocalChecked(), toJS(entry.second)); + } + + return scope.Escape(result); + } +}; + +v8::Local<v8::Value> toJS(const Value& value) { + return Value::visit(value, ToValue()); +} + void NodeExpression::Evaluate(const Nan::FunctionCallbackInfo<v8::Value>& info) { NodeExpression* nodeExpr = ObjectWrap::Unwrap<NodeExpression>(info.Holder()); const auto& expression = nodeExpr->expression; @@ -99,29 +148,19 @@ void NodeExpression::Evaluate(const Nan::FunctionCallbackInfo<v8::Value>& info) try { mapbox::geojson::feature feature = geoJSON->get<mapbox::geojson::feature>(); - EvaluationError error; - auto result = expression->evaluate(zoom, feature, error); - if (result) { - result->match( - [&] (const std::array<float, 2>&) {}, - [&] (const std::array<float, 4>&) {}, - [&] (const std::string s) { - info.GetReturnValue().Set(Nan::New(s.c_str()).ToLocalChecked()); - }, - [&] (const mbgl::Color& c) { - info.GetReturnValue().Set(Nan::New(c.stringify().c_str()).ToLocalChecked()); - }, - [&] (const auto& v) { - info.GetReturnValue().Set(Nan::New(v)); - } - ); - } else { - v8::Local<v8::Object> res = Nan::New<v8::Object>(); - Nan::Set(res, - Nan::New("error").ToLocalChecked(), - Nan::New(error.message.c_str()).ToLocalChecked()); - info.GetReturnValue().Set(res); - } + auto result = expression->evaluate(zoom, feature); + result.match( + [&] (const Value& v) { + info.GetReturnValue().Set(toJS(v)); + }, + [&] (const EvaluationError& error) { + v8::Local<v8::Object> res = Nan::New<v8::Object>(); + Nan::Set(res, + Nan::New("error").ToLocalChecked(), + Nan::New(error.message.c_str()).ToLocalChecked()); + info.GetReturnValue().Set(res); + } + ); } catch(std::exception &ex) { return Nan::ThrowTypeError(ex.what()); } diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp index 3797632236..5cfc3b553e 100644 --- a/platform/node/src/node_expression.hpp +++ b/platform/node/src/node_expression.hpp @@ -16,6 +16,8 @@ using namespace mbgl::style::expression; namespace node_mbgl { +v8::Local<v8::Value> toJS(const Value&); + class NodeExpression : public Nan::ObjectWrap { public: static void Init(v8::Local<v8::Object>); diff --git a/src/mbgl/style/function/expression.cpp b/src/mbgl/style/function/expression.cpp index b609a6e576..1c24378265 100644 --- a/src/mbgl/style/function/expression.cpp +++ b/src/mbgl/style/function/expression.cpp @@ -29,18 +29,18 @@ public: return {}; } - optional<Value> getValue(const std::string& key) const override { + optional<mbgl::Value> getValue(const std::string& key) const override { auto it = feature.properties.find(key); if (it != feature.properties.end()) { - return optional<Value>(it->second); + return optional<mbgl::Value>(it->second); } - return optional<Value>(); + return optional<mbgl::Value>(); } }; -optional<OutputValue> Expression::evaluate(float z, const Feature& feature, EvaluationError& error) const { +EvaluationResult Expression::evaluate(float z, const Feature& feature) const { std::unique_ptr<const GeometryTileFeature> f = std::make_unique<const GeoJSONFeature>(feature); - return this->evaluate(z, *f, error); + return this->evaluate(EvaluationParameters {z, *f}); } |