From 8696db551b82601971676ab892afc2a479342f77 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 29 Jun 2018 12:52:08 -0700 Subject: [core] Convert legacy functions directly to expressions --- .../function/composite_function.benchmark.cpp | 1 - cmake/core-files.cmake | 13 +- cmake/test-files.cmake | 2 - include/mbgl/style/conversion/function.hpp | 400 +----------- include/mbgl/style/conversion/property_value.hpp | 1 + include/mbgl/style/expression/dsl.hpp | 4 + include/mbgl/style/expression/error.hpp | 39 ++ include/mbgl/style/function/categorical_stops.hpp | 40 -- .../style/function/composite_categorical_stops.hpp | 30 - .../style/function/composite_exponential_stops.hpp | 35 -- .../style/function/composite_interval_stops.hpp | 32 - include/mbgl/style/function/convert.hpp | 322 ---------- include/mbgl/style/function/exponential_stops.hpp | 56 -- include/mbgl/style/function/identity_stops.hpp | 20 - include/mbgl/style/function/interval_stops.hpp | 51 -- src/mbgl/style/conversion/function.cpp | 699 +++++++++++++++++++++ src/mbgl/style/expression/dsl.cpp | 9 + src/mbgl/style/function/categorical_stops.cpp | 41 -- src/mbgl/style/function/convert.cpp | 40 -- src/mbgl/style/function/identity_stops.cpp | 89 --- test/style/function/exponential_stops.test.cpp | 20 - test/style/function/interval_stops.test.cpp | 20 - 22 files changed, 774 insertions(+), 1190 deletions(-) create mode 100644 include/mbgl/style/expression/error.hpp delete mode 100644 include/mbgl/style/function/categorical_stops.hpp delete mode 100644 include/mbgl/style/function/composite_categorical_stops.hpp delete mode 100644 include/mbgl/style/function/composite_exponential_stops.hpp delete mode 100644 include/mbgl/style/function/composite_interval_stops.hpp delete mode 100644 include/mbgl/style/function/convert.hpp delete mode 100644 include/mbgl/style/function/exponential_stops.hpp delete mode 100644 include/mbgl/style/function/identity_stops.hpp delete mode 100644 include/mbgl/style/function/interval_stops.hpp create mode 100644 src/mbgl/style/conversion/function.cpp delete mode 100644 src/mbgl/style/function/categorical_stops.cpp delete mode 100644 src/mbgl/style/function/convert.cpp delete mode 100644 src/mbgl/style/function/identity_stops.cpp delete mode 100644 test/style/function/exponential_stops.test.cpp delete mode 100644 test/style/function/interval_stops.test.cpp diff --git a/benchmark/function/composite_function.benchmark.cpp b/benchmark/function/composite_function.benchmark.cpp index e2545e6349..8442e0aa15 100644 --- a/benchmark/function/composite_function.benchmark.cpp +++ b/benchmark/function/composite_function.benchmark.cpp @@ -2,7 +2,6 @@ #include -#include #include #include diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 9a26ac70b0..7d7e887a76 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -426,6 +426,7 @@ set(MBGL_CORE_FILES src/mbgl/style/conversion/constant.cpp src/mbgl/style/conversion/coordinate.cpp src/mbgl/style/conversion/filter.cpp + src/mbgl/style/conversion/function.cpp src/mbgl/style/conversion/geojson.cpp src/mbgl/style/conversion/geojson_options.cpp src/mbgl/style/conversion/get_json_type.cpp @@ -454,6 +455,7 @@ set(MBGL_CORE_FILES include/mbgl/style/expression/compound_expression.hpp include/mbgl/style/expression/dsl.hpp include/mbgl/style/expression/equals.hpp + include/mbgl/style/expression/error.hpp include/mbgl/style/expression/expression.hpp include/mbgl/style/expression/find_zoom_curve.hpp include/mbgl/style/expression/get_covering_stops.hpp @@ -498,20 +500,9 @@ set(MBGL_CORE_FILES # style/function include/mbgl/style/function/camera_function.hpp - include/mbgl/style/function/categorical_stops.hpp - include/mbgl/style/function/composite_categorical_stops.hpp - include/mbgl/style/function/composite_exponential_stops.hpp include/mbgl/style/function/composite_function.hpp - include/mbgl/style/function/composite_interval_stops.hpp - include/mbgl/style/function/convert.hpp - include/mbgl/style/function/exponential_stops.hpp - include/mbgl/style/function/identity_stops.hpp - include/mbgl/style/function/interval_stops.hpp include/mbgl/style/function/source_function.hpp - src/mbgl/style/function/categorical_stops.cpp - src/mbgl/style/function/convert.cpp src/mbgl/style/function/expression.cpp - src/mbgl/style/function/identity_stops.cpp # style/layers include/mbgl/style/layers/background_layer.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index b2c0172d73..5d76ffcade 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -90,8 +90,6 @@ set(MBGL_TEST_FILES # style/function test/style/function/camera_function.test.cpp test/style/function/composite_function.test.cpp - test/style/function/exponential_stops.test.cpp - test/style/function/interval_stops.test.cpp test/style/function/source_function.test.cpp # test diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index 932925c53c..5ddede324b 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -3,224 +3,15 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include +#include namespace mbgl { namespace style { namespace conversion { -template -optional> convertStops(const Convertible& value, Error& error) { - auto stopsValue = objectMember(value, "stops"); - if (!stopsValue) { - error = { "function value must specify stops" }; - return {}; - } - - if (!isArray(*stopsValue)) { - error = { "function stops must be an array" }; - return {}; - } - - if (arrayLength(*stopsValue) == 0) { - error = { "function must have at least one stop" }; - return {}; - } - - std::map stops; - for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { - const auto& stopValue = arrayMember(*stopsValue, i); - - if (!isArray(stopValue)) { - error = { "function stop must be an array" }; - return {}; - } - - if (arrayLength(stopValue) != 2) { - error = { "function stop must have two elements" }; - return {}; - } - - optional d = convert(arrayMember(stopValue, 0), error); - if (!d) { - return {}; - } - - optional r = convert(arrayMember(stopValue, 1), error); - if (!r) { - return {}; - } - - stops.emplace(*d, *r); - } - - return stops; -} - -template -struct Converter> { - static constexpr const char * type = "exponential"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops(value, error); - if (!stops) { - return {}; - } - - auto baseValue = objectMember(value, "base"); - if (!baseValue) { - return ExponentialStops(*stops); - } - - optional base = toNumber(*baseValue); - if (!base) { - error = { "function base must be a number"}; - return {}; - } - - return ExponentialStops(*stops, *base); - } -}; - -template -struct Converter> { - static constexpr const char * type = "interval"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops(value, error); - if (!stops) { - return {}; - } - return IntervalStops(*stops); - } -}; - -template <> -struct Converter { - optional operator()(const Convertible& value, Error& error) const { - auto b = toBool(value); - if (b) { - return { *b }; - } - - auto n = toNumber(value); - if (n) { - return { int64_t(*n) }; - } - - auto s = toString(value); - if (s) { - return { *s }; - } - - error = { "stop domain value must be a number, string, or boolean" }; - return {}; - } -}; - -template -struct Converter> { - static constexpr const char * type = "categorical"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops(value, error); - if (!stops) { - return {}; - } - return CategoricalStops( - std::map((*stops).begin(), (*stops).end())); - } -}; - -template -struct Converter> { - static constexpr const char * type = "identity"; - - optional> operator()(const Convertible&, Error&) const { - return IdentityStops(); - } -}; - -template -struct StopsConverter; - -template -struct StopsConverter> { -public: - optional> operator()(const Convertible& value, Error& error) const { - std::string type = util::Interpolatable::value ? "exponential" : "interval"; - - auto typeValue = objectMember(value, "type"); - if (typeValue && toString(*typeValue)) { - type = *toString(*typeValue); - } - - bool matched = false; - optional> result; - - // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226 - auto tryConvert = [&] (auto* tp) { - using Stops = std::decay_t; - if (type == Converter::type) { - matched = true; - optional stops = convert(value, error); - if (stops) { - result = variant(*stops); - } - } - }; - - util::ignore({ - (tryConvert((Ts*)nullptr), 0)... - }); - - if (!matched) { - error = { "unsupported function type" }; - return {}; - } - - return result; - } -}; - -template -struct Converter> { - optional> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; - return {}; - } - - using Stops = std::conditional_t< - util::Interpolatable::value, - variant< - ExponentialStops, - IntervalStops>, - variant< - IntervalStops>>; - - auto stops = StopsConverter()(value, error); - if (!stops) { - return {}; - } - - return CameraFunction((*stops).match([&] (const auto& s) { - return expression::Convert::toExpression(s); - }), false); - } -}; - template optional> convertDefaultValue(const Convertible& value, Error& error) { auto defaultValueValue = objectMember(value, "default"); @@ -237,199 +28,48 @@ optional> convertDefaultValue(const Convertible& value, Error& error return { *defaultValue }; } -template -struct Converter> { - optional> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; - return {}; - } - - auto propertyValue = objectMember(value, "property"); - if (!propertyValue) { - error = { "function must specify property" }; - return {}; - } - - auto propertyString = toString(*propertyValue); - if (!propertyString) { - error = { "function property must be a string" }; - return {}; - } - - using Stops = std::conditional_t< - util::Interpolatable::value, - variant< - ExponentialStops, - IntervalStops, - CategoricalStops, - IdentityStops>, - variant< - IntervalStops, - CategoricalStops, - IdentityStops>>; - - auto stops = StopsConverter()(value, error); - if (!stops) { - return {}; - } - - auto defaultValue = convertDefaultValue(value, error); - if (!defaultValue) { - return {}; - } - - return SourceFunction((*stops).match([&] (const auto& s) { - return expression::Convert::toExpression(*propertyString, s); - }), *defaultValue); - } -}; - -template -struct CompositeValue : std::pair { - using std::pair::pair; -}; - -template -struct Converter> { - optional> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "stop must be an object" }; - return {}; - } - - auto zoomValue = objectMember(value, "zoom"); - if (!zoomValue) { - error = { "stop must specify zoom" }; - return {}; - } - - auto propertyValue = objectMember(value, "value"); - if (!propertyValue) { - error = { "stop must specify value" }; - return {}; - } - - optional z = convert(*zoomValue, error); - if (!z) { - return {}; - } - - optional s = convert(*propertyValue, error); - if (!s) { - return {}; - } - - return CompositeValue { *z, *s }; - } -}; +optional> convertCameraFunctionToExpression(expression::type::Type, const Convertible&, Error&); +optional> convertSourceFunctionToExpression(expression::type::Type, const Convertible&, Error&); +optional> convertCompositeFunctionToExpression(expression::type::Type, const Convertible&, Error&); template -struct Converter> { - static constexpr const char * type = "exponential"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops, T>(value, error); - if (!stops) { +struct Converter> { + optional> operator()(const Convertible& value, Error& error) const { + auto expression = convertCameraFunctionToExpression(expression::valueTypeToExpressionType(), value, error); + if (!expression) { return {}; } - - auto base = 1.0f; - auto baseValue = objectMember(value, "base"); - if (baseValue && toNumber(*baseValue)) { - base = *toNumber(*baseValue); - } - - std::map> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeExponentialStops(convertedStops, base); + return CameraFunction(std::move(*expression), false); } }; template -struct Converter> { - static constexpr const char * type = "interval"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops, T>(value, error); - if (!stops) { +struct Converter> { + optional> operator()(const Convertible& value, Error& error) const { + auto expression = convertSourceFunctionToExpression(expression::valueTypeToExpressionType(), value, error); + if (!expression) { return {}; } - - std::map> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeIntervalStops(convertedStops); - } -}; - -template -struct Converter> { - static constexpr const char * type = "categorical"; - - optional> operator()(const Convertible& value, Error& error) const { - auto stops = convertStops, T>(value, error); - if (!stops) { + auto defaultValue = convertDefaultValue(value, error); + if (!defaultValue) { return {}; } - - std::map> convertedStops; - for (const auto& stop : *stops) { - convertedStops[stop.first.first].emplace(stop.first.second, stop.second); - } - - return CompositeCategoricalStops(convertedStops); + return SourceFunction(std::move(*expression), *defaultValue); } }; template struct Converter> { optional> operator()(const Convertible& value, Error& error) const { - if (!isObject(value)) { - error = { "function must be an object" }; + auto expression = convertCompositeFunctionToExpression(expression::valueTypeToExpressionType(), value, error); + if (!expression) { return {}; } - - auto propertyValue = objectMember(value, "property"); - if (!propertyValue) { - error = { "function must specify property" }; - return {}; - } - - auto propertyString = toString(*propertyValue); - if (!propertyString) { - error = { "function property must be a string" }; - return {}; - } - - using Stops = std::conditional_t< - util::Interpolatable::value, - variant< - CompositeExponentialStops, - CompositeIntervalStops, - CompositeCategoricalStops>, - variant< - CompositeIntervalStops, - CompositeCategoricalStops>>; - - auto stops = StopsConverter()(value, error); - if (!stops) { - return {}; - } - auto defaultValue = convertDefaultValue(value, error); if (!defaultValue) { return {}; } - - return CompositeFunction((*stops).match([&] (const auto& s) { - return expression::Convert::toExpression(*propertyString, s); - }), *defaultValue); + return CompositeFunction(std::move(*expression), *defaultValue); } }; diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index dc1c32830f..e52c63d023 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index 8a5d1d84f5..22278b0975 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace mbgl { @@ -15,6 +16,8 @@ namespace dsl { // This convenience API does little to no expression validation or type-checking, and is intended for // use only by test and other non-production code. +std::unique_ptr error(std::string); + std::unique_ptr literal(const char* value); std::unique_ptr literal(Value value); std::unique_ptr literal(std::initializer_list value); @@ -22,6 +25,7 @@ std::unique_ptr literal(std::initializer_list value); std::unique_ptr number(std::unique_ptr); std::unique_ptr string(std::unique_ptr); +std::unique_ptr boolean(std::unique_ptr); std::unique_ptr toColor(const char* value); std::unique_ptr toColor(std::unique_ptr); diff --git a/include/mbgl/style/expression/error.hpp b/include/mbgl/style/expression/error.hpp new file mode 100644 index 0000000000..bfb9247d11 --- /dev/null +++ b/include/mbgl/style/expression/error.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace style { +namespace expression { + +class Error : public Expression { +public: + Error(std::string message_) + : Expression(type::Error), + message(std::move(message_)) {} + + void eachChild(const std::function&) const override {} + + bool operator==(const Expression& e) const override { + return dynamic_cast(&e); + } + + EvaluationResult evaluate(const EvaluationContext&) const override { + return EvaluationError{message}; + } + + std::vector> possibleOutputs() const override { + return {}; + } + + std::string getOperator() const override { return "error"; } + +private: + std::string message; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp deleted file mode 100644 index c8505115ab..0000000000 --- a/include/mbgl/style/function/categorical_stops.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -namespace mbgl { -namespace style { - -class CategoricalValue : public variant { -public: - using variant::variant; -}; - -template -class CategoricalStops { -public: - using Stops = std::map; - - Stops stops; - - CategoricalStops() = default; - CategoricalStops(Stops stops_) - : stops(std::move(stops_)) { - assert(stops.size() > 0); - } - - optional evaluate(const Value&) const; - - friend bool operator==(const CategoricalStops& lhs, - const CategoricalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_categorical_stops.hpp b/include/mbgl/style/function/composite_categorical_stops.hpp deleted file mode 100644 index b796621d1a..0000000000 --- a/include/mbgl/style/function/composite_categorical_stops.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -namespace mbgl { -namespace style { - -template -class CompositeCategoricalStops { -public: - using Stops = std::map>; - Stops stops; - - CompositeCategoricalStops() = default; - CompositeCategoricalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - CategoricalStops innerStops(const std::map& stops_) const { - return CategoricalStops(stops_); - } - - friend bool operator==(const CompositeCategoricalStops& lhs, - const CompositeCategoricalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_exponential_stops.hpp b/include/mbgl/style/function/composite_exponential_stops.hpp deleted file mode 100644 index f1ad32a04d..0000000000 --- a/include/mbgl/style/function/composite_exponential_stops.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace style { - -template -class CompositeExponentialStops { -public: - using Stops = std::map>; - - Stops stops; - float base = 1.0f; - - CompositeExponentialStops() = default; - CompositeExponentialStops(Stops stops_, float base_ = 1.0f) - : stops(std::move(stops_)), - base(base_) { - } - - ExponentialStops innerStops(const std::map& stops_) const { - return ExponentialStops(stops_, base); - } - - friend bool operator==(const CompositeExponentialStops& lhs, - const CompositeExponentialStops& rhs) { - return lhs.stops == rhs.stops && lhs.base == rhs.base; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/composite_interval_stops.hpp b/include/mbgl/style/function/composite_interval_stops.hpp deleted file mode 100644 index 3c495f2a7f..0000000000 --- a/include/mbgl/style/function/composite_interval_stops.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace style { - -template -class CompositeIntervalStops { -public: - using Stops = std::map>; - Stops stops; - - CompositeIntervalStops() = default; - CompositeIntervalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - IntervalStops innerStops(const std::map& stops_) const { - return IntervalStops(stops_); - } - - friend bool operator==(const CompositeIntervalStops& lhs, - const CompositeIntervalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp deleted file mode 100644 index a0dae992fa..0000000000 --- a/include/mbgl/style/function/convert.hpp +++ /dev/null @@ -1,322 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - - -namespace mbgl { -namespace style { -namespace expression { - -namespace detail { - -class ErrorExpression : public Expression { -public: - ErrorExpression(std::string message_) : Expression(type::Error), message(std::move(message_)) {} - void eachChild(const std::function&) const override {} - - bool operator==(const Expression& e) const override { - return dynamic_cast(&e); - } - - EvaluationResult evaluate(const EvaluationContext&) const override { - return EvaluationError{message}; - } - - std::vector> possibleOutputs() const override { - return {}; - } - - std::string getOperator() const override { return "error"; } -private: - std::string message; -}; - -} // namespace detail - - -// Create expressions representing 'classic' (i.e. stop-based) style functions - -struct Convert { - template - static std::unique_ptr makeLiteral(const T& value) { - return std::make_unique(Value(toExpressionValue(value))); - } - - static std::unique_ptr makeGet(type::Type type, const std::string& property) { - ParsingContext ctx; - std::vector> getArgs; - getArgs.push_back(makeLiteral(property)); - ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); - assert(get); - assert(ctx.getErrors().size() == 0); - - std::vector> assertionArgs; - assertionArgs.push_back(std::move(*get)); - - return std::make_unique(type, std::move(assertionArgs)); - } - - static std::unique_ptr makeZoom() { - ParsingContext ctx; - ParseResult zoom = createCompoundExpression("zoom", std::vector>(), ctx); - assert(zoom); - assert(ctx.getErrors().size() == 0); - return std::move(*zoom); - } - - static std::unique_ptr makeError(std::string message) { - return std::make_unique(message); - } - - template - static ParseResult makeMatch(type::Type type, - std::unique_ptr input, - std::map> stops) { - // match expression - typename Match::Branches branches; - for(auto it = stops.begin(); it != stops.end(); it++) { - assert(it->first.template is()); - Key key = it->first.template get(); - branches.emplace( - std::move(key), - std::move(it->second) - ); - } - - return ParseResult(std::make_unique>(std::move(type), - std::move(input), - std::move(branches), - makeError("No matching label"))); - } - - static ParseResult makeCase(type::Type type, - std::unique_ptr input, - std::map> stops) { - // case expression - std::vector branches; - - auto it = stops.find(true); - std::unique_ptr true_case = it == stops.end() ? - makeError("No matching label") : - std::move(it->second); - - it = stops.find(false); - std::unique_ptr false_case = it == stops.end() ? - makeError("No matching label") : - std::move(it->second); - - branches.push_back(std::make_pair(std::move(input), std::move(true_case))); - return ParseResult(std::make_unique(std::move(type), std::move(branches), std::move(false_case))); - } - - template - static ParseResult fromCategoricalStops(std::map stops, const std::string& property) { - assert(stops.size() > 0); - - std::map> convertedStops; - for(const std::pair& stop : stops) { - convertedStops.emplace( - stop.first, - makeLiteral(stop.second) - ); - } - - type::Type type = valueTypeToExpressionType(); - - const CategoricalValue& firstKey = stops.begin()->first; - return firstKey.match( - [&](bool) { - return makeCase(type, makeGet(type::Boolean, property), std::move(convertedStops)); - }, - [&](const std::string&) { - return makeMatch(type, makeGet(type::String, property), std::move(convertedStops)); - }, - [&](int64_t) { - return makeMatch(type, makeGet(type::Number, property), std::move(convertedStops)); - } - ); - } - - template - static std::map> convertStops(const std::map& stops) { - std::map> convertedStops; - for(const auto& stop : stops) { - convertedStops.emplace( - stop.first, - makeLiteral(stop.second) - ); - } - return convertedStops; - } - - template - static std::unique_ptr toExpression(const ExponentialStops& stops) - { - ParsingContext ctx; - ParseResult e = createInterpolate(valueTypeToExpressionType(), - ExponentialInterpolator(stops.base), - makeZoom(), - convertStops(stops.stops), - ctx); - assert(e); - return std::move(*e); - } - - template - static std::unique_ptr toExpression(const IntervalStops& stops) - { - ParseResult e(std::make_unique(valueTypeToExpressionType(), - makeZoom(), - convertStops(stops.stops))); - assert(e); - return std::move(*e); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const ExponentialStops& stops) - { - ParsingContext ctx; - ParseResult e = createInterpolate(valueTypeToExpressionType(), - ExponentialInterpolator(stops.base), - makeGet(type::Number, property), - convertStops(stops.stops), - ctx); - assert(e); - return std::move(*e); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const IntervalStops& stops) - { - std::unique_ptr get = makeGet(type::Number, property); - ParseResult e(std::make_unique(valueTypeToExpressionType(), - std::move(get), - convertStops(stops.stops))); - assert(e); - return std::move(*e); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const CategoricalStops& stops) - { - ParseResult expr = fromCategoricalStops(stops.stops, property); - assert(expr); - return std::move(*expr); - } - - // interpolatable zoom curve - template - static typename std::enable_if_t::value, - ParseResult> makeZoomCurve(std::map> stops) { - ParsingContext ctx; - return createInterpolate(valueTypeToExpressionType(), - ExponentialInterpolator(1.0), - makeZoom(), - std::move(stops), - ctx); - } - - // non-interpolatable zoom curve - template - static typename std::enable_if_t::value, - ParseResult> makeZoomCurve(std::map> stops) { - return ParseResult(std::make_unique(valueTypeToExpressionType(), makeZoom(), std::move(stops))); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const CompositeExponentialStops& stops) - { - ParsingContext ctx; - - std::map> outerStops; - for (const std::pair>& stop : stops.stops) { - ParseResult innerInterpolate = createInterpolate(valueTypeToExpressionType(), - ExponentialInterpolator(stops.base), - makeGet(type::Number, property), - convertStops(stop.second), - ctx); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const CompositeIntervalStops& stops) - { - std::map> outerStops; - for (const std::pair>& stop : stops.stops) { - std::unique_ptr get = makeGet(type::Number, property); - ParseResult innerInterpolate(std::make_unique(valueTypeToExpressionType(), - std::move(get), - convertStops(stop.second))); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const CompositeCategoricalStops& stops) - { - std::map> outerStops; - for (const std::pair>& stop : stops.stops) { - ParseResult innerInterpolate = fromCategoricalStops(stop.second, property); - assert(innerInterpolate); - outerStops.emplace(stop.first, std::move(*innerInterpolate)); - } - - ParseResult zoomCurve = makeZoomCurve(std::move(outerStops)); - assert(zoomCurve); - return std::move(*zoomCurve); - } - - template - static std::unique_ptr toExpression(const std::string& property, - const IdentityStops&) - { - return fromIdentityFunction(property, expression::valueTypeToExpressionType()); - } - -private: - static std::unique_ptr fromIdentityFunction(const std::string& property, type::Type type); -}; - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp deleted file mode 100644 index b3866c4059..0000000000 --- a/include/mbgl/style/function/exponential_stops.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace mbgl { -namespace style { - -template -class ExponentialStops { -public: - using Stops = std::map; - - Stops stops; - float base = 1.0f; - - ExponentialStops() = default; - ExponentialStops(Stops stops_, float base_ = 1.0f) - : stops(std::move(stops_)), - base(base_) { - } - - optional evaluate(float z) const { - if (stops.empty()) { - return {}; - } - - auto it = stops.upper_bound(z); - if (it == stops.end()) { - return stops.rbegin()->second; - } else if (it == stops.begin()) { - return stops.begin()->second; - } else { - return util::interpolate(std::prev(it)->second, it->second, - util::interpolationFactor(base, { std::prev(it)->first, it->first }, z)); - } - } - - optional evaluate(const Value& value) const { - optional z = numericValue(value); - if (!z) { - return {}; - } - return evaluate(*z); - } - - friend bool operator==(const ExponentialStops& lhs, - const ExponentialStops& rhs) { - return lhs.stops == rhs.stops && lhs.base == rhs.base; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp deleted file mode 100644 index 741ebbbe0c..0000000000 --- a/include/mbgl/style/function/identity_stops.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -namespace mbgl { -namespace style { - -template -class IdentityStops { -public: - optional evaluate(const Value&) const; - - friend bool operator==(const IdentityStops&, - const IdentityStops&) { - return true; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp deleted file mode 100644 index 45e2dc6f2e..0000000000 --- a/include/mbgl/style/function/interval_stops.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include - -#include - -namespace mbgl { -namespace style { - -template -class IntervalStops { -public: - using Stops = std::map; - Stops stops; - - IntervalStops() = default; - IntervalStops(Stops stops_) - : stops(std::move(stops_)) { - } - - optional evaluate(float z) const { - if (stops.empty()) { - return {}; - } - - auto it = stops.upper_bound(z); - if (it == stops.end()) { - return stops.rbegin()->second; - } else if (it == stops.begin()) { - return stops.begin()->second; - } else { - return std::prev(it)->second; - } - } - - optional evaluate(const Value& value) const { - optional z = numericValue(value); - if (!z) { - return {}; - } - return evaluate(*z); - } - - friend bool operator==(const IntervalStops& lhs, - const IntervalStops& rhs) { - return lhs.stops == rhs.stops; - } -}; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp new file mode 100644 index 0000000000..64adf522a1 --- /dev/null +++ b/src/mbgl/style/conversion/function.cpp @@ -0,0 +1,699 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +using namespace expression; +using namespace expression::dsl; + +// Ad-hoc Converters for double and int64_t. We should replace float with double wholesale, +// and promote the int64_t Converter to general use (and it should check that the input is +// an integer). +template <> +struct Converter { + optional operator()(const Convertible& value, Error& error) const { + auto converted = convert(value, error); + if (!converted) { + return {}; + } + return *converted; + } +}; + +template <> +struct Converter { + optional operator()(const Convertible& value, Error& error) const { + auto converted = convert(value, error); + if (!converted) { + return {}; + } + return *converted; + } +}; + +enum class FunctionType { + Interval, + Exponential, + Categorical, + Identity, + Invalid +}; + +static bool interpolatable(type::Type type) { + return type.match( + [&] (const type::NumberType&) { + return true; + }, + [&] (const type::ColorType&) { + return true; + }, + [&] (const type::Array& array) { + return array.N && array.itemType == type::Number; + }, + [&] (const auto&) { + return false; + } + ); +} + +static FunctionType functionType(type::Type type, const Convertible& value) { + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + return interpolatable(type) ? FunctionType::Exponential : FunctionType::Interval; + } + + optional string = toString(*typeValue); + if (!string) { + return FunctionType::Invalid; + } + + if (*string == "interval") + return FunctionType::Interval; + if (*string == "exponential" && interpolatable(type)) + return FunctionType::Exponential; + if (*string == "categorical") + return FunctionType::Categorical; + if (*string == "identity") + return FunctionType::Identity; + + return FunctionType::Invalid; +} + +static optional> convertLiteral(type::Type type, const Convertible& value, Error& error) { + return type.match( + [&] (const type::NumberType&) -> optional> { + auto result = convert(value, error); + if (!result) { + return {}; + } + return literal(double(*result)); + }, + [&] (const type::BooleanType&) -> optional> { + auto result = convert(value, error); + if (!result) { + return {}; + } + return literal(*result); + }, + [&] (const type::StringType&) -> optional> { + auto result = convert(value, error); + if (!result) { + return {}; + } + return literal(*result); + }, + [&] (const type::ColorType&) -> optional> { + auto result = convert(value, error); + if (!result) { + return {}; + } + return literal(*result); + }, + [&] (const type::Array& array) -> optional> { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + if (array.N && arrayLength(value) != *array.N) { + error = { "value must be an array of length " + util::toString(*array.N) }; + return {}; + } + return array.itemType.match( + [&] (const type::NumberType&) -> optional> { + std::vector result; + result.reserve(arrayLength(value)); + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional number = toNumber(arrayMember(value, i)); + if (!number) { + error = { "value must be an array of numbers" }; + return {}; + } + result.push_back(double(*number)); + } + return literal(result); + }, + [&] (const type::StringType&) -> optional> { + std::vector result; + result.reserve(arrayLength(value)); + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional string = toString(arrayMember(value, i)); + if (!string) { + error = { "value must be an array of strings" }; + return {}; + } + result.push_back(*string); + } + return literal(result); + }, + [&] (const auto&) -> optional> { + assert(false); // No properties use this type. + return {}; + } + ); + }, + [&] (const type::NullType&) -> optional> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ObjectType&) -> optional> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ErrorType&) -> optional> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::ValueType&) -> optional> { + assert(false); // No properties use this type. + return {}; + }, + [&] (const type::CollatorType&) -> optional> { + assert(false); // No properties use this type. + return {}; + } + ); +} + +static optional>> convertStops(type::Type type, + const Convertible& value, + Error& error) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + error = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + error = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + error = { "function must have at least one stop" }; + return {}; + } + + std::map> stops; + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + optional t = convert(arrayMember(stopValue, 0), error); + if (!t) { + return {}; + } + + optional> e = convertLiteral(type, arrayMember(stopValue, 1), error); + if (!e) { + return {}; + } + + stops.emplace(*t, std::move(*e)); + } + + return { std::move(stops) }; +} + +template +optional>> convertBranches(type::Type type, + const Convertible& value, + Error& error) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + error = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + error = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + error = { "function must have at least one stop" }; + return {}; + } + + std::map> stops; + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + optional t = convert(arrayMember(stopValue, 0), error); + if (!t) { + return {}; + } + + optional> e = convertLiteral(type, arrayMember(stopValue, 1), error); + if (!e) { + return {}; + } + + stops.emplace(*t, std::move(*e)); + } + + return { std::move(stops) }; +} + +static optional convertBase(const Convertible& value, Error& error) { + auto baseValue = objectMember(value, "base"); + + if (!baseValue) { + return 1.0; + } + + auto base = toNumber(*baseValue); + if (!base) { + error = { "function base must be a number" }; + return {}; + } + + return *base; +} + +static std::unique_ptr step(type::Type type, std::unique_ptr input, std::map> stops) { + return std::make_unique(type, std::move(input), std::move(stops)); +} + +static std::unique_ptr interpolate(type::Type type, Interpolator interpolator, std::unique_ptr input, std::map> stops) { + ParsingContext ctx; + auto result = createInterpolate(type, std::move(interpolator), std::move(input), std::move(stops), ctx); + if (!result) { + assert(false); + return {}; + } + return std::move(*result); +} + +template +std::unique_ptr categorical(type::Type type, const std::string& property, std::map> branches) { + std::unordered_map> convertedBranches; + for (auto& b : branches) { + convertedBranches[b.first] = std::move(b.second); + } + return std::make_unique>(type, get(literal(property)), std::move(convertedBranches), error("replaced with default")); +} + +template <> +std::unique_ptr categorical(type::Type type, const std::string& property, std::map> branches) { + auto it = branches.find(true); + std::unique_ptr trueCase = it == branches.end() ? + error("replaced with default") : + std::move(it->second); + + it = branches.find(false); + std::unique_ptr falseCase = it == branches.end() ? + error("replaced with default") : + std::move(it->second); + + std::vector trueBranch; + trueBranch.emplace_back(get(literal(property)), std::move(trueCase)); + + return std::make_unique(type, std::move(trueBranch), std::move(falseCase)); +} + +static optional> convertIntervalFunction(type::Type type, + const Convertible& value, + Error& error, + std::unique_ptr input) { + auto stops = convertStops(type, value, error); + if (!stops) { + return {}; + } + return step(type, std::move(input), std::move(*stops)); +} + +static optional> convertExponentialFunction(type::Type type, + const Convertible& value, + Error& error, + std::unique_ptr input) { + auto stops = convertStops(type, value, error); + if (!stops) { + return {}; + } + auto base = convertBase(value, error); + if (!base) { + return {}; + } + return interpolate(type, exponential(*base), std::move(input), std::move(*stops)); +} + +static optional> convertCategoricalFunction(type::Type type, + const Convertible& value, + Error& err, + const std::string& property) { + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + err = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + err = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + err = { "function must have at least one stop" }; + return {}; + } + + const auto& first = arrayMember(*stopsValue, 0); + + if (!isArray(first)) { + err = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(first) != 2) { + err = { "function stop must have two elements" }; + return {}; + } + + if (toBool(arrayMember(first, 0))) { + auto branches = convertBranches(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + if (toNumber(arrayMember(first, 0))) { + auto branches = convertBranches(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + if (toString(arrayMember(first, 0))) { + auto branches = convertBranches(type, value, err); + if (!branches) { + return {}; + } + return categorical(type, property, std::move(*branches)); + } + + err = { "stop domain value must be a number, string, or boolean" }; + return {}; +} + +optional> convertCameraFunctionToExpression(type::Type type, + const Convertible& value, + Error& error) { + if (!isObject(value)) { + error = { "function must be an object" }; + return {}; + } + + switch (functionType(type, value)) { + case FunctionType::Interval: + return convertIntervalFunction(type, value, error, zoom()); + case FunctionType::Exponential: + return convertExponentialFunction(type, value, error, zoom()); + default: + error = { "unsupported function type" }; + return {}; + } +} + +optional> convertSourceFunctionToExpression(type::Type type, + const Convertible& value, + Error& error) { + if (!isObject(value)) { + error = { "function must be an object" }; + return {}; + } + + auto propertyValue = objectMember(value, "property"); + if (!propertyValue) { + error = { "function must specify property" }; + return {}; + } + + auto property = toString(*propertyValue); + if (!property) { + error = { "function property must be a string" }; + return {}; + } + + switch (functionType(type, value)) { + case FunctionType::Interval: + return convertIntervalFunction(type, value, error, number(get(literal(*property)))); + case FunctionType::Exponential: + return convertExponentialFunction(type, value, error, number(get(literal(*property)))); + case FunctionType::Categorical: + return convertCategoricalFunction(type, value, error, *property); + case FunctionType::Identity: + return type.match( + [&] (const type::StringType&) -> optional> { + return string(get(literal(*property))); + }, + [&] (const type::NumberType&) -> optional> { + return number(get(literal(*property))); + }, + [&] (const type::BooleanType&) -> optional> { + return boolean(get(literal(*property))); + }, + [&] (const type::ColorType&) -> optional> { + return toColor(get(literal(*property))); + }, + [&] (const type::Array& array) -> optional> { + return std::unique_ptr( + std::make_unique(array, get(literal(*property)))); + }, + [&] (const auto&) -> optional> { + assert(false); // No properties use this type. + return {}; + } + ); + default: + error = { "unsupported function type" }; + return {}; + } +} + +template +optional> composite(type::Type type, + const Convertible& value, + Error& error, + std::unique_ptr (*makeInnerExpression) (type::Type type, + double base, + const std::string& property, + std::map>)) { + auto propertyValue = objectMember(value, "property"); + if (!propertyValue) { + error = { "function must specify property" }; + return {}; + } + + auto base = convertBase(value, error); + if (!base) { + return {}; + } + + auto propertyString = toString(*propertyValue); + if (!propertyString) { + error = { "function property must be a string" }; + return {}; + } + + auto stopsValue = objectMember(value, "stops"); + + // Checked by caller. + assert(stopsValue); + assert(isArray(*stopsValue)); + + std::map>> map; + + for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { + const auto& stopValue = arrayMember(*stopsValue, i); + + if (!isArray(stopValue)) { + error = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(stopValue) != 2) { + error = { "function stop must have two elements" }; + return {}; + } + + const auto& stopInput = arrayMember(stopValue, 0); + + if (!isObject(stopInput)) { + error = { "stop input must be an object" }; + return {}; + } + + auto zoomValue = objectMember(stopInput, "zoom"); + if (!zoomValue) { + error = { "stop input must specify zoom" }; + return {}; + } + + auto sourceValue = objectMember(stopInput, "value"); + if (!sourceValue) { + error = { "stop input must specify value" }; + return {}; + } + + optional z = convert(*zoomValue, error); + if (!z) { + return {}; + } + + optional d = convert(*sourceValue, error); + if (!d) { + return {}; + } + + optional> r = convertLiteral(type, arrayMember(stopValue, 1), error); + if (!r) { + return {}; + } + + map[*z].emplace(*d, std::move(*r)); + } + + std::map> stops; + + for (auto& e : map) { + stops.emplace(e.first, makeInnerExpression(type, *base, *propertyString, std::move(e.second))); + } + + if (interpolatable(type)) { + return interpolate(type, linear(), zoom(), std::move(stops)); + } else { + return step(type, zoom(), std::move(stops)); + } +} + +optional> convertCompositeFunctionToExpression(type::Type type, + const Convertible& value, + Error& err) { + if (!isObject(value)) { + err = { "function must be an object" }; + return {}; + } + + auto stopsValue = objectMember(value, "stops"); + if (!stopsValue) { + err = { "function value must specify stops" }; + return {}; + } + + if (!isArray(*stopsValue)) { + err = { "function stops must be an array" }; + return {}; + } + + if (arrayLength(*stopsValue) == 0) { + err = { "function must have at least one stop" }; + return {}; + } + + const auto& first = arrayMember(*stopsValue, 0); + + if (!isArray(first)) { + err = { "function stop must be an array" }; + return {}; + } + + if (arrayLength(first) != 2) { + err = { "function stop must have two elements" }; + return {}; + } + + const auto& stop = arrayMember(first, 0); + + if (!isObject(stop)) { + err = { "stop must be an object" }; + return {}; + } + + auto sourceValue = objectMember(stop, "value"); + if (!sourceValue) { + err = { "stop must specify value" }; + return {}; + } + + if (toBool(*sourceValue)) { + switch (functionType(type, value)) { + case FunctionType::Categorical: + return composite(type, value, err, [] (type::Type type_, double, const std::string& property, std::map> stops) { + return categorical(type_, property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + if (toNumber(*sourceValue)) { + switch (functionType(type, value)) { + case FunctionType::Interval: + return composite(type, value, err, [] (type::Type type_, double, const std::string& property, std::map> stops) { + return step(type_, number(get(literal(property))), std::move(stops)); + }); + case FunctionType::Exponential: + return composite(type, value, err, [] (type::Type type_, double base, const std::string& property, std::map> stops) { + return interpolate(type_, exponential(base), number(get(literal(property))), std::move(stops)); + }); + case FunctionType::Categorical: + return composite(type, value, err, [] (type::Type type_, double, const std::string& property, std::map> stops) { + return categorical(type_, property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + if (toString(*sourceValue)) { + switch (functionType(type, value)) { + case FunctionType::Categorical: + return composite(type, value, err, [] (type::Type type_, double, const std::string& property, std::map> stops) { + return categorical(type_, property, std::move(stops)); + }); + default: + err = { "unsupported function type" }; + return {}; + } + } + + err = { "stop domain value must be a number, string, or boolean" }; + return {}; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp index 2298bdf8d3..5532e0a520 100644 --- a/src/mbgl/style/expression/dsl.cpp +++ b/src/mbgl/style/expression/dsl.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -28,6 +29,10 @@ static std::unique_ptr compound(const char* op, Args... args) { return std::move(*result); } +std::unique_ptr error(std::string message) { + return std::make_unique(std::move(message)); +} + std::unique_ptr literal(const char* value) { return literal(std::string(value)); } @@ -60,6 +65,10 @@ std::unique_ptr string(std::unique_ptr value) { return std::make_unique(type::String, vec(std::move(value))); } +std::unique_ptr boolean(std::unique_ptr value) { + return std::make_unique(type::Boolean, vec(std::move(value))); +} + std::unique_ptr toColor(const char* value) { return toColor(literal(value)); } diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp deleted file mode 100644 index dd179f5376..0000000000 --- a/src/mbgl/style/function/categorical_stops.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include - -#include - -namespace mbgl { -namespace style { - -optional categoricalValue(const Value& value) { - return value.match( - [] (bool t) { return optional(t); }, - [] (uint64_t t) { return optional(int64_t(t)); }, - [] (int64_t t) { return optional(t); }, - [] (double t) { return optional(int64_t(t)); }, - [] (const std::string& t) { return optional(t); }, - [] (const auto&) { return optional(); } - ); -} - -template -optional CategoricalStops::evaluate(const Value& value) const { - auto v = categoricalValue(value); - if (!v) { - return {}; - } - auto it = stops.find(*v); - return it == stops.end() ? optional() : it->second; -} - -template class CategoricalStops; -template class CategoricalStops; -template class CategoricalStops>; -template class CategoricalStops; -template class CategoricalStops; -template class CategoricalStops; -template class CategoricalStops; -template class CategoricalStops; - -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/function/convert.cpp b/src/mbgl/style/function/convert.cpp deleted file mode 100644 index a3b19f287b..0000000000 --- a/src/mbgl/style/function/convert.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include - -namespace mbgl { -namespace style { -namespace expression { - -std::unique_ptr Convert::fromIdentityFunction(const std::string& property, type::Type type) { - return type.match( - [&] (const type::StringType&) { - return makeGet(type::String, property); - }, - [&] (const type::NumberType&) { - return makeGet(type::Number, property); - }, - [&] (const type::BooleanType&) { - return makeGet(type::Boolean, property); - }, - [&] (const type::ColorType&) { - std::vector> args; - args.push_back(makeGet(type::String, property)); - return std::make_unique(type::Color, std::move(args)); - }, - [&] (const type::Array& arr) { - std::vector> getArgs; - getArgs.push_back(makeLiteral(property)); - ParsingContext ctx; - ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx); - assert(get); - assert(ctx.getErrors().size() == 0); - return std::make_unique(arr, std::move(*get)); - }, - [&] (const auto&) -> std::unique_ptr { - return makeLiteral(Null); - } - ); -} - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp deleted file mode 100644 index 0ac6fda846..0000000000 --- a/src/mbgl/style/function/identity_stops.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace style { - -template <> -optional IdentityStops::evaluate(const Value& value) const { - return numericValue(value); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return value.get(); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return Color::parse(value.get()); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return Enum::toEnum(value.get()); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return Enum::toEnum(value.get()); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return Enum::toEnum(value.get()); -} - -template <> -optional IdentityStops::evaluate(const Value& value) const { - if (!value.is()) { - return {}; - } - - return Enum::toEnum(value.get()); -} - -template <> -optional> IdentityStops>::evaluate(const Value& value) const { - if (!value.is>()) { - return {}; - } - - const auto& vector = value.get>(); - if (vector.size() != 2 || !numericValue(vector[0]) || !numericValue(vector[1])) { - return {}; - } - - std::array array {{ - *numericValue(vector[0]), - *numericValue(vector[1]) - }}; - return array; -} - -} // namespace style -} // namespace mbgl diff --git a/test/style/function/exponential_stops.test.cpp b/test/style/function/exponential_stops.test.cpp deleted file mode 100644 index 81438ec952..0000000000 --- a/test/style/function/exponential_stops.test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -#include - -using namespace mbgl; -using namespace mbgl::style; - -TEST(ExponentialStops, Empty) { - ExponentialStops stops; - EXPECT_FALSE(bool(stops.evaluate(0))); -} - -TEST(ExponentialStops, NonNumericInput) { - ExponentialStops stops(std::map {{0.0f, 0.0f}}); - EXPECT_FALSE(bool(stops.evaluate(Value(NullValue())))); - EXPECT_FALSE(bool(stops.evaluate(Value(false)))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::string())))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::vector())))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::unordered_map())))); -} diff --git a/test/style/function/interval_stops.test.cpp b/test/style/function/interval_stops.test.cpp deleted file mode 100644 index 8a5e74b8b6..0000000000 --- a/test/style/function/interval_stops.test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include - -#include - -using namespace mbgl; -using namespace mbgl::style; - -TEST(IntervalStops, Empty) { - IntervalStops stops; - EXPECT_FALSE(bool(stops.evaluate(0))); -} - -TEST(IntervalStops, NonNumericInput) { - IntervalStops stops(std::map {{0.0f, 0.0f}}); - EXPECT_FALSE(bool(stops.evaluate(Value(NullValue())))); - EXPECT_FALSE(bool(stops.evaluate(Value(false)))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::string())))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::vector())))); - EXPECT_FALSE(bool(stops.evaluate(Value(std::unordered_map())))); -} -- cgit v1.2.1