diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2018-12-03 21:43:43 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2018-12-04 11:29:20 +0200 |
commit | fcd7c6d83715385d229e11b19997ebbe340b4112 (patch) | |
tree | f19140b2d679d59845bfeac484361282d3dcd29b | |
parent | 4ee32910ffb806b92faab877b3eccc0593b03ae3 (diff) | |
download | qtlocation-mapboxgl-upstream/constexpr-expression-map.tar.gz |
[core] convert CompoundExpressionRegistry to constexpr hash mapupstream/constexpr-expression-map
-rw-r--r-- | include/mbgl/style/expression/compound_expression.hpp | 11 | ||||
-rw-r--r-- | include/mbgl/style/expression/parsing_context.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/style/expression/compound_expression.cpp | 515 | ||||
-rw-r--r-- | src/mbgl/style/expression/is_expression.cpp | 3 | ||||
-rw-r--r-- | src/mbgl/style/expression/parsing_context.cpp | 12 |
5 files changed, 423 insertions, 121 deletions
diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index b54720a258..57a96d08a0 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -39,20 +39,13 @@ public: optional<std::size_t> getParameterCount() const; + static bool exists(const std::string& name); + protected: const detail::SignatureBase& signature; std::vector<std::unique_ptr<Expression>> args; }; -/* - Holds the map of expression name => implementation (which is just one or - more evaluation functions, each wrapped in a Signature struct). -*/ -struct CompoundExpressionRegistry { - using Definition = std::vector<std::unique_ptr<detail::SignatureBase>>; - static std::unordered_map<std::string, Definition> definitions; -}; - ParseResult parseCompoundExpression(const std::string name, const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp index 08151a2b7d..596b136419 100644 --- a/include/mbgl/style/expression/parsing_context.hpp +++ b/include/mbgl/style/expression/parsing_context.hpp @@ -177,8 +177,7 @@ private: std::shared_ptr<std::vector<ParsingError>> errors; }; -using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); -ParseFunction getExpression(const std::string&); +bool isExpression(const std::string&); } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 6a4894a478..cc1d58025b 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -12,6 +12,8 @@ #include <mbgl/util/platform.hpp> #include <mbgl/util/variant.hpp> +#include <mapbox/eternal.hpp> + #include <cmath> namespace mbgl { @@ -215,14 +217,12 @@ struct SignatureType<Lambda, std::enable_if_t<std::is_class<Lambda>::value>> { using Type = typename SignatureType<decltype(&Lambda::operator())>::Type; }; template <typename Fn> -static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) { +static std::unique_ptr<detail::SignatureBase> makeSignature(std::string name, Fn evaluateFunction) { return std::make_unique<Signature<typename SignatureType<Fn>::Type>>(evaluateFunction, std::move(name)); } } // namespace detail -using Definition = CompoundExpressionRegistry::Definition; - Value featureIdAsExpressionValue(EvaluationContext params) { assert(params.feature); auto id = params.feature->getID(); @@ -295,26 +295,45 @@ optional<std::string> featureIdAsString(EvaluationContext params) { ); }; -std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() { - std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions; - auto define = [&](std::string name, auto fn) { - definitions[name].push_back(detail::makeSignature(fn, name)); - }; +const auto& eCompoundExpression() { + static auto signature = detail::makeSignature("e", []() -> Result<double> { return 2.718281828459045; }); + return signature; +} - define("e", []() -> Result<double> { return 2.718281828459045; }); - define("pi", []() -> Result<double> { return 3.141592653589793; }); - define("ln2", []() -> Result<double> { return 0.6931471805599453; }); +const auto& piCompoundExpression() { + static auto signature = detail::makeSignature("pi", []() -> Result<double> { return 3.141592653589793; }); + return signature; +} - define("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); }); +const auto& ln2CompoundExpression() { + static auto signature = detail::makeSignature("ln2", []() -> Result<double> { return 0.6931471805599453; }); + return signature; +} + +const auto& typeofCompoundExpression() { + static auto signature = detail::makeSignature("typeof", [](const Value& v) -> Result<std::string> { return toString(typeOf(v)); }); + return signature; +} - define("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> { +const auto& toRgbaCompoundExpression() { + static auto signature = detail::makeSignature("to-rgba", [](const Color& color) -> Result<std::array<double, 4>> { return color.toArray(); }); + return signature; +} + +const auto& rgbaCompoundExpression() { + static auto signature = detail::makeSignature("rgba", [](double r, double g, double b, double a) { return rgba(r, g, b, a); }); + return signature; +} - define("rgba", [](double r, double g, double b, double a) { return rgba(r, g, b, a); }); - define("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); }); +const auto& rgbCompoundExpression() { + static auto signature = detail::makeSignature("rgb", [](double r, double g, double b) { return rgba(r, g, b, 1.0f); }); + return signature; +} - define("zoom", [](const EvaluationContext& params) -> Result<double> { +const auto& zoomCompoundExpression() { + static auto signature = detail::makeSignature("zoom", [](const EvaluationContext& params) -> Result<double> { if (!params.zoom) { return EvaluationError { "The 'zoom' expression is unavailable in the current evaluation context." @@ -322,8 +341,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return *(params.zoom); }); + return signature; +} - define("heatmap-density", [](const EvaluationContext& params) -> Result<double> { +const auto& heatmapDensityCompoundExpression() { + static auto signature = detail::makeSignature("heatmap-density", [](const EvaluationContext& params) -> Result<double> { if (!params.colorRampParameter) { return EvaluationError { "The 'heatmap-density' expression is unavailable in the current evaluation context." @@ -331,8 +353,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return *(params.colorRampParameter); }); + return signature; +} - define("line-progress", [](const EvaluationContext& params) -> Result<double> { +const auto& lineProgressCompoundExpression() { + static auto signature = detail::makeSignature("line-progress", [](const EvaluationContext& params) -> Result<double> { if (!params.colorRampParameter) { return EvaluationError { "The 'line-progress' expression is unavailable in the current evaluation context." @@ -340,8 +365,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return *(params.colorRampParameter); }); + return signature; +} - define("has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> { +const auto& hasContextCompoundExpression() { + static auto signature = detail::makeSignature("has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." @@ -350,11 +378,18 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return params.feature->getValue(key) ? true : false; }); - define("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> { + return signature; +} + +const auto& hasObjectCompoundExpression() { + static auto signature = detail::makeSignature("has", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<bool> { return object.find(key) != object.end(); }); + return signature; +} - define("get", [](const EvaluationContext& params, const std::string& key) -> Result<Value> { +const auto& getContextCompoundExpression() { + static auto signature = detail::makeSignature("get", [](const EvaluationContext& params, const std::string& key) -> Result<Value> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." @@ -367,14 +402,21 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return Value(toExpressionValue(*propertyValue)); }); - define("get", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<Value> { + return signature; +} + +const auto& getObjectCompoundExpression() { + static auto signature = detail::makeSignature("get", [](const std::string& key, const std::unordered_map<std::string, Value>& object) -> Result<Value> { if (object.find(key) == object.end()) { return Null; } return object.at(key); }); + return signature; +} - define("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> { +const auto& propertiesCompoundExpression() { + static auto signature = detail::makeSignature("properties", [](const EvaluationContext& params) -> Result<std::unordered_map<std::string, Value>> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." @@ -387,8 +429,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } return result; }); + return signature; +} - define("geometry-type", [](const EvaluationContext& params) -> Result<std::string> { +const auto& geometryTypeCompoundExpression() { + static auto signature = detail::makeSignature("geometry-type", [](const EvaluationContext& params) -> Result<std::string> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." @@ -406,8 +451,11 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali return "Unknown"; } }); + return signature; +} - define("id", [](const EvaluationContext& params) -> Result<Value> { +const auto& idCompoundExpression() { + static auto signature = detail::makeSignature("id", [](const EvaluationContext& params) -> Result<Value> { if (!params.feature) { return EvaluationError { "Feature data is unavailable in the current evaluation context." @@ -421,219 +469,482 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali } ); }); + return signature; +} - define("+", [](const Varargs<double>& args) -> Result<double> { +const auto& plusCompoundExpression() { + static auto signature = detail::makeSignature("+", [](const Varargs<double>& args) -> Result<double> { double sum = 0.0f; for (auto arg : args) { sum += arg; } return sum; }); - define("-", [](double a, double b) -> Result<double> { return a - b; }); - define("-", [](double a) -> Result<double> { return -a; }); - define("*", [](const Varargs<double>& args) -> Result<double> { + return signature; +} + +const auto& minusCompoundExpression() { + static auto signature = detail::makeSignature("-", [](double a, double b) -> Result<double> { return a - b; }); + return signature; +} + +const auto& negateCompoundExpression() { + static auto signature = detail::makeSignature("-", [](double a) -> Result<double> { return -a; }); + return signature; +} + +const auto& multiplyCompoundExpression() { + static auto signature = detail::makeSignature("*", [](const Varargs<double>& args) -> Result<double> { double prod = 1.0f; for (auto arg : args) { prod *= arg; } return prod; }); - define("/", [](double a, double b) -> Result<double> { return a / b; }); - define("%", [](double a, double b) -> Result<double> { return fmod(a, b); }); - define("^", [](double a, double b) -> Result<double> { return pow(a, b); }); - define("sqrt", [](double x) -> Result<double> { return sqrt(x); }); - define("log10", [](double x) -> Result<double> { return log10(x); }); - define("ln", [](double x) -> Result<double> { return log(x); }); - define("log2", [](double x) -> Result<double> { return util::log2(x); }); - define("sin", [](double x) -> Result<double> { return sin(x); }); - define("cos", [](double x) -> Result<double> { return cos(x); }); - define("tan", [](double x) -> Result<double> { return tan(x); }); - define("asin", [](double x) -> Result<double> { return asin(x); }); - define("acos", [](double x) -> Result<double> { return acos(x); }); - define("atan", [](double x) -> Result<double> { return atan(x); }); - - define("min", [](const Varargs<double>& args) -> Result<double> { + return signature; +} + +const auto& divideCompoundExpression() { + static auto signature = detail::makeSignature("/", [](double a, double b) -> Result<double> { return a / b; }); + return signature; +} + +const auto& modCompoundExpression() { + static auto signature = detail::makeSignature("%", [](double a, double b) -> Result<double> { return fmod(a, b); }); + return signature; +} + +const auto& powCompoundExpression() { + static auto signature = detail::makeSignature("^", [](double a, double b) -> Result<double> { return pow(a, b); }); + return signature; +} + +const auto& sqrtCompoundExpression() { + static auto signature = detail::makeSignature("sqrt", [](double x) -> Result<double> { return sqrt(x); }); + return signature; +} + +const auto& log10CompoundExpression() { + static auto signature = detail::makeSignature("log10", [](double x) -> Result<double> { return log10(x); }); + return signature; +} + +const auto& lnCompoundExpression() { + static auto signature = detail::makeSignature("ln", [](double x) -> Result<double> { return log(x); }); + return signature; +} + +const auto& log2CompoundExpression() { + static auto signature = detail::makeSignature("log2", [](double x) -> Result<double> { return util::log2(x); }); + return signature; +} + +const auto& sinCompoundExpression() { + static auto signature = detail::makeSignature("sin", [](double x) -> Result<double> { return sin(x); }); + return signature; +} + +const auto& cosCompoundExpression() { + static auto signature = detail::makeSignature("cos", [](double x) -> Result<double> { return cos(x); }); + return signature; +} + +const auto& tanCompoundExpression() { + static auto signature = detail::makeSignature("tan", [](double x) -> Result<double> { return tan(x); }); + return signature; +} + +const auto& asinCompoundExpression() { + static auto signature = detail::makeSignature("asin", [](double x) -> Result<double> { return asin(x); }); + return signature; +} + +const auto& acosCompoundExpression() { + static auto signature = detail::makeSignature("acos", [](double x) -> Result<double> { return acos(x); }); + return signature; +} + +const auto& atanCompoundExpression() { + static auto signature = detail::makeSignature("atan", [](double x) -> Result<double> { return atan(x); }); + return signature; +} + +const auto& minCompoundExpression() { + static auto signature = detail::makeSignature("min", [](const Varargs<double>& args) -> Result<double> { double result = std::numeric_limits<double>::infinity(); for (double arg : args) { result = fmin(arg, result); } return result; }); - define("max", [](const Varargs<double>& args) -> Result<double> { + return signature; +} + +const auto& maxCompoundExpression() { + static auto signature = detail::makeSignature("max", [](const Varargs<double>& args) -> Result<double> { double result = -std::numeric_limits<double>::infinity(); for (double arg : args) { result = fmax(arg, result); } return result; }); + return signature; +} + +const auto& roundCompoundExpression() { + static auto signature = detail::makeSignature("round", [](double x) -> Result<double> { return ::round(x); }); + return signature; +} - define("round", [](double x) -> Result<double> { return ::round(x); }); - define("floor", [](double x) -> Result<double> { return std::floor(x); }); - define("ceil", [](double x) -> Result<double> { return std::ceil(x); }); - define("abs", [](double x) -> Result<double> { return std::abs(x); }); +const auto& floorCompoundExpression() { + static auto signature = detail::makeSignature("floor", [](double x) -> Result<double> { return std::floor(x); }); + return signature; +} + +const auto& ceilCompoundExpression() { + static auto signature = detail::makeSignature("ceil", [](double x) -> Result<double> { return std::ceil(x); }); + return signature; +} - define("!", [](bool e) -> Result<bool> { return !e; }); +const auto& absCompoundExpression() { + static auto signature = detail::makeSignature("abs", [](double x) -> Result<double> { return std::abs(x); }); + return signature; +} - define("is-supported-script", [](const std::string& x) -> Result<bool> { +const auto& notCompoundExpression() { + static auto signature = detail::makeSignature("!", [](bool e) -> Result<bool> { return !e; }); + return signature; +} + +const auto& isSupportedScriptCompoundExpression() { + static auto signature = detail::makeSignature("is-supported-script", [](const std::string& x) -> Result<bool> { return util::i18n::isStringInSupportedScript(x); }); + return signature; +} - define("upcase", [](const std::string& input) -> Result<std::string> { +const auto& upcaseCompoundExpression() { + static auto signature = detail::makeSignature("upcase", [](const std::string& input) -> Result<std::string> { return platform::uppercase(input); }); - define("downcase", [](const std::string& input) -> Result<std::string> { + return signature; +} + +const auto& downcaseCompoundExpression() { + static auto signature = detail::makeSignature("downcase", [](const std::string& input) -> Result<std::string> { return platform::lowercase(input); }); - define("concat", [](const Varargs<Value>& args) -> Result<std::string> { + return signature; +} + +const auto& concatCompoundExpression() { + static auto signature = detail::makeSignature("concat", [](const Varargs<Value>& args) -> Result<std::string> { std::string s; for (const Value& arg : args) { s += toString(arg); } return s; }); - define("resolved-locale", [](const Collator& collator) -> Result<std::string> { + return signature; +} + +const auto& resolvedLocaleCompoundExpression() { + static auto signature = detail::makeSignature("resolved-locale", [](const Collator& collator) -> Result<std::string> { return collator.resolvedLocale(); }); + return signature; +} - define("error", [](const std::string& input) -> Result<type::ErrorType> { +const auto& errorCompoundExpression() { + static auto signature = detail::makeSignature("error", [](const std::string& input) -> Result<type::ErrorType> { return EvaluationError { input }; }); + return signature; +} - // Legacy Filters - define("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> { +// Legacy Filters +const auto& filterEqualsCompoundExpression() { + static auto signature = detail::makeSignature("filter-==", [](const EvaluationContext& params, const std::string& key, const Value &lhs) -> Result<bool> { const auto rhs = featurePropertyAsExpressionValue(params, key); return rhs ? lhs == *rhs : false; }); + return signature; +} - define("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> { +const auto& filterIdEqualsCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-==", [](const EvaluationContext& params, const Value &lhs) -> Result<bool> { return lhs == featureIdAsExpressionValue(params); }); + return signature; +} - define("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> { +const auto& filterTypeEqualsCompoundExpression() { + static auto signature = detail::makeSignature("filter-type-==", [](const EvaluationContext& params, const std::string &lhs) -> Result<bool> { if (!params.feature) return false; return featureTypeAsString(params.feature->getType()) == lhs; }); + return signature; +} - define("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { +const auto& filterLessThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-<", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { auto rhs = featurePropertyAsDouble(params, key); return rhs ? rhs < lhs : false; }); + return signature; +} - define("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { +const auto& filterLessThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-<", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { auto rhs = featurePropertyAsString(params, key); return rhs ? rhs < lhs : false; }); + return signature; +} - define("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> { +const auto& filterIdLessThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-<", [](const EvaluationContext& params, double lhs) -> Result<bool> { auto rhs = featureIdAsDouble(params); return rhs ? rhs < lhs : false; }); + return signature; +} - define("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { +const auto& filterIdLessThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-<", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { auto rhs = featureIdAsString(params); return rhs ? rhs < lhs : false; }); + return signature; +} - define("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { +const auto& filterMoreThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter->", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { auto rhs = featurePropertyAsDouble(params, key); return rhs ? rhs > lhs : false; }); + return signature; +} - define("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { +const auto& filterMoreThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter->", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { auto rhs = featurePropertyAsString(params, key); return rhs ? rhs > lhs : false; }); + return signature; +} - define("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> { +const auto& filterIdMoreThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-id->", [](const EvaluationContext& params, double lhs) -> Result<bool> { auto rhs = featureIdAsDouble(params); return rhs ? rhs > lhs : false; }); + return signature; +} - define("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { +const auto& filterIdMoreThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-id->", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { auto rhs = featureIdAsString(params); return rhs ? rhs > lhs : false; }); + return signature; +} - define("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { +const auto& filterLessOrEqualThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-<=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { auto rhs = featurePropertyAsDouble(params, key); return rhs ? rhs <= lhs : false; }); + return signature; +} - define("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { +const auto& filterLessOrEqualThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-<=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { auto rhs = featurePropertyAsString(params, key); return rhs ? rhs <= lhs : false; }); + return signature; +} - define("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> { +const auto& filterIdLessOrEqualThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-<=", [](const EvaluationContext& params, double lhs) -> Result<bool> { auto rhs = featureIdAsDouble(params); return rhs ? rhs <= lhs : false; }); + return signature; +} - define("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { +const auto& filterIdLessOrEqualThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-<=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { auto rhs = featureIdAsString(params); return rhs ? rhs <= lhs : false; }); + return signature; +} - define("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { +const auto& filterGreaterOrEqualThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter->=", [](const EvaluationContext& params, const std::string& key, double lhs) -> Result<bool> { auto rhs = featurePropertyAsDouble(params, key); return rhs ? rhs >= lhs : false; }); + return signature; +} - define("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { +const auto& filterGreaterOrEqualThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter->=", [](const EvaluationContext& params, const std::string& key, std::string lhs) -> Result<bool> { auto rhs = featurePropertyAsString(params, key); return rhs ? rhs >= lhs : false; }); + return signature; +} - define("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> { +const auto& filterIdGreaterOrEqualThanNumberCompoundExpression() { + static auto signature = detail::makeSignature("filter-id->=", [](const EvaluationContext& params, double lhs) -> Result<bool> { auto rhs = featureIdAsDouble(params); return rhs ? rhs >= lhs : false; }); + return signature; +} - define("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { +const auto& filterIdGreaterOrEqualThanStringCompoundExpression() { + static auto signature = detail::makeSignature("filter-id->=", [](const EvaluationContext& params, std::string lhs) -> Result<bool> { auto rhs = featureIdAsString(params); return rhs ? rhs >= lhs : false; }); + return signature; +} - define("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> { +const auto& filterHasCompoundExpression() { + static auto signature = detail::makeSignature("filter-has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> { assert(params.feature); return bool(params.feature->getValue(key)); }); + return signature; +} - define("filter-has-id", [](const EvaluationContext& params) -> Result<bool> { +const auto& filterHasIdCompoundExpression() { + static auto signature = detail::makeSignature("filter-has-id", [](const EvaluationContext& params) -> Result<bool> { assert(params.feature); return !params.feature->getID().is<NullValue>(); }); + return signature; +} - define("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> { +const auto& filterTypeInCompoundExpression() { + static auto signature = detail::makeSignature("filter-type-in", [](const EvaluationContext& params, const Varargs<std::string>& types) -> Result<bool> { assert(params.feature); optional<std::string> type = featureTypeAsString(params.feature->getType()); return std::find(types.begin(), types.end(), type) != types.end(); }); + return signature; +} - define("filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> { +const auto& filterIdInCompoundExpression() { + static auto signature = detail::makeSignature("filter-id-in", [](const EvaluationContext& params, const Varargs<Value>& ids) -> Result<bool> { auto id = featureIdAsExpressionValue(params); return std::find(ids.begin(), ids.end(), id) != ids.end(); }); + return signature; +} + - define("filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> { +const auto& filterInCompoundExpression() { + static auto signature = detail::makeSignature("filter-in", [](const EvaluationContext& params, const Varargs<Value>& varargs) -> Result<bool> { if (varargs.size() < 2) return false; assert(varargs[0].is<std::string>()); auto value = featurePropertyAsExpressionValue(params, varargs[0].get<std::string>()); return value ? std::find(varargs.begin() + 1, varargs.end(), *value) != varargs.end() : false; }); - - return definitions; + return signature; } -std::unordered_map<std::string, Definition> CompoundExpressionRegistry::definitions = initializeDefinitions(); +using ParseCompoundFunction = const std::unique_ptr<detail::SignatureBase>& (*)(); +MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry = mapbox::eternal::hash_map<mapbox::eternal::string, ParseCompoundFunction>({ + { "e", eCompoundExpression }, + { "pi", piCompoundExpression }, + { "ln2", ln2CompoundExpression }, + { "typeof", typeofCompoundExpression }, + { "to-rgba", toRgbaCompoundExpression }, + { "rgba", rgbaCompoundExpression }, + { "rgb", rgbCompoundExpression }, + { "zoom", zoomCompoundExpression }, + { "heatmap-density", heatmapDensityCompoundExpression }, + { "line-progress", lineProgressCompoundExpression }, + { "has", hasContextCompoundExpression }, + { "has", hasObjectCompoundExpression }, + { "get", getContextCompoundExpression }, + { "get", getObjectCompoundExpression }, + { "properties", propertiesCompoundExpression }, + { "geometry-type", geometryTypeCompoundExpression }, + { "id", idCompoundExpression }, + { "+", plusCompoundExpression }, + { "-", minusCompoundExpression }, + { "-", negateCompoundExpression }, + { "*", multiplyCompoundExpression }, + { "/", divideCompoundExpression }, + { "%", modCompoundExpression }, + { "^", powCompoundExpression }, + { "sqrt", sqrtCompoundExpression }, + { "log10", log10CompoundExpression }, + { "ln", lnCompoundExpression }, + { "log2", log2CompoundExpression }, + { "sin", sinCompoundExpression }, + { "cos", cosCompoundExpression }, + { "tan", tanCompoundExpression }, + { "asin", asinCompoundExpression }, + { "acos", acosCompoundExpression }, + { "atan", atanCompoundExpression }, + { "min", minCompoundExpression }, + { "max", maxCompoundExpression }, + { "round", roundCompoundExpression }, + { "floor", floorCompoundExpression }, + { "ceil", ceilCompoundExpression }, + { "abs", absCompoundExpression }, + { "!", notCompoundExpression }, + { "is-supported-script", isSupportedScriptCompoundExpression }, + { "upcase", upcaseCompoundExpression }, + { "downcase", downcaseCompoundExpression }, + { "concat", concatCompoundExpression }, + { "resolved-locale", resolvedLocaleCompoundExpression }, + { "error", errorCompoundExpression }, + // Legacy Filters + { "filter-==", filterEqualsCompoundExpression }, + { "filter-id-==", filterIdEqualsCompoundExpression }, + { "filter-type-==", filterTypeEqualsCompoundExpression }, + { "filter-<", filterLessThanNumberCompoundExpression }, + { "filter-<", filterLessThanStringCompoundExpression }, + { "filter-id-<", filterIdLessThanNumberCompoundExpression }, + { "filter-id-<", filterIdLessThanStringCompoundExpression }, + { "filter->", filterMoreThanNumberCompoundExpression }, + { "filter->", filterMoreThanStringCompoundExpression }, + { "filter-id->", filterIdMoreThanNumberCompoundExpression }, + { "filter-id->", filterIdMoreThanStringCompoundExpression }, + { "filter-<=", filterLessOrEqualThanNumberCompoundExpression }, + { "filter-<=", filterLessOrEqualThanStringCompoundExpression }, + { "filter-id-<=", filterIdLessOrEqualThanNumberCompoundExpression }, + { "filter-id-<=", filterIdLessOrEqualThanStringCompoundExpression }, + { "filter->=", filterGreaterOrEqualThanNumberCompoundExpression }, + { "filter->=", filterGreaterOrEqualThanStringCompoundExpression }, + { "filter-id->=", filterIdGreaterOrEqualThanNumberCompoundExpression }, + { "filter-id->=", filterIdGreaterOrEqualThanStringCompoundExpression }, + { "filter-has", filterHasCompoundExpression }, + { "filter-has-id", filterHasIdCompoundExpression }, + { "filter-type-in", filterTypeInCompoundExpression }, + { "filter-id-in", filterIdInCompoundExpression }, + { "filter-in", filterInCompoundExpression }, +}); using namespace mbgl::style::conversion; - -std::string expectedTypesError(const Definition& definition, + +using DefinitionIterator = decltype(compoundExpressionRegistry)::const_iterator; +using Definitions = std::pair<DefinitionIterator, DefinitionIterator>; + +std::string expectedTypesError(const Definitions& definitions, const std::vector<std::unique_ptr<Expression>>& args) { std::vector<std::string> availableOverloads; // Only used if there are no overloads with matching number of args std::vector<std::string> overloads; - for (const auto& signature : definition) { + for (auto it = definitions.first; it != definitions.second; ++it) { + const auto& signature = it->second(); signature->params.match( [&](const VarargsType& varargs) { std::string overload = "(" + toString(varargs.type) + ")"; @@ -671,13 +982,14 @@ std::string expectedTypesError(const Definition& definition, return "Expected arguments of type " + signatures + ", but found (" + actualTypes + ") instead."; } -static ParseResult createCompoundExpression(const Definition& definition, +static ParseResult createCompoundExpression(const Definitions& definitions, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { ParsingContext signatureContext(ctx.getKey()); - for (const std::unique_ptr<detail::SignatureBase>& signature : definition) { + for (auto it = definitions.first; it != definitions.second; ++it) { + const auto& signature = it->second(); signatureContext.clearErrors(); if (signature->params.is<std::vector<type::Type>>()) { @@ -713,10 +1025,10 @@ static ParseResult createCompoundExpression(const Definition& definition, } } - if (definition.size() == 1) { + if (definitions.second - definitions.first == 1) { ctx.appendErrors(std::move(signatureContext)); } else { - ctx.error(expectedTypesError(definition, args)); + ctx.error(expectedTypesError(definitions, args)); } return ParseResult(); @@ -725,20 +1037,19 @@ static ParseResult createCompoundExpression(const Definition& definition, ParseResult parseCompoundExpression(const std::string name, const Convertible& value, ParsingContext& ctx) { assert(isArray(value) && arrayLength(value) > 0); - auto it = CompoundExpressionRegistry::definitions.find(name); - if (it == CompoundExpressionRegistry::definitions.end()) { + const auto definitions = compoundExpressionRegistry.equal_range(name.c_str()); + if (definitions.first == definitions.second) { ctx.error( R"(Unknown expression ")" + name + R"(". If you wanted a literal array, use ["literal", [...]].)", 0 ); return ParseResult(); } - const CompoundExpressionRegistry::Definition& definition = it->second; auto length = arrayLength(value); - for (std::size_t j = 0; j < definition.size(); j++) { - const std::unique_ptr<detail::SignatureBase>& signature = definition[j]; + for (auto it = definitions.first; it != definitions.second; ++it) { + const auto& signature = it->second(); if ( signature->params.is<VarargsType>() || @@ -752,7 +1063,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v args.reserve(length - 1); for (std::size_t i = 1; i < length; i++) { - optional<type::Type> expected = definition[j]->params.match( + optional<type::Type> expected = signature->params.match( [](const VarargsType& varargs) { return varargs.type; }, [&](const std::vector<type::Type>& params_) { return params_[i - 1]; } ); @@ -769,7 +1080,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v // on to next one. continue; } else { - ParseResult parseWithArgs = createCompoundExpression(definition, std::move(args), ctx); + ParseResult parseWithArgs = createCompoundExpression(definitions, std::move(args), ctx); if (parseWithArgs) { return parseWithArgs; } @@ -790,7 +1101,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v args.push_back(std::move(*parsed)); } - ctx.error(expectedTypesError(definition, args)); + ctx.error(expectedTypesError(definitions, args)); return ParseResult(); } @@ -799,7 +1110,7 @@ ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { - return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + return createCompoundExpression(compoundExpressionRegistry.equal_range(name.c_str()), std::move(args), ctx); } CompoundExpression::CompoundExpression(const detail::SignatureBase& signature_, std::vector<std::unique_ptr<Expression>> args_) : @@ -844,6 +1155,10 @@ bool CompoundExpression::operator==(const Expression& e) const { return false; } +bool CompoundExpression::exists(const std::string& name) { + return compoundExpressionRegistry.contains(name.c_str()); +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/is_expression.cpp b/src/mbgl/style/expression/is_expression.cpp index 34f0fec7a3..cf26182164 100644 --- a/src/mbgl/style/expression/is_expression.cpp +++ b/src/mbgl/style/expression/is_expression.cpp @@ -16,8 +16,7 @@ bool isExpression(const Convertible& value) { optional<std::string> name = toString(arrayMember(value, 0)); if (!name) return false; - return getExpression(*name) || - (CompoundExpressionRegistry::definitions.find(*name) != CompoundExpressionRegistry::definitions.end()); + return isExpression(*name) || CompoundExpression::exists(*name); } diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 79a2f251e2..411aa660e8 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -97,6 +97,7 @@ ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, return child.parse(value); } +using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = mapbox::eternal::hash_map<mapbox::eternal::string, ParseFunction>({ {"==", parseComparison}, {"!=", parseComparison}, @@ -126,16 +127,11 @@ MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = mapbox::eternal::hash_m {"to-color", Coercion::parse}, {"to-number", Coercion::parse}, {"to-string", Coercion::parse}, - {"var", Var::parse} + {"var", Var::parse}, }); -ParseFunction getExpression(const std::string& name) { - auto parseFunction = expressionRegistry.find(name.c_str()); - if (parseFunction != expressionRegistry.end()) { - return parseFunction->second; - } else { - return nullptr; - } +bool isExpression(const std::string& name) { + return expressionRegistry.contains(name.c_str()); } ParseResult ParsingContext::parse(const Convertible& value, optional<TypeAnnotationOption> typeAnnotationOption) { |