From cc2ab6806c3f58b46da8d252d3f21eda53d185a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 17 Aug 2018 15:38:47 -0700 Subject: [core] make style/conversion.hpp implementation private --- benchmark/function/camera_function.benchmark.cpp | 2 +- .../function/composite_function.benchmark.cpp | 2 +- benchmark/function/source_function.benchmark.cpp | 2 +- benchmark/parse/filter.benchmark.cpp | 2 +- cmake/core-files.cmake | 2 + include/mbgl/style/conversion.hpp | 290 +------------------- include/mbgl/style/conversion/constant.hpp | 35 +-- include/mbgl/style/conversion/coordinate.hpp | 1 + .../conversion/custom_geometry_source_options.hpp | 1 + include/mbgl/style/conversion/filter.hpp | 1 + include/mbgl/style/conversion/function.hpp | 22 +- include/mbgl/style/conversion/geojson.hpp | 3 +- include/mbgl/style/conversion/geojson_options.hpp | 3 +- include/mbgl/style/conversion/layer.hpp | 1 + include/mbgl/style/conversion/light.hpp | 1 + include/mbgl/style/conversion/position.hpp | 3 +- include/mbgl/style/conversion/property_value.hpp | 50 +--- include/mbgl/style/conversion/source.hpp | 3 +- include/mbgl/style/conversion/tileset.hpp | 1 + .../mbgl/style/conversion/transition_options.hpp | 1 + include/mbgl/style/conversion_impl.hpp | 302 +++++++++++++++++++++ include/mbgl/style/expression/assertion.hpp | 2 +- include/mbgl/style/expression/case.hpp | 2 +- include/mbgl/style/expression/coalesce.hpp | 2 +- .../mbgl/style/expression/compound_expression.hpp | 2 +- include/mbgl/style/expression/parsing_context.hpp | 1 + include/mbgl/style/layer.hpp | 1 + platform/android/config.cmake | 7 +- platform/android/src/native_map_view.cpp | 2 +- platform/android/src/style/android_conversion.hpp | 2 +- platform/android/src/style/conversion/filter.hpp | 2 +- .../android/src/style/conversion/latlngquad.hpp | 2 +- .../src/style/conversion/url_or_tileset.hpp | 2 +- platform/android/src/style/layers/layer.cpp | 2 +- .../android/src/style/sources/geojson_source.cpp | 2 +- .../android/src/style/sources/image_source.cpp | 2 +- platform/android/src/style/sources/source.cpp | 2 +- platform/darwin/src/MGLConversion.h | 2 +- platform/node/src/node_conversion.hpp | 2 +- platform/node/src/node_expression.hpp | 2 +- platform/qt/src/qmapboxgl.cpp | 2 +- platform/qt/src/qt_conversion.hpp | 2 +- .../style/conversion/color_ramp_property_value.cpp | 2 +- src/mbgl/style/conversion/constant.cpp | 56 ++++ src/mbgl/style/conversion/coordinate.cpp | 1 + .../conversion/custom_geometry_source_options.cpp | 1 + src/mbgl/style/conversion/filter.cpp | 3 +- src/mbgl/style/conversion/function.cpp | 68 +++++ src/mbgl/style/conversion/geojson.cpp | 1 + src/mbgl/style/conversion/geojson_options.cpp | 1 + src/mbgl/style/conversion/get_json_type.cpp | 1 + src/mbgl/style/conversion/json.hpp | 2 +- src/mbgl/style/conversion/layer.cpp | 1 + src/mbgl/style/conversion/light.cpp | 1 + src/mbgl/style/conversion/position.cpp | 1 + src/mbgl/style/conversion/property_value.cpp | 83 ++++++ src/mbgl/style/conversion/source.cpp | 1 + src/mbgl/style/conversion/tileset.cpp | 1 + src/mbgl/style/conversion/transition_options.cpp | 1 + src/mbgl/style/expression/array_assertion.cpp | 1 + src/mbgl/style/expression/assertion.cpp | 1 + src/mbgl/style/expression/at.cpp | 1 + src/mbgl/style/expression/boolean_operator.cpp | 1 + src/mbgl/style/expression/case.cpp | 1 + src/mbgl/style/expression/coalesce.cpp | 1 + src/mbgl/style/expression/coercion.cpp | 1 + src/mbgl/style/expression/collator_expression.cpp | 1 + src/mbgl/style/expression/comparison.cpp | 1 + src/mbgl/style/expression/compound_expression.cpp | 1 + src/mbgl/style/expression/interpolate.cpp | 1 + src/mbgl/style/expression/is_expression.cpp | 3 +- src/mbgl/style/expression/length.cpp | 1 + src/mbgl/style/expression/let.cpp | 1 + src/mbgl/style/expression/literal.cpp | 1 + src/mbgl/style/expression/match.cpp | 1 + src/mbgl/style/expression/parsing_context.cpp | 1 + src/mbgl/style/expression/step.cpp | 1 + src/mbgl/style/layer.cpp | 1 + src/mbgl/style/layers/background_layer.cpp | 2 +- src/mbgl/style/layers/circle_layer.cpp | 2 +- src/mbgl/style/layers/fill_extrusion_layer.cpp | 2 +- src/mbgl/style/layers/fill_layer.cpp | 2 +- src/mbgl/style/layers/heatmap_layer.cpp | 2 +- src/mbgl/style/layers/hillshade_layer.cpp | 2 +- src/mbgl/style/layers/layer.cpp.ejs | 2 +- src/mbgl/style/layers/line_layer.cpp | 2 +- src/mbgl/style/layers/raster_layer.cpp | 2 +- src/mbgl/style/layers/symbol_layer.cpp | 2 +- src/mbgl/style/parser.cpp | 2 +- src/mbgl/style/rapidjson_conversion.hpp | 2 +- test/style/conversion/light.test.cpp | 2 +- test/style/expression/expression.test.cpp | 2 +- 92 files changed, 616 insertions(+), 431 deletions(-) create mode 100644 include/mbgl/style/conversion_impl.hpp create mode 100644 src/mbgl/style/conversion/property_value.cpp diff --git a/benchmark/function/camera_function.benchmark.cpp b/benchmark/function/camera_function.benchmark.cpp index 51d2e22293..0ce7d7c763 100644 --- a/benchmark/function/camera_function.benchmark.cpp +++ b/benchmark/function/camera_function.benchmark.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/function/composite_function.benchmark.cpp b/benchmark/function/composite_function.benchmark.cpp index f16254641f..8064d548fa 100644 --- a/benchmark/function/composite_function.benchmark.cpp +++ b/benchmark/function/composite_function.benchmark.cpp @@ -2,10 +2,10 @@ #include -#include #include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/function/source_function.benchmark.cpp b/benchmark/function/source_function.benchmark.cpp index 2164b2a418..b75cc143d2 100644 --- a/benchmark/function/source_function.benchmark.cpp +++ b/benchmark/function/source_function.benchmark.cpp @@ -2,9 +2,9 @@ #include -#include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/parse/filter.benchmark.cpp b/benchmark/parse/filter.benchmark.cpp index 4e39237138..1ae2b0f2bc 100644 --- a/benchmark/parse/filter.benchmark.cpp +++ b/benchmark/parse/filter.benchmark.cpp @@ -1,9 +1,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 02335fef7a..2d0bd003c7 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -363,6 +363,7 @@ set(MBGL_CORE_FILES # style include/mbgl/style/color_ramp_property_value.hpp include/mbgl/style/conversion.hpp + include/mbgl/style/conversion_impl.hpp include/mbgl/style/filter.hpp include/mbgl/style/image.hpp include/mbgl/style/layer.hpp @@ -437,6 +438,7 @@ set(MBGL_CORE_FILES src/mbgl/style/conversion/layer.cpp src/mbgl/style/conversion/light.cpp src/mbgl/style/conversion/position.cpp + src/mbgl/style/conversion/property_value.cpp src/mbgl/style/conversion/source.cpp src/mbgl/style/conversion/stringify.hpp src/mbgl/style/conversion/tileset.cpp diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 71c2cec237..2c83d1561b 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -1,306 +1,26 @@ #pragma once -#include -#include -#include - #include namespace mbgl { namespace style { namespace conversion { -/* - The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by - the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain: - - * `std::unique_ptr` - * `std::unique_ptr` - * `Filter` - * `PropertyValue` - - A single template function serves as the public interface: - - template - optional convert(const Convertible& input, Error& error); - - Where `T` is one of the above types. If the conversion fails, the result is empty, and the - error parameter includes diagnostic text suitable for presentation to a library user. Otherwise, - a filled optional is returned. - - `Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that - can serve as input to the conversion algorithm. For instance, on macOS, we need to support - conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc. - On Qt, we need to support conversion from RapidJSON types and QVariant. - - We don't want to use traditional forms of polymorphism to accomplish this: - - * Compile time polymorphism using a template parameter for the actual value type leads to - excessive code bloat and long compile times. - * Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous - use of std::unique_ptr, unsuitable for this performance-sensitive code. - - Therefore, we're using a custom implementation of runtime polymorphism where we manually create and - dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible - underlying types inline on the stack, using `std::aligned_storage`. - - For a given underlying type T, an explicit specialization of `ConversionTraits` must be provided. This - specialization must provide the following static methods: - - * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null - - * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array - * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length - * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&` - - * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object - * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value: - * is true when evaluated in a boolean context iff the named member exists - * is convertable to a `V` or `V&` when dereferenced - * `eachMember(v, [] (const std::string&, const V&) -> optional {...})` -- called - only if `isObject(v)`; calls the provided lambda once for each key and value of the object; - short-circuits if any call returns an `Error` - - * `toBool(v)` -- returns `optional`, absence indicating `v` is not a JSON boolean - * `toNumber(v)` -- returns `optional`, absence indicating `v` is not a JSON number - * `toDouble(v)` -- returns `optional`, absence indicating `v` is not a JSON number - * `toString(v)` -- returns `optional`, absence indicating `v` is not a JSON string - * `toValue(v)` -- returns `optional`, a variant type, for generic conversion, - absence indicating `v` is not a boolean, number, or string. Numbers should be converted to - unsigned integer, signed integer, or floating point, in descending preference. - - In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for - `std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the - possible underlying types. (A static assert will fail if this is not the case.) - - `Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state; - you must not do anything with it except let it go out of scope. -*/ +// This is a forward-declaration only header intended to minimize dependencies and to improve +// compilation speed. In order to specialize implementations and get access to the actual +// implementation, include . struct Error { std::string message; }; template class ConversionTraits; -class Convertible { -public: - template - Convertible(T&& value) : vtable(vtableForType>()) { - static_assert(sizeof(Storage) >= sizeof(std::decay_t), "Storage must be large enough to hold value type"); - new (static_cast(&storage)) std::decay_t(std::forward(value)); - } - - Convertible(Convertible&& v) - : vtable(v.vtable) - { - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } - } - - ~Convertible() { - if (vtable) { - vtable->destroy(storage); - } - } - - Convertible& operator=(Convertible&& v) { - if (vtable) { - vtable->destroy(storage); - } - vtable = v.vtable; - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } - v.vtable = nullptr; - return *this; - } - - Convertible() = delete; - Convertible(const Convertible&) = delete; - Convertible& operator=(const Convertible&) = delete; - - friend inline bool isUndefined(const Convertible& v) { - assert(v.vtable); - return v.vtable->isUndefined(v.storage); - } - - friend inline bool isArray(const Convertible& v) { - assert(v.vtable); - return v.vtable->isArray(v.storage); - } - - friend inline std::size_t arrayLength(const Convertible& v) { - assert(v.vtable); - return v.vtable->arrayLength(v.storage); - } - - friend inline Convertible arrayMember(const Convertible& v, std::size_t i) { - assert(v.vtable); - return v.vtable->arrayMember(v.storage, i); - } - - friend inline bool isObject(const Convertible& v) { - assert(v.vtable); - return v.vtable->isObject(v.storage); - } - - friend inline optional objectMember(const Convertible& v, const char * name) { - assert(v.vtable); - return v.vtable->objectMember(v.storage, name); - } - - friend inline optional eachMember(const Convertible& v, const std::function (const std::string&, const Convertible&)>& fn) { - assert(v.vtable); - return v.vtable->eachMember(v.storage, fn); - } - - friend inline optional toBool(const Convertible& v) { - assert(v.vtable); - return v.vtable->toBool(v.storage); - } - - friend inline optional toNumber(const Convertible& v) { - assert(v.vtable); - return v.vtable->toNumber(v.storage); - } - - friend inline optional toDouble(const Convertible& v) { - assert(v.vtable); - return v.vtable->toDouble(v.storage); - } - - friend inline optional toString(const Convertible& v) { - assert(v.vtable); - return v.vtable->toString(v.storage); - } - - friend inline optional toValue(const Convertible& v) { - assert(v.vtable); - return v.vtable->toValue(v.storage); - } - - friend inline optional toGeoJSON(const Convertible& v, Error& error) { - assert(v.vtable); - return v.vtable->toGeoJSON(v.storage, error); - } - -private: -#if __ANDROID__ - // Android: JSValue* or mbgl::android::Value - using Storage = std::aligned_storage_t<32, 8>; -#elif __QT__ - // Qt: JSValue* or QVariant - using Storage = std::aligned_storage_t<32, 8>; -#else - // Node: JSValue* or v8::Local - // iOS/macOS: JSValue* or id - using Storage = std::aligned_storage_t<8, 8>; -#endif - - struct VTable { - void (*move) (Storage&& src, Storage& dest); - void (*destroy) (Storage&); - - bool (*isUndefined) (const Storage&); - - bool (*isArray) (const Storage&); - std::size_t (*arrayLength) (const Storage&); - Convertible (*arrayMember) (const Storage&, std::size_t); - - bool (*isObject) (const Storage&); - optional (*objectMember) (const Storage&, const char *); - optional (*eachMember) (const Storage&, const std::function (const std::string&, const Convertible&)>&); - - optional (*toBool) (const Storage&); - optional (*toNumber) (const Storage&); - optional (*toDouble) (const Storage&); - optional (*toString) (const Storage&); - optional (*toValue) (const Storage&); - - // https://github.com/mapbox/mapbox-gl-native/issues/5623 - optional (*toGeoJSON) (const Storage&, Error&); - }; - - // Extracted this function from the table below to work around a GCC bug with differing - // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 - template - static auto vtableEachMember(const Storage& s, const std::function(const std::string&, const Convertible&)>& fn) { - return ConversionTraits::eachMember(reinterpret_cast(s), [&](const std::string& k, T&& v) { - return fn(k, Convertible(std::move(v))); - }); - } - - template - static VTable* vtableForType() { - using Traits = ConversionTraits; - static VTable vtable = { - [] (Storage&& src, Storage& dest) { - auto srcValue = reinterpret_cast(src); - new (static_cast(&dest)) T(std::move(srcValue)); - srcValue.~T(); - }, - [] (Storage& s) { - reinterpret_cast(s).~T(); - }, - [] (const Storage& s) { - return Traits::isUndefined(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::isArray(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::arrayLength(reinterpret_cast(s)); - }, - [] (const Storage& s, std::size_t i) { - return Convertible(Traits::arrayMember(reinterpret_cast(s), i)); - }, - [] (const Storage& s) { - return Traits::isObject(reinterpret_cast(s)); - }, - [] (const Storage& s, const char * key) { - optional member = Traits::objectMember(reinterpret_cast(s), key); - if (member) { - return optional(Convertible(std::move(*member))); - } else { - return optional(); - } - }, - vtableEachMember, - [] (const Storage& s) { - return Traits::toBool(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toNumber(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toDouble(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toString(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toValue(reinterpret_cast(s)); - }, - [] (const Storage& s, Error& err) { - return Traits::toGeoJSON(reinterpret_cast(s), err); - } - }; - return &vtable; - } - - VTable* vtable; - Storage storage; -}; +class Convertible; template struct Converter; -template -optional convert(const Convertible& value, Error& error, Args&&...args) { - return Converter()(value, error, std::forward(args)...); -} - } // namespace conversion } // namespace style } // namespace mbgl + diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 7d74ec42ce..40657528c4 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -30,21 +31,7 @@ struct Converter { template struct Converter::value>> { - optional operator()(const Convertible& value, Error& error) const { - optional string = toString(value); - if (!string) { - error.message = "value must be a string"; - return nullopt; - } - - const auto result = Enum::toEnum(*string); - if (!result) { - error.message = "value must be a valid enumeration value"; - return nullopt; - } - - return *result; - } + optional operator()(const Convertible& value, Error& error) const; }; template <> @@ -54,23 +41,7 @@ struct Converter { template struct Converter> { - optional> operator()(const Convertible& value, Error& error) const { - if (!isArray(value) || arrayLength(value) != N) { - error.message = "value must be an array of " + util::toString(N) + " numbers"; - return nullopt; - } - - std::array result; - for (size_t i = 0; i < N; i++) { - optional n = toNumber(arrayMember(value, i)); - if (!n) { - error.message = "value must be an array of " + util::toString(N) + " numbers"; - return nullopt; - } - result[i] = *n; - } - return result; - } + optional> operator()(const Convertible& value, Error& error) const; }; template <> diff --git a/include/mbgl/style/conversion/coordinate.hpp b/include/mbgl/style/conversion/coordinate.hpp index e11db5e32f..1346ed738a 100644 --- a/include/mbgl/style/conversion/coordinate.hpp +++ b/include/mbgl/style/conversion/coordinate.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/custom_geometry_source_options.hpp b/include/mbgl/style/conversion/custom_geometry_source_options.hpp index f0f505e54f..090e5b6239 100644 --- a/include/mbgl/style/conversion/custom_geometry_source_options.hpp +++ b/include/mbgl/style/conversion/custom_geometry_source_options.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 9daf6ea7a4..2d7ad0afc7 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index 49825a3410..ba9acd7a3b 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include @@ -16,25 +16,7 @@ std::unique_ptr convertTokenStringToExpression(const std optional> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens); template -optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { - auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType(), value, error, convertTokens); - if (!expression) { - return nullopt; - } - - optional defaultValue; - - auto defaultValueValue = objectMember(value, "default"); - if (defaultValueValue) { - defaultValue = convert(*defaultValueValue, error); - if (!defaultValue) { - error.message = R"(wrong type for "default": )" + error.message; - return nullopt; - } - } - - return PropertyExpression(std::move(*expression), defaultValue); -} +optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens); } // namespace conversion } // namespace style diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp index 403c5f953b..90c1d64197 100644 --- a/include/mbgl/style/conversion/geojson.hpp +++ b/include/mbgl/style/conversion/geojson.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp index 3f625babb6..89511848dd 100644 --- a/include/mbgl/style/conversion/geojson_options.hpp +++ b/include/mbgl/style/conversion/geojson_options.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index 2df6c9e381..9cf019378b 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -2,6 +2,7 @@ #include #include +#include #include diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp index 289fca2e31..2f6f8628b8 100644 --- a/include/mbgl/style/conversion/light.hpp +++ b/include/mbgl/style/conversion/light.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp index 044c45862d..10db5c6ec1 100644 --- a/include/mbgl/style/conversion/position.hpp +++ b/include/mbgl/style/conversion/position.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index fa6752867b..f6f36db983 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -1,9 +1,9 @@ #pragma once #include -#include #include #include +#include #include #include #include @@ -16,53 +16,7 @@ namespace conversion { template struct Converter> { - optional> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const { - using namespace mbgl::style::expression; - - if (isUndefined(value)) { - return PropertyValue(); - } - - optional> expression; - - if (isExpression(value)) { - ParsingContext ctx(valueTypeToExpressionType()); - ParseResult parsed = ctx.parseLayerPropertyExpression(value); - if (!parsed) { - error.message = ctx.getCombinedErrors(); - return nullopt; - } - expression = PropertyExpression(std::move(*parsed)); - } else if (isObject(value)) { - expression = convertFunctionToExpression(value, error, convertTokens); - } else { - optional constant = convert(value, error); - if (!constant) { - return nullopt; - } - return convertTokens ? maybeConvertTokens(*constant) : PropertyValue(*constant); - } - - if (!expression) { - return nullopt; - } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) { - error.message = "data expressions not supported"; - return nullopt; - } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) { - return { std::move(*expression) }; - } else if ((*expression).getExpression().getKind() == Kind::Literal) { - optional constant = fromExpressionValue( - static_cast((*expression).getExpression()).getValue()); - if (!constant) { - return nullopt; - } - return PropertyValue(*constant); - } else { - assert(false); - error.message = "expected a literal expression"; - return nullopt; - } - } + optional> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const; template PropertyValue maybeConvertTokens(const S& t) const { diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index 2cf2e36da4..19bc1ce6b6 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include #include diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp index 1fb4acf70d..88661c358c 100644 --- a/include/mbgl/style/conversion/tileset.hpp +++ b/include/mbgl/style/conversion/tileset.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp index 0563f39ac3..a72d757d3c 100644 --- a/include/mbgl/style/conversion/transition_options.hpp +++ b/include/mbgl/style/conversion/transition_options.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp new file mode 100644 index 0000000000..27b2ee1917 --- /dev/null +++ b/include/mbgl/style/conversion_impl.hpp @@ -0,0 +1,302 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +/* + The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by + the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain: + + * `std::unique_ptr` + * `std::unique_ptr` + * `Filter` + * `PropertyValue` + + A single template function serves as the public interface: + + template + optional convert(const Convertible& input, Error& error); + + Where `T` is one of the above types. If the conversion fails, the result is empty, and the + error parameter includes diagnostic text suitable for presentation to a library user. Otherwise, + a filled optional is returned. + + `Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that + can serve as input to the conversion algorithm. For instance, on macOS, we need to support + conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc. + On Qt, we need to support conversion from RapidJSON types and QVariant. + + We don't want to use traditional forms of polymorphism to accomplish this: + + * Compile time polymorphism using a template parameter for the actual value type leads to + excessive code bloat and long compile times. + * Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous + use of std::unique_ptr, unsuitable for this performance-sensitive code. + + Therefore, we're using a custom implementation of runtime polymorphism where we manually create and + dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible + underlying types inline on the stack, using `std::aligned_storage`. + + For a given underlying type T, an explicit specialization of `ConversionTraits` must be provided. This + specialization must provide the following static methods: + + * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null + + * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array + * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length + * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&` + + * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object + * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value: + * is true when evaluated in a boolean context iff the named member exists + * is convertable to a `V` or `V&` when dereferenced + * `eachMember(v, [] (const std::string&, const V&) -> optional {...})` -- called + only if `isObject(v)`; calls the provided lambda once for each key and value of the object; + short-circuits if any call returns an `Error` + + * `toBool(v)` -- returns `optional`, absence indicating `v` is not a JSON boolean + * `toNumber(v)` -- returns `optional`, absence indicating `v` is not a JSON number + * `toDouble(v)` -- returns `optional`, absence indicating `v` is not a JSON number + * `toString(v)` -- returns `optional`, absence indicating `v` is not a JSON string + * `toValue(v)` -- returns `optional`, a variant type, for generic conversion, + absence indicating `v` is not a boolean, number, or string. Numbers should be converted to + unsigned integer, signed integer, or floating point, in descending preference. + + In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for + `std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the + possible underlying types. (A static assert will fail if this is not the case.) + + `Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state; + you must not do anything with it except let it go out of scope. +*/ + +template +class ConversionTraits; + +class Convertible { +public: + template + Convertible(T&& value) : vtable(vtableForType>()) { + static_assert(sizeof(Storage) >= sizeof(std::decay_t), "Storage must be large enough to hold value type"); + new (static_cast(&storage)) std::decay_t(std::forward(value)); + } + + Convertible(Convertible&& v) + : vtable(v.vtable) + { + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + } + + ~Convertible() { + if (vtable) { + vtable->destroy(storage); + } + } + + Convertible& operator=(Convertible&& v) { + if (vtable) { + vtable->destroy(storage); + } + vtable = v.vtable; + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + v.vtable = nullptr; + return *this; + } + + Convertible() = delete; + Convertible(const Convertible&) = delete; + Convertible& operator=(const Convertible&) = delete; + + friend inline bool isUndefined(const Convertible& v) { + assert(v.vtable); + return v.vtable->isUndefined(v.storage); + } + + friend inline bool isArray(const Convertible& v) { + assert(v.vtable); + return v.vtable->isArray(v.storage); + } + + friend inline std::size_t arrayLength(const Convertible& v) { + assert(v.vtable); + return v.vtable->arrayLength(v.storage); + } + + friend inline Convertible arrayMember(const Convertible& v, std::size_t i) { + assert(v.vtable); + return v.vtable->arrayMember(v.storage, i); + } + + friend inline bool isObject(const Convertible& v) { + assert(v.vtable); + return v.vtable->isObject(v.storage); + } + + friend inline optional objectMember(const Convertible& v, const char * name) { + assert(v.vtable); + return v.vtable->objectMember(v.storage, name); + } + + friend inline optional eachMember(const Convertible& v, const std::function (const std::string&, const Convertible&)>& fn) { + assert(v.vtable); + return v.vtable->eachMember(v.storage, fn); + } + + friend inline optional toBool(const Convertible& v) { + assert(v.vtable); + return v.vtable->toBool(v.storage); + } + + friend inline optional toNumber(const Convertible& v) { + assert(v.vtable); + return v.vtable->toNumber(v.storage); + } + + friend inline optional toDouble(const Convertible& v) { + assert(v.vtable); + return v.vtable->toDouble(v.storage); + } + + friend inline optional toString(const Convertible& v) { + assert(v.vtable); + return v.vtable->toString(v.storage); + } + + friend inline optional toValue(const Convertible& v) { + assert(v.vtable); + return v.vtable->toValue(v.storage); + } + + friend inline optional toGeoJSON(const Convertible& v, Error& error) { + assert(v.vtable); + return v.vtable->toGeoJSON(v.storage, error); + } + +private: +#if __ANDROID__ + // Android: JSValue* or mbgl::android::Value + using Storage = std::aligned_storage_t<32, 8>; +#elif __QT__ + // Qt: JSValue* or QVariant + using Storage = std::aligned_storage_t<32, 8>; +#else + // Node: JSValue* or v8::Local + // iOS/macOS: JSValue* or id + using Storage = std::aligned_storage_t<8, 8>; +#endif + + struct VTable { + void (*move) (Storage&& src, Storage& dest); + void (*destroy) (Storage&); + + bool (*isUndefined) (const Storage&); + + bool (*isArray) (const Storage&); + std::size_t (*arrayLength) (const Storage&); + Convertible (*arrayMember) (const Storage&, std::size_t); + + bool (*isObject) (const Storage&); + optional (*objectMember) (const Storage&, const char *); + optional (*eachMember) (const Storage&, const std::function (const std::string&, const Convertible&)>&); + + optional (*toBool) (const Storage&); + optional (*toNumber) (const Storage&); + optional (*toDouble) (const Storage&); + optional (*toString) (const Storage&); + optional (*toValue) (const Storage&); + + // https://github.com/mapbox/mapbox-gl-native/issues/5623 + optional (*toGeoJSON) (const Storage&, Error&); + }; + + // Extracted this function from the table below to work around a GCC bug with differing + // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 + template + static auto vtableEachMember(const Storage& s, const std::function(const std::string&, const Convertible&)>& fn) { + return ConversionTraits::eachMember(reinterpret_cast(s), [&](const std::string& k, T&& v) { + return fn(k, Convertible(std::move(v))); + }); + } + + template + static VTable* vtableForType() { + using Traits = ConversionTraits; + static VTable vtable = { + [] (Storage&& src, Storage& dest) { + auto srcValue = reinterpret_cast(src); + new (static_cast(&dest)) T(std::move(srcValue)); + srcValue.~T(); + }, + [] (Storage& s) { + reinterpret_cast(s).~T(); + }, + [] (const Storage& s) { + return Traits::isUndefined(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::isArray(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::arrayLength(reinterpret_cast(s)); + }, + [] (const Storage& s, std::size_t i) { + return Convertible(Traits::arrayMember(reinterpret_cast(s), i)); + }, + [] (const Storage& s) { + return Traits::isObject(reinterpret_cast(s)); + }, + [] (const Storage& s, const char * key) { + optional member = Traits::objectMember(reinterpret_cast(s), key); + if (member) { + return optional(Convertible(std::move(*member))); + } else { + return optional(); + } + }, + vtableEachMember, + [] (const Storage& s) { + return Traits::toBool(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toNumber(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toDouble(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toString(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toValue(reinterpret_cast(s)); + }, + [] (const Storage& s, Error& err) { + return Traits::toGeoJSON(reinterpret_cast(s), err); + } + }; + return &vtable; + } + + VTable* vtable; + Storage storage; +}; + +template +optional convert(const Convertible& value, Error& error, Args&&...args) { + return Converter()(value, error, std::forward(args)...); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 90da16b068..239cdf2ea6 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index 02dc3bc4c2..7cd007d3c7 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index cd60cee02e..c4216f234f 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index ef10dadb55..b54720a258 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -1,10 +1,10 @@ #pragma once #include -#include #include #include #include +#include #include #include diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp index c19974a4f7..66014e33d4 100644 --- a/include/mbgl/style/expression/parsing_context.hpp +++ b/include/mbgl/style/expression/parsing_context.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index e0f71d2689..3b7969ea79 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/platform/android/config.cmake b/platform/android/config.cmake index e76a447c88..be9d95ef0a 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -345,6 +345,11 @@ add_library(example-custom-layer SHARED platform/android/src/example_custom_layer.cpp ) +target_include_directories(example-custom-layer + PRIVATE include +) + target_link_libraries(example-custom-layer - PRIVATE mbgl-core + PRIVATE -llog + PRIVATE -lGLESv2 ) diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 8da44c10cb..8c76332b39 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -30,8 +30,8 @@ // Java -> C++ conversion #include "style/android_conversion.hpp" -#include #include +#include // C++ -> Java conversion #include "conversion/conversion.hpp" diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 510a9f8444..8559720b2f 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp index c154e88e7c..241c98713a 100644 --- a/platform/android/src/style/conversion/filter.hpp +++ b/platform/android/src/style/conversion/filter.hpp @@ -1,8 +1,8 @@ #pragma once #include "../android_conversion.hpp" -#include #include +#include #include diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp index 9d1a83e164..9588336855 100644 --- a/platform/android/src/style/conversion/latlngquad.hpp +++ b/platform/android/src/style/conversion/latlngquad.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include namespace mbgl { diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index 92c1182a63..d6bf86639c 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index c3ae9e40cd..6c08893411 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -18,10 +18,10 @@ #include // Java -> C++ conversion -#include #include #include #include +#include // C++ -> Java conversion #include "../conversion/property_value.hpp" diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 6d9ab9e22c..14067503f1 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -5,9 +5,9 @@ // Java -> C++ conversion #include "../android_conversion.hpp" #include "../conversion/filter.hpp" -#include #include #include +#include // C++ -> Java conversion #include "../../conversion/conversion.hpp" diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 249387ea51..278564485d 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -5,7 +5,7 @@ // C++ -> Java conversion #include "../../conversion/conversion.hpp" -#include +#include #include #include "../../bitmap.hpp" diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 8f14ebc43e..d2e2426c0b 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -7,8 +7,8 @@ #include // Java -> C++ conversion -#include #include +#include // C++ -> Java conversion #include "../conversion/property_value.hpp" diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index 92a6720e6a..9057ed7824 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,4 +1,4 @@ -#include +#include NS_ASSUME_NONNULL_BEGIN diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp index 7c5bbf4386..ea6652c5e2 100644 --- a/platform/node/src/node_conversion.hpp +++ b/platform/node/src/node_conversion.hpp @@ -8,8 +8,8 @@ #include #include -#include #include +#include namespace mbgl { namespace style { diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp index 05af217bde..a53f8c18db 100644 --- a/platform/node/src/node_expression.hpp +++ b/platform/node/src/node_expression.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 480174810c..d584012830 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -13,11 +13,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp index 19b0cb54fc..99a262be54 100644 --- a/platform/qt/src/qt_conversion.hpp +++ b/platform/qt/src/qt_conversion.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include diff --git a/src/mbgl/style/conversion/color_ramp_property_value.cpp b/src/mbgl/style/conversion/color_ramp_property_value.cpp index f29438b6a2..0da16c67ee 100644 --- a/src/mbgl/style/conversion/color_ramp_property_value.cpp +++ b/src/mbgl/style/conversion/color_ramp_property_value.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index d432b5f051..de4ab22269 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { @@ -31,6 +32,38 @@ optional Converter::operator()(const Convertible& valu return *converted; } +template +optional Converter::value>>::operator()(const Convertible& value, Error& error) const { + optional string = toString(value); + if (!string) { + error.message = "value must be a string"; + return nullopt; + } + + const auto result = Enum::toEnum(*string); + if (!result) { + error.message = "value must be a valid enumeration value"; + return nullopt; + } + + return *result; +} + +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; + optional Converter::operator()(const Convertible& value, Error& error) const { optional string = toString(value); if (!string) { @@ -47,6 +80,29 @@ optional Converter::operator()(const Convertible& value, Error& er return *color; } +template +optional> Converter>::operator()(const Convertible& value, Error& error) const { + if (!isArray(value) || arrayLength(value) != N) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + + std::array result; + for (size_t i = 0; i < N; i++) { + optional n = toNumber(arrayMember(value, i)); + if (!n) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + result[i] = *n; + } + return result; +} + +template optional> Converter>::operator()(const Convertible&, Error&) const; +template optional> Converter>::operator()(const Convertible&, Error&) const; +template optional> Converter>::operator()(const Convertible&, Error&) const; + optional> Converter>::operator()(const Convertible& value, Error& error) const { if (!isArray(value)) { error.message = "value must be an array"; diff --git a/src/mbgl/style/conversion/coordinate.cpp b/src/mbgl/style/conversion/coordinate.cpp index 20abd45e26..ee03bffb30 100644 --- a/src/mbgl/style/conversion/coordinate.cpp +++ b/src/mbgl/style/conversion/coordinate.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/custom_geometry_source_options.cpp b/src/mbgl/style/conversion/custom_geometry_source_options.cpp index 8983f9f479..491509c28f 100644 --- a/src/mbgl/style/conversion/custom_geometry_source_options.cpp +++ b/src/mbgl/style/conversion/custom_geometry_source_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp index 5114c61778..fc25ab0b0d 100644 --- a/src/mbgl/style/conversion/filter.cpp +++ b/src/mbgl/style/conversion/filter.cpp @@ -1,10 +1,11 @@ #include +#include #include -#include #include #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index 1cc49e483a..6aadaad3b3 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -70,6 +72,72 @@ std::unique_ptr convertTokenStringToExpression(const std::string& so } } +template +optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { + auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType(), value, error, convertTokens); + if (!expression) { + return nullopt; + } + + optional defaultValue; + + auto defaultValueValue = objectMember(value, "default"); + if (defaultValueValue) { + defaultValue = convert(*defaultValueValue, error); + if (!defaultValue) { + error.message = R"(wrong type for "default": )" + error.message; + return nullopt; + } + } + + return PropertyExpression(std::move(*expression), defaultValue); +} + +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); + // 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). diff --git a/src/mbgl/style/conversion/geojson.cpp b/src/mbgl/style/conversion/geojson.cpp index e39a1a80eb..c2d34c5491 100644 --- a/src/mbgl/style/conversion/geojson.cpp +++ b/src/mbgl/style/conversion/geojson.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp index 77340e5f1d..11bd7cc507 100644 --- a/src/mbgl/style/conversion/geojson_options.cpp +++ b/src/mbgl/style/conversion/geojson_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/get_json_type.cpp b/src/mbgl/style/conversion/get_json_type.cpp index cd3b4608b1..2e9d35a957 100644 --- a/src/mbgl/style/conversion/get_json_type.cpp +++ b/src/mbgl/style/conversion/get_json_type.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/conversion/json.hpp b/src/mbgl/style/conversion/json.hpp index a823f6d383..3a7bf2b557 100644 --- a/src/mbgl/style/conversion/json.hpp +++ b/src/mbgl/style/conversion/json.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp index d36ca494da..085d7ae4c6 100644 --- a/src/mbgl/style/conversion/layer.cpp +++ b/src/mbgl/style/conversion/layer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp index 7b96c89a1c..e8723216ee 100644 --- a/src/mbgl/style/conversion/light.cpp +++ b/src/mbgl/style/conversion/light.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/position.cpp b/src/mbgl/style/conversion/position.cpp index a19f57bff3..df6c868ee8 100644 --- a/src/mbgl/style/conversion/position.cpp +++ b/src/mbgl/style/conversion/position.cpp @@ -1,5 +1,6 @@ #include #include +#include #include diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp new file mode 100644 index 0000000000..8a93c24767 --- /dev/null +++ b/src/mbgl/style/conversion/property_value.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +optional> Converter>::operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const { + using namespace mbgl::style::expression; + + if (isUndefined(value)) { + return PropertyValue(); + } + + optional> expression; + + if (isExpression(value)) { + ParsingContext ctx(valueTypeToExpressionType()); + ParseResult parsed = ctx.parseLayerPropertyExpression(value); + if (!parsed) { + error.message = ctx.getCombinedErrors(); + return nullopt; + } + expression = PropertyExpression(std::move(*parsed)); + } else if (isObject(value)) { + expression = convertFunctionToExpression(value, error, convertTokens); + } else { + optional constant = convert(value, error); + if (!constant) { + return nullopt; + } + return convertTokens ? maybeConvertTokens(*constant) : PropertyValue(*constant); + } + + if (!expression) { + return nullopt; + } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) { + error.message = "data expressions not supported"; + return nullopt; + } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) { + return { std::move(*expression) }; + } else if ((*expression).getExpression().getKind() == Kind::Literal) { + optional constant = fromExpressionValue( + static_cast((*expression).getExpression()).getValue()); + if (!constant) { + return nullopt; + } + return PropertyValue(*constant); + } else { + assert(false); + error.message = "expected a literal expression"; + return nullopt; + } +} + +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/source.cpp b/src/mbgl/style/conversion/source.cpp index ce0cb24ce0..5ecbd3b474 100644 --- a/src/mbgl/style/conversion/source.cpp +++ b/src/mbgl/style/conversion/source.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index b566af0a18..40575838ea 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp index 924032a0c0..6e39dca24f 100644 --- a/src/mbgl/style/conversion/transition_options.cpp +++ b/src/mbgl/style/conversion/transition_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 4049301b0b..9df586bdc3 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 2434d7a2f8..7e93003ac3 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/at.cpp b/src/mbgl/style/expression/at.cpp index 725e5ddb51..648f247830 100644 --- a/src/mbgl/style/expression/at.cpp +++ b/src/mbgl/style/expression/at.cpp @@ -1,4 +1,5 @@ #include +#include #include diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp index 68e96129aa..fa472270ce 100644 --- a/src/mbgl/style/expression/boolean_operator.cpp +++ b/src/mbgl/style/expression/boolean_operator.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/case.cpp b/src/mbgl/style/expression/case.cpp index e885c0ce6b..0c2ff0d7cd 100644 --- a/src/mbgl/style/expression/case.cpp +++ b/src/mbgl/style/expression/case.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/coalesce.cpp b/src/mbgl/style/expression/coalesce.cpp index 0090f16009..cdbf452f7f 100644 --- a/src/mbgl/style/expression/coalesce.cpp +++ b/src/mbgl/style/expression/coalesce.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index f5a4d70f66..486658ddda 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/collator_expression.cpp b/src/mbgl/style/expression/collator_expression.cpp index b27eedbc76..07346633a2 100644 --- a/src/mbgl/style/expression/collator_expression.cpp +++ b/src/mbgl/style/expression/collator_expression.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/comparison.cpp b/src/mbgl/style/expression/comparison.cpp index 6179c3ce88..cdcdb5d59c 100644 --- a/src/mbgl/style/expression/comparison.cpp +++ b/src/mbgl/style/expression/comparison.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 4c476a3749..f8c2376cb3 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 54fbc6e1d7..8725e9e86d 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/is_expression.cpp b/src/mbgl/style/expression/is_expression.cpp index 77212f6a1e..acf074c25b 100644 --- a/src/mbgl/style/expression/is_expression.cpp +++ b/src/mbgl/style/expression/is_expression.cpp @@ -1,8 +1,7 @@ #include #include #include - -#include +#include #include diff --git a/src/mbgl/style/expression/length.cpp b/src/mbgl/style/expression/length.cpp index ad7a15675a..f1b58d7952 100644 --- a/src/mbgl/style/expression/length.cpp +++ b/src/mbgl/style/expression/length.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index 242a995b0b..592ceed58a 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 345a52de9b..c69341d298 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 4b4984811f..0f05001a97 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index b3f6b1acee..ef17caed33 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -24,6 +24,7 @@ #include #include +#include #include diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index a1ca0a702e..39b04c04a0 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp index 31ff5bf47a..e08b71e6b3 100644 --- a/src/mbgl/style/layer.cpp +++ b/src/mbgl/style/layer.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index e47b41daa8..f2e85ce7e7 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 1dae77547b..c301a83c9e 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index db90415daa..74cdb9abe6 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 2da131b6b2..bdfc000736 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index df00558135..a90aab7009 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index fb96c681cc..aed49f6441 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 4e80a7bf74..b5fb1a97a4 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,12 +8,12 @@ #include _layer.hpp> #include _layer_impl.hpp> #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index c744adad95..1b84c2d73e 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 45d3240833..7bd01c92e1 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 48af6b13aa..4ea138a7f5 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 0a90919f0b..114a666f08 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,12 +1,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp index 79bd9c928b..be335101e9 100644 --- a/src/mbgl/style/rapidjson_conversion.hpp +++ b/src/mbgl/style/rapidjson_conversion.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/test/style/conversion/light.test.cpp b/test/style/conversion/light.test.cpp index f111e40ff3..092c476277 100644 --- a/test/style/conversion/light.test.cpp +++ b/test/style/conversion/light.test.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include #include #include #include diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp index 0b46facf42..982a769b93 100644 --- a/test/style/expression/expression.test.cpp +++ b/test/style/expression/expression.test.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include -- cgit v1.2.1