summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/math/log2.hpp16
-rw-r--r--include/mbgl/storage/default_file_source.hpp15
-rw-r--r--include/mbgl/storage/offline.hpp38
-rw-r--r--include/mbgl/style/conversion.hpp290
-rw-r--r--include/mbgl/style/conversion/constant.hpp35
-rw-r--r--include/mbgl/style/conversion/coordinate.hpp1
-rw-r--r--include/mbgl/style/conversion/custom_geometry_source_options.hpp1
-rw-r--r--include/mbgl/style/conversion/filter.hpp1
-rw-r--r--include/mbgl/style/conversion/function.hpp22
-rw-r--r--include/mbgl/style/conversion/geojson.hpp3
-rw-r--r--include/mbgl/style/conversion/geojson_options.hpp3
-rw-r--r--include/mbgl/style/conversion/layer.hpp3
-rw-r--r--include/mbgl/style/conversion/light.hpp1
-rw-r--r--include/mbgl/style/conversion/position.hpp3
-rw-r--r--include/mbgl/style/conversion/property_value.hpp50
-rw-r--r--include/mbgl/style/conversion/source.hpp3
-rw-r--r--include/mbgl/style/conversion/tileset.hpp1
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp1
-rw-r--r--include/mbgl/style/conversion_impl.hpp302
-rw-r--r--include/mbgl/style/expression/assertion.hpp2
-rw-r--r--include/mbgl/style/expression/case.hpp2
-rw-r--r--include/mbgl/style/expression/coalesce.hpp2
-rw-r--r--include/mbgl/style/expression/compound_expression.hpp2
-rw-r--r--include/mbgl/style/expression/parsing_context.hpp1
-rw-r--r--include/mbgl/style/layer.hpp12
-rw-r--r--include/mbgl/style/layers/background_layer.hpp4
-rw-r--r--include/mbgl/style/layers/circle_layer.hpp4
-rw-r--r--include/mbgl/style/layers/custom_layer.hpp4
-rw-r--r--include/mbgl/style/layers/fill_extrusion_layer.hpp4
-rw-r--r--include/mbgl/style/layers/fill_layer.hpp4
-rw-r--r--include/mbgl/style/layers/heatmap_layer.hpp4
-rw-r--r--include/mbgl/style/layers/hillshade_layer.hpp4
-rw-r--r--include/mbgl/style/layers/layer.hpp.ejs4
-rw-r--r--include/mbgl/style/layers/line_layer.hpp4
-rw-r--r--include/mbgl/style/layers/raster_layer.hpp4
-rw-r--r--include/mbgl/style/layers/symbol_layer.hpp4
-rw-r--r--include/mbgl/style/source.hpp4
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp1
-rw-r--r--include/mbgl/util/expected.hpp16
-rw-r--r--include/mbgl/util/font_stack.hpp7
-rw-r--r--include/mbgl/util/peer.hpp111
-rw-r--r--include/mbgl/util/unique_any.hpp271
42 files changed, 577 insertions, 687 deletions
diff --git a/include/mbgl/math/log2.hpp b/include/mbgl/math/log2.hpp
index 6a1ba23ed9..3136ac22b4 100644
--- a/include/mbgl/math/log2.hpp
+++ b/include/mbgl/math/log2.hpp
@@ -2,6 +2,11 @@
#include <cmath>
#include <cstdint>
+#include <type_traits>
+
+#if defined(__ANDROID__)
+#include <android/api-level.h>
+#endif
namespace mbgl {
namespace util {
@@ -12,3 +17,14 @@ uint32_t ceil_log2(uint64_t x);
} // namespace util
} // namespace mbgl
+
+// log2 is not available on Android before API 18.
+#if defined(__ANDROID__) && defined(__GNUC__) && \
+ defined(__ANDROID_API__) && __ANDROID_API__ < 18
+
+template <typename T>
+typename std::enable_if_t<std::is_floating_point<T>::value, T> log2(T x) {
+ return ::log(x) / M_LN2;
+}
+
+#endif
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index b9c8de5052..e048d82af2 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -5,6 +5,7 @@
#include <mbgl/storage/offline.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/expected.hpp>
#include <vector>
#include <mutex>
@@ -55,8 +56,7 @@ public:
* callback, which will be executed on the database thread; it is the responsibility
* of the SDK bindings to re-execute a user-provided callback on the main thread.
*/
- void listOfflineRegions(std::function<void (std::exception_ptr,
- optional<std::vector<OfflineRegion>>)>);
+ void listOfflineRegions(std::function<void (expected<OfflineRegions, std::exception_ptr>)>);
/*
* Create an offline region in the database.
@@ -71,16 +71,14 @@ public:
*/
void createOfflineRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata,
- std::function<void (std::exception_ptr,
- optional<OfflineRegion>)>);
+ std::function<void (expected<OfflineRegion, std::exception_ptr>)>);
/*
* Update an offline region metadata in the database.
*/
void updateOfflineMetadata(const int64_t regionID,
const OfflineRegionMetadata& metadata,
- std::function<void (std::exception_ptr,
- optional<OfflineRegionMetadata>)>);
+ std::function<void (expected<OfflineRegionMetadata, std::exception_ptr>)>);
/*
* Register an observer to be notified when the state of the region changes.
*/
@@ -97,8 +95,9 @@ public:
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*/
- void getOfflineRegionStatus(OfflineRegion&, std::function<void (std::exception_ptr,
- optional<OfflineRegionStatus>)>) const;
+ void getOfflineRegionStatus(
+ OfflineRegion&,
+ std::function<void (expected<OfflineRegionStatus, std::exception_ptr>)>) const;
/*
* Remove an offline region from the database and perform any resources evictions
diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp
index ef4a499e83..b4e40cb5f3 100644
--- a/include/mbgl/storage/offline.hpp
+++ b/include/mbgl/storage/offline.hpp
@@ -1,8 +1,10 @@
#pragma once
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
#include <mbgl/util/range.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/variant.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/storage/response.hpp>
@@ -30,22 +32,40 @@ public:
OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float);
/* Private */
- std::vector<CanonicalTileID> tileCover(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const;
- uint64_t tileCount(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const;
const std::string styleURL;
const LatLngBounds bounds;
const double minZoom;
const double maxZoom;
const float pixelRatio;
-private:
- Range<uint8_t> coveringZoomRange(style::SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const;
};
/*
- * For the present, a tile pyramid is the only type of offline region. In the future,
- * other definition types will be available and this will be a variant type.
+ * An offline region defined by a style URL, geometry, zoom range, and
+ * device pixel ratio.
+ *
+ * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
+ *
+ * maxZoom may be ∞, in which case for each tile source, the region will include
+ * tiles from minZoom up to the maximum zoom level provided by that source.
+ *
+ * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
*/
-using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition;
+class OfflineGeometryRegionDefinition {
+public:
+ OfflineGeometryRegionDefinition(std::string styleURL, Geometry<double>, double minZoom, double maxZoom, float pixelRatio);
+
+ /* Private */
+ const std::string styleURL;
+ const Geometry<double> geometry;
+ const double minZoom;
+ const double maxZoom;
+ const float pixelRatio;
+};
+
+/*
+ * The offline region definition types supported
+ */
+using OfflineRegionDefinition = variant<OfflineTilePyramidRegionDefinition, OfflineGeometryRegionDefinition>;
/*
* The encoded format is private.
@@ -187,11 +207,11 @@ class OfflineRegion {
public:
// Move-only; not publicly constructible.
OfflineRegion(OfflineRegion&&);
- OfflineRegion& operator=(OfflineRegion&&);
~OfflineRegion();
OfflineRegion() = delete;
OfflineRegion(const OfflineRegion&) = delete;
+ OfflineRegion& operator=(OfflineRegion&&) = delete;
OfflineRegion& operator=(const OfflineRegion&) = delete;
int64_t getID() const;
@@ -210,4 +230,6 @@ private:
const OfflineRegionMetadata metadata;
};
+using OfflineRegions = std::vector<OfflineRegion>;
+
} // namespace mbgl
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 <mbgl/util/optional.hpp>
-#include <mbgl/util/feature.hpp>
-#include <mbgl/util/geojson.hpp>
-
#include <string>
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<Source>`
- * `std::unique_ptr<Layer>`
- * `Filter`
- * `PropertyValue<T>`
-
- A single template function serves as the public interface:
-
- template <class T>
- optional<T> 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<T>` 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<Error> {...})` -- 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<bool>`, absence indicating `v` is not a JSON boolean
- * `toNumber(v)` -- returns `optional<float>`, absence indicating `v` is not a JSON number
- * `toDouble(v)` -- returns `optional<double>`, absence indicating `v` is not a JSON number
- * `toString(v)` -- returns `optional<std::string>`, absence indicating `v` is not a JSON string
- * `toValue(v)` -- returns `optional<Value>`, 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 <mbgl/style/conversion_impl.hpp>.
struct Error { std::string message; };
template <typename T>
class ConversionTraits;
-class Convertible {
-public:
- template <typename T>
- Convertible(T&& value) : vtable(vtableForType<std::decay_t<T>>()) {
- static_assert(sizeof(Storage) >= sizeof(std::decay_t<T>), "Storage must be large enough to hold value type");
- new (static_cast<void*>(&storage)) std::decay_t<T>(std::forward<T>(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<Convertible> objectMember(const Convertible& v, const char * name) {
- assert(v.vtable);
- return v.vtable->objectMember(v.storage, name);
- }
-
- friend inline optional<Error> eachMember(const Convertible& v, const std::function<optional<Error> (const std::string&, const Convertible&)>& fn) {
- assert(v.vtable);
- return v.vtable->eachMember(v.storage, fn);
- }
-
- friend inline optional<bool> toBool(const Convertible& v) {
- assert(v.vtable);
- return v.vtable->toBool(v.storage);
- }
-
- friend inline optional<float> toNumber(const Convertible& v) {
- assert(v.vtable);
- return v.vtable->toNumber(v.storage);
- }
-
- friend inline optional<double> toDouble(const Convertible& v) {
- assert(v.vtable);
- return v.vtable->toDouble(v.storage);
- }
-
- friend inline optional<std::string> toString(const Convertible& v) {
- assert(v.vtable);
- return v.vtable->toString(v.storage);
- }
-
- friend inline optional<Value> toValue(const Convertible& v) {
- assert(v.vtable);
- return v.vtable->toValue(v.storage);
- }
-
- friend inline optional<GeoJSON> 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<v8::Value>
- // 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<Convertible> (*objectMember) (const Storage&, const char *);
- optional<Error> (*eachMember) (const Storage&, const std::function<optional<Error> (const std::string&, const Convertible&)>&);
-
- optional<bool> (*toBool) (const Storage&);
- optional<float> (*toNumber) (const Storage&);
- optional<double> (*toDouble) (const Storage&);
- optional<std::string> (*toString) (const Storage&);
- optional<Value> (*toValue) (const Storage&);
-
- // https://github.com/mapbox/mapbox-gl-native/issues/5623
- optional<GeoJSON> (*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 <typename T>
- static auto vtableEachMember(const Storage& s, const std::function<optional<Error>(const std::string&, const Convertible&)>& fn) {
- return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
- return fn(k, Convertible(std::move(v)));
- });
- }
-
- template <typename T>
- static VTable* vtableForType() {
- using Traits = ConversionTraits<T>;
- static VTable vtable = {
- [] (Storage&& src, Storage& dest) {
- auto srcValue = reinterpret_cast<T&&>(src);
- new (static_cast<void*>(&dest)) T(std::move(srcValue));
- srcValue.~T();
- },
- [] (Storage& s) {
- reinterpret_cast<T&>(s).~T();
- },
- [] (const Storage& s) {
- return Traits::isUndefined(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::isArray(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::arrayLength(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s, std::size_t i) {
- return Convertible(Traits::arrayMember(reinterpret_cast<const T&>(s), i));
- },
- [] (const Storage& s) {
- return Traits::isObject(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s, const char * key) {
- optional<T> member = Traits::objectMember(reinterpret_cast<const T&>(s), key);
- if (member) {
- return optional<Convertible>(Convertible(std::move(*member)));
- } else {
- return optional<Convertible>();
- }
- },
- vtableEachMember<T>,
- [] (const Storage& s) {
- return Traits::toBool(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::toNumber(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::toDouble(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::toString(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s) {
- return Traits::toValue(reinterpret_cast<const T&>(s));
- },
- [] (const Storage& s, Error& err) {
- return Traits::toGeoJSON(reinterpret_cast<const T&>(s), err);
- }
- };
- return &vtable;
- }
-
- VTable* vtable;
- Storage storage;
-};
+class Convertible;
template <class T, class Enable = void>
struct Converter;
-template <class T, class...Args>
-optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
- return Converter<T>()(value, error, std::forward<Args>(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 <mbgl/style/conversion.hpp>
+#include <mbgl/style/types.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/util/string.hpp>
@@ -30,21 +31,7 @@ struct Converter<std::string> {
template <class T>
struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
- optional<T> operator()(const Convertible& value, Error& error) const {
- optional<std::string> string = toString(value);
- if (!string) {
- error.message = "value must be a string";
- return nullopt;
- }
-
- const auto result = Enum<T>::toEnum(*string);
- if (!result) {
- error.message = "value must be a valid enumeration value";
- return nullopt;
- }
-
- return *result;
- }
+ optional<T> operator()(const Convertible& value, Error& error) const;
};
template <>
@@ -54,23 +41,7 @@ struct Converter<Color> {
template <size_t N>
struct Converter<std::array<float, N>> {
- optional<std::array<float, N>> 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<float, N> result;
- for (size_t i = 0; i < N; i++) {
- optional<float> 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<std::array<float, N>> 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 <mbgl/style/conversion.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/conversion.hpp>
#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/filter.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/property_expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/value.hpp>
@@ -16,25 +16,7 @@ std::unique_ptr<expression::Expression> convertTokenStringToExpression(const std
optional<std::unique_ptr<expression::Expression>> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens);
template <class T>
-optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) {
- auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error, convertTokens);
- if (!expression) {
- return nullopt;
- }
-
- optional<T> defaultValue;
-
- auto defaultValueValue = objectMember(value, "default");
- if (defaultValueValue) {
- defaultValue = convert<T>(*defaultValueValue, error);
- if (!defaultValue) {
- error.message = R"(wrong type for "default": )" + error.message;
- return nullopt;
- }
- }
-
- return PropertyExpression<T>(std::move(*expression), defaultValue);
-}
+optional<PropertyExpression<T>> 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 <mbgl/style/conversion.hpp>
#include <mbgl/util/geojson.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/conversion.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp
index 1c0e2e2f07..9cf019378b 100644
--- a/include/mbgl/style/conversion/layer.hpp
+++ b/include/mbgl/style/conversion/layer.hpp
@@ -2,6 +2,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
@@ -15,8 +16,6 @@ public:
optional<std::unique_ptr<Layer>> operator()(const Convertible& value, Error& error) const;
};
-optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const Convertible& value);
-optional<Error> setPaintProperty(Layer& layer, const std::string& name, const Convertible& value);
optional<Error> setPaintProperties(Layer& layer, const Convertible& value);
} // namespace conversion
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 <mbgl/style/light.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/conversion.hpp>
#include <mbgl/style/position.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/property_value.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/function.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/is_expression.hpp>
@@ -16,53 +16,7 @@ namespace conversion {
template <class T>
struct Converter<PropertyValue<T>> {
- optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const {
- using namespace mbgl::style::expression;
-
- if (isUndefined(value)) {
- return PropertyValue<T>();
- }
-
- optional<PropertyExpression<T>> expression;
-
- if (isExpression(value)) {
- ParsingContext ctx(valueTypeToExpressionType<T>());
- ParseResult parsed = ctx.parseLayerPropertyExpression(value);
- if (!parsed) {
- error.message = ctx.getCombinedErrors();
- return nullopt;
- }
- expression = PropertyExpression<T>(std::move(*parsed));
- } else if (isObject(value)) {
- expression = convertFunctionToExpression<T>(value, error, convertTokens);
- } else {
- optional<T> constant = convert<T>(value, error);
- if (!constant) {
- return nullopt;
- }
- return convertTokens ? maybeConvertTokens(*constant) : PropertyValue<T>(*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<T> constant = fromExpressionValue<T>(
- static_cast<const Literal&>((*expression).getExpression()).getValue());
- if (!constant) {
- return nullopt;
- }
- return PropertyValue<T>(*constant);
- } else {
- assert(false);
- error.message = "expected a literal expression";
- return nullopt;
- }
- }
+ optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const;
template <class S>
PropertyValue<T> 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 <mbgl/style/conversion.hpp>
#include <mbgl/style/source.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
#include <memory>
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 <mbgl/util/tileset.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/transition_options.hpp>
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
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 <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/geojson.hpp>
+
+#include <string>
+
+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<Source>`
+ * `std::unique_ptr<Layer>`
+ * `Filter`
+ * `PropertyValue<T>`
+
+ A single template function serves as the public interface:
+
+ template <class T>
+ optional<T> 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<T>` 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<Error> {...})` -- 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<bool>`, absence indicating `v` is not a JSON boolean
+ * `toNumber(v)` -- returns `optional<float>`, absence indicating `v` is not a JSON number
+ * `toDouble(v)` -- returns `optional<double>`, absence indicating `v` is not a JSON number
+ * `toString(v)` -- returns `optional<std::string>`, absence indicating `v` is not a JSON string
+ * `toValue(v)` -- returns `optional<Value>`, 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 <typename T>
+class ConversionTraits;
+
+class Convertible {
+public:
+ template <typename T>
+ Convertible(T&& value) : vtable(vtableForType<std::decay_t<T>>()) {
+ static_assert(sizeof(Storage) >= sizeof(std::decay_t<T>), "Storage must be large enough to hold value type");
+ new (static_cast<void*>(&storage)) std::decay_t<T>(std::forward<T>(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<Convertible> objectMember(const Convertible& v, const char * name) {
+ assert(v.vtable);
+ return v.vtable->objectMember(v.storage, name);
+ }
+
+ friend inline optional<Error> eachMember(const Convertible& v, const std::function<optional<Error> (const std::string&, const Convertible&)>& fn) {
+ assert(v.vtable);
+ return v.vtable->eachMember(v.storage, fn);
+ }
+
+ friend inline optional<bool> toBool(const Convertible& v) {
+ assert(v.vtable);
+ return v.vtable->toBool(v.storage);
+ }
+
+ friend inline optional<float> toNumber(const Convertible& v) {
+ assert(v.vtable);
+ return v.vtable->toNumber(v.storage);
+ }
+
+ friend inline optional<double> toDouble(const Convertible& v) {
+ assert(v.vtable);
+ return v.vtable->toDouble(v.storage);
+ }
+
+ friend inline optional<std::string> toString(const Convertible& v) {
+ assert(v.vtable);
+ return v.vtable->toString(v.storage);
+ }
+
+ friend inline optional<Value> toValue(const Convertible& v) {
+ assert(v.vtable);
+ return v.vtable->toValue(v.storage);
+ }
+
+ friend inline optional<GeoJSON> 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<v8::Value>
+ // 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<Convertible> (*objectMember) (const Storage&, const char *);
+ optional<Error> (*eachMember) (const Storage&, const std::function<optional<Error> (const std::string&, const Convertible&)>&);
+
+ optional<bool> (*toBool) (const Storage&);
+ optional<float> (*toNumber) (const Storage&);
+ optional<double> (*toDouble) (const Storage&);
+ optional<std::string> (*toString) (const Storage&);
+ optional<Value> (*toValue) (const Storage&);
+
+ // https://github.com/mapbox/mapbox-gl-native/issues/5623
+ optional<GeoJSON> (*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 <typename T>
+ static auto vtableEachMember(const Storage& s, const std::function<optional<Error>(const std::string&, const Convertible&)>& fn) {
+ return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
+ return fn(k, Convertible(std::move(v)));
+ });
+ }
+
+ template <typename T>
+ static VTable* vtableForType() {
+ using Traits = ConversionTraits<T>;
+ static VTable vtable = {
+ [] (Storage&& src, Storage& dest) {
+ auto srcValue = reinterpret_cast<T&&>(src);
+ new (static_cast<void*>(&dest)) T(std::move(srcValue));
+ srcValue.~T();
+ },
+ [] (Storage& s) {
+ reinterpret_cast<T&>(s).~T();
+ },
+ [] (const Storage& s) {
+ return Traits::isUndefined(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::isArray(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::arrayLength(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s, std::size_t i) {
+ return Convertible(Traits::arrayMember(reinterpret_cast<const T&>(s), i));
+ },
+ [] (const Storage& s) {
+ return Traits::isObject(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s, const char * key) {
+ optional<T> member = Traits::objectMember(reinterpret_cast<const T&>(s), key);
+ if (member) {
+ return optional<Convertible>(Convertible(std::move(*member)));
+ } else {
+ return optional<Convertible>();
+ }
+ },
+ vtableEachMember<T>,
+ [] (const Storage& s) {
+ return Traits::toBool(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::toNumber(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::toDouble(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::toString(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s) {
+ return Traits::toValue(reinterpret_cast<const T&>(s));
+ },
+ [] (const Storage& s, Error& err) {
+ return Traits::toGeoJSON(reinterpret_cast<const T&>(s), err);
+ }
+ };
+ return &vtable;
+ }
+
+ VTable* vtable;
+ Storage storage;
+};
+
+template <class T, class...Args>
+optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
+ return Converter<T>()(value, error, std::forward<Args>(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 <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
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 <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
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 <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
+#include <mbgl/style/conversion.hpp>
#include <memory>
#include <map>
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 <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/value.hpp>
+#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
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 <iterator>
#include <map>
+#include <unordered_map>
#include <string>
#include <vector>
#include <memory>
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index 12494f5387..3b7969ea79 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -1,10 +1,12 @@
#pragma once
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/unique_any.hpp>
+#include <mbgl/util/peer.hpp>
#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/optional.hpp>
#include <mbgl/style/layer_type.hpp>
#include <mbgl/style/types.hpp>
+#include <mbgl/style/conversion.hpp>
#include <cassert>
#include <memory>
@@ -98,7 +100,6 @@ public:
return std::forward<V>(visitor)(*as<HeatmapLayer>());
}
-
// Not reachable, but placate GCC.
assert(false);
throw new std::runtime_error("unknown layer type");
@@ -117,6 +118,11 @@ public:
virtual void setMinZoom(float) = 0;
virtual void setMaxZoom(float) = 0;
+ // Dynamic properties
+ virtual optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) = 0;
+ virtual optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) = 0;
+ optional<conversion::Error> setVisibility(const conversion::Convertible& value);
+
// Private implementation
class Impl;
Immutable<Impl> baseImpl;
@@ -132,7 +138,7 @@ public:
// For use in SDK bindings, which store a reference to a platform-native peer
// object here, so that separately-obtained references to this object share
// identical platform-native peers.
- util::unique_any peer;
+ util::peer peer;
};
} // namespace style
diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp
index eab2681fec..76230df12c 100644
--- a/include/mbgl/style/layers/background_layer.hpp
+++ b/include/mbgl/style/layers/background_layer.hpp
@@ -25,6 +25,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<Color> getDefaultBackgroundColor();
diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp
index 89ef926221..cde691c893 100644
--- a/include/mbgl/style/layers/circle_layer.hpp
+++ b/include/mbgl/style/layers/circle_layer.hpp
@@ -33,6 +33,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<float> getDefaultCircleRadius();
diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp
index fbe3a4a6c2..4b4c770489 100644
--- a/include/mbgl/style/layers/custom_layer.hpp
+++ b/include/mbgl/style/layers/custom_layer.hpp
@@ -75,6 +75,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Private implementation
class Impl;
diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp
index 742bac8c7e..e72fcade61 100644
--- a/include/mbgl/style/layers/fill_extrusion_layer.hpp
+++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp
@@ -33,6 +33,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<float> getDefaultFillExtrusionOpacity();
diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp
index d0b2a25bfe..430d7a011f 100644
--- a/include/mbgl/style/layers/fill_layer.hpp
+++ b/include/mbgl/style/layers/fill_layer.hpp
@@ -33,6 +33,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<bool> getDefaultFillAntialias();
diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp
index 53fd24aa6c..fd0051f44c 100644
--- a/include/mbgl/style/layers/heatmap_layer.hpp
+++ b/include/mbgl/style/layers/heatmap_layer.hpp
@@ -34,6 +34,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<float> getDefaultHeatmapRadius();
diff --git a/include/mbgl/style/layers/hillshade_layer.hpp b/include/mbgl/style/layers/hillshade_layer.hpp
index 214576b120..89d0ae686f 100644
--- a/include/mbgl/style/layers/hillshade_layer.hpp
+++ b/include/mbgl/style/layers/hillshade_layer.hpp
@@ -28,6 +28,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<float> getDefaultHillshadeIlluminationDirection();
diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs
index 9d52973af4..db7052387c 100644
--- a/include/mbgl/style/layers/layer.hpp.ejs
+++ b/include/mbgl/style/layers/layer.hpp.ejs
@@ -53,6 +53,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
<% if (layoutProperties.length) { -%>
// Layout properties
diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp
index 26e3b81fc9..fe4cd7c0d1 100644
--- a/include/mbgl/style/layers/line_layer.hpp
+++ b/include/mbgl/style/layers/line_layer.hpp
@@ -35,6 +35,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Layout properties
static PropertyValue<LineCapType> getDefaultLineCap();
diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp
index c133c23484..fcc35412a0 100644
--- a/include/mbgl/style/layers/raster_layer.hpp
+++ b/include/mbgl/style/layers/raster_layer.hpp
@@ -28,6 +28,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Paint properties
static PropertyValue<float> getDefaultRasterOpacity();
diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp
index 8c0b45d796..fa0b0c4e4e 100644
--- a/include/mbgl/style/layers/symbol_layer.hpp
+++ b/include/mbgl/style/layers/symbol_layer.hpp
@@ -35,6 +35,10 @@ public:
void setMinZoom(float) final;
void setMaxZoom(float) final;
+ // Dynamic properties
+ optional<conversion::Error> setLayoutProperty(const std::string& name, const conversion::Convertible& value) final;
+ optional<conversion::Error> setPaintProperty(const std::string& name, const conversion::Convertible& value) final;
+
// Layout properties
static PropertyValue<SymbolPlacementType> getDefaultSymbolPlacement();
diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp
index 2f2838ade8..dc3a8d73fb 100644
--- a/include/mbgl/style/source.hpp
+++ b/include/mbgl/style/source.hpp
@@ -2,7 +2,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/util/unique_any.hpp>
+#include <mbgl/util/peer.hpp>
#include <mbgl/util/immutable.hpp>
#include <mbgl/style/types.hpp>
@@ -77,7 +77,7 @@ public:
// For use in SDK bindings, which store a reference to a platform-native peer
// object here, so that separately-obtained references to this object share
// identical platform-native peers.
- util::unique_any peer;
+ util::peer peer;
};
} // namespace style
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
index 372e7c7a78..a03b910279 100644
--- a/include/mbgl/style/sources/geojson_source.hpp
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -18,6 +18,7 @@ struct GeoJSONOptions {
uint16_t tileSize = util::tileSize;
uint16_t buffer = 128;
double tolerance = 0.375;
+ bool lineMetrics = false;
// Supercluster options
bool cluster = false;
diff --git a/include/mbgl/util/expected.hpp b/include/mbgl/util/expected.hpp
new file mode 100644
index 0000000000..a45f071065
--- /dev/null
+++ b/include/mbgl/util/expected.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include <expected.hpp>
+#pragma GCC diagnostic pop
+
+namespace mbgl {
+
+template <class T, class E>
+using expected = nonstd::expected<T, E>;
+
+template <class E>
+using unexpected = nonstd::unexpected_type<E>;
+
+} // namespace mbgl
diff --git a/include/mbgl/util/font_stack.hpp b/include/mbgl/util/font_stack.hpp
index d0b431e9ea..ace60a4ba6 100644
--- a/include/mbgl/util/font_stack.hpp
+++ b/include/mbgl/util/font_stack.hpp
@@ -1,7 +1,11 @@
#pragma once
+#include <mbgl/util/immutable.hpp>
+#include <mbgl/style/layer.hpp>
+
#include <string>
#include <vector>
+#include <set>
namespace mbgl {
@@ -14,4 +18,7 @@ struct FontStackHash {
std::size_t operator()(const FontStack&) const;
};
+// Statically evaluate layer properties to determine what font stacks are used.
+std::set<FontStack> fontStacks(const std::vector<Immutable<style::Layer::Impl>>&);
+
} // namespace mbgl
diff --git a/include/mbgl/util/peer.hpp b/include/mbgl/util/peer.hpp
new file mode 100644
index 0000000000..a4abea0e88
--- /dev/null
+++ b/include/mbgl/util/peer.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <type_traits>
+#include <utility>
+
+namespace mbgl {
+namespace util {
+
+class peer {
+public:
+ peer() = default;
+ peer(const peer&) = delete;
+
+ peer(peer&& other)
+ : vtable(other.vtable)
+ {
+ if (vtable) {
+ vtable->move(other.storage, storage);
+ }
+ other.vtable = nullptr;
+ }
+
+ template <class T>
+ peer(T&& value) {
+ using _Vt = std::decay_t<T>;
+ vtable = get_vtable<_Vt>();
+ new (&storage) _Vt(std::forward<T>(value));
+ }
+
+ ~peer() {
+ reset();
+ }
+
+ peer& operator=(peer&& rhs) {
+ peer(std::move(rhs)).swap(*this);
+ return *this;
+ }
+
+ void reset() {
+ if (vtable) {
+ vtable->destroy(storage);
+ vtable = nullptr;
+ }
+ }
+
+ void swap(peer& rhs) {
+ if (this == &rhs) {
+ return;
+ } else {
+ peer tmp(std::move(rhs));
+ rhs.vtable = vtable;
+ if (rhs.vtable) {
+ rhs.vtable->move(storage, rhs.storage);
+ }
+ vtable = tmp.vtable;
+ if (vtable) {
+ vtable->move(tmp.storage, storage);
+ }
+ }
+ }
+
+ bool has_value() const {
+ return vtable != nullptr;
+ }
+
+ template <class T>
+ T& get() {
+ return reinterpret_cast<T&>(storage);
+ }
+
+ template <class T>
+ T&& take() {
+ reset();
+ return std::move(get<T>());
+ }
+
+private:
+ using storage_t = std::aligned_storage_t<2*sizeof(void*), alignof(void*)>;
+
+ struct vtable {
+ virtual ~vtable() = default;
+ virtual void move(storage_t&, storage_t&) = 0;
+ virtual void destroy(storage_t&) = 0;
+ };
+
+ template <class T>
+ struct vtable_impl : public vtable {
+ static_assert(sizeof(T) <= sizeof(storage_t), "peer object is too big");
+
+ void move(storage_t& src, storage_t& dst) override {
+ new (&dst) T(std::move(reinterpret_cast<T&>(src)));
+ destroy(src);
+ }
+
+ void destroy(storage_t& s) override {
+ reinterpret_cast<T&>(s).~T();
+ }
+ };
+
+ template <class T>
+ static vtable* get_vtable() {
+ static vtable_impl<T> vtable;
+ return &vtable;
+ }
+
+ vtable* vtable = nullptr;
+ storage_t storage;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/include/mbgl/util/unique_any.hpp b/include/mbgl/util/unique_any.hpp
deleted file mode 100644
index c7dc8b38ea..0000000000
--- a/include/mbgl/util/unique_any.hpp
+++ /dev/null
@@ -1,271 +0,0 @@
-#pragma once
-
-#include <typeinfo>
-#include <type_traits>
-#include <stdexcept>
-namespace mbgl {
-namespace util {
-
-class bad_any_cast : public std::bad_cast {
-public:
- const char* what() const noexcept override {
- return "bad any_cast<>()";
- }
-};
-/**
- * A variant of `std::any` for non-copyable types.
- *
- * Use `unique_any` for non-copyable types (e.g. `std::unique_ptr<T>`)
- * or to ensure that no copies are made of copyable types that are
- * moved in.
- *
- * `uniqe_any` differs from `std::any` in that it does not support copy construction
- * or copy assignment. It also does not require the contained type to be copy
- * constructible.
- *
- * The `any_cast<T>()` methods work similar to `std::any_cast<T>()` except that
- * non-copyable types may only be cast to references.
- *
- * Example usage:
- * unique_any u1(3);
- * auto u2 = unique_any(std::move(u1)); // u1 is moved from
- * int i = any_cast<int>(u2);
- *
- * unique_any u2;
- * u2 = std::unique_ptr<int>(new int);
- * std::unique_ptr<int> iPtr = any_cast<std::unique_ptr<int>>(std::move(u2));
- *
- * Inspired by linb::any (https://github.com/thelink2012/any) and the
- * libc++ implementation (https://github.com/llvm-mirror/libcxx).
- */
-class unique_any final
-{
-public:
- unique_any() = default;
-
- //Copy constructor (deleted)
- unique_any(const unique_any& rhs) = delete;
-
- unique_any(unique_any&& rhs) : vtable(rhs.vtable) {
- if (vtable) {
- vtable->move(std::move(rhs.storage), storage);
- }
- rhs.vtable = nullptr;
- }
-
- // Constructs with a direct-initilizated object of type ValueType
- template <typename ValueType,
- typename _Vt = std::decay_t<ValueType>,
- typename = std::enable_if_t<!std::is_same<_Vt, unique_any>::value> >
- unique_any(ValueType&& value) {
- create(std::forward<ValueType>(value));
- }
-
- ~unique_any() {
- reset();
- }
-
- unique_any& operator=(unique_any&& rhs) {
- unique_any(std::move(rhs)).swap(*this);
- return *this;
- }
-
- template <class ValueType,
- typename = std::enable_if_t<!std::is_same<std::decay_t<ValueType>, unique_any>::value> >
- unique_any& operator=(ValueType&& rhs) {
- unique_any(std::forward<ValueType>(rhs)).swap(*this);
- return *this;
- }
-
- void reset() {
- if (vtable) {
- vtable->destroy(storage);
- vtable = nullptr;
- }
- }
-
- void swap(unique_any& rhs) {
- if (this == &rhs) {
- return;
- } else {
- unique_any tmp(std::move(rhs));
- rhs.vtable = vtable;
- if (rhs.vtable) {
- rhs.vtable->move(std::move(storage), rhs.storage);
- }
- vtable = tmp.vtable;
- if (vtable) {
- vtable->move(std::move(tmp.storage), storage);
- }
- }
- }
-
- const std::type_info& type() const {
- return !has_value()? typeid(void) : vtable->type();
- }
-
- bool has_value() const {
- return vtable != nullptr;
- }
-
-private:
-
- union Storage {
- using StackStorage = std::aligned_storage_t<3*sizeof(void*), std::alignment_of<void*>::value>;
- Storage() = default;
-
- void * dynamic { nullptr };
- StackStorage stack;
- };
-
- template<typename T>
- struct AllocateOnStack : std::integral_constant<bool,
- sizeof(T) <= sizeof(Storage::stack)
- && std::alignment_of<T>::value <= std::alignment_of<Storage::StackStorage>::value
- && std::is_nothrow_move_constructible<T>::value> {
- };
-
- struct VTable {
- virtual ~VTable() = default;
- virtual void move(Storage&& src, Storage& dest) = 0;
- virtual void destroy(Storage&) = 0;
- virtual const std::type_info& type() = 0;
- };
-
- template <typename ValueType>
- struct VTableHeap : public VTable {
- void move(Storage&& src, Storage& dest) override {
- dest.dynamic = src.dynamic;
- src.dynamic = nullptr;
- }
-
- void destroy(Storage& s) override {
- delete reinterpret_cast<ValueType*>(s.dynamic);
- }
-
- const std::type_info& type() override {
- return typeid(ValueType);
- }
- };
-
- template <typename ValueType>
- struct VTableStack : public VTable {
- void move(Storage&& src, Storage& dest) override {
- new (&dest.stack) ValueType(std::move(reinterpret_cast<ValueType&>(src.stack)));
- destroy(src);
- }
-
- void destroy(Storage& s) override {
- reinterpret_cast<ValueType&>(s.stack).~ValueType();
- }
-
- const std::type_info& type() override {
- return typeid(ValueType);
- }
- };
-
- template <typename ValueType>
- static VTable* vtableForType() {
- using VTableType = std::conditional_t<AllocateOnStack<ValueType>::value, VTableStack<ValueType>, VTableHeap<ValueType> >;
- static VTableType vtable;
- return &vtable;
- }
-
- template <typename ValueType, typename _Vt>
- std::enable_if_t<AllocateOnStack<_Vt>::value>
- createStorage(ValueType&& value) {
- new (&storage.stack) _Vt(std::forward<ValueType>(value));
- }
-
- template <typename ValueType, typename _Vt>
- std::enable_if_t<!AllocateOnStack<_Vt>::value>
- createStorage(ValueType&& value) {
- storage.dynamic = new _Vt(std::forward<ValueType>(value));
- }
-
- template <typename ValueType>
- void create(ValueType&& value) {
- using _Vt = std::decay_t<ValueType>;
- vtable = vtableForType<_Vt>();
- createStorage<ValueType, _Vt>(std::forward<ValueType>(value));
- }
-
- VTable* vtable { nullptr };
- Storage storage;
-
-protected:
- template<class ValueType>
- friend const ValueType* any_cast(const unique_any* operand) ;
-
- template<class ValueType>
- friend ValueType* any_cast(unique_any* operand) ;
-
- template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
- ValueType* cast()
- {
- return reinterpret_cast<ValueType *>(
- AllocateOnStack<_Vt>::value ? &storage.stack : storage.dynamic);
- }
-};
-
-template<typename ValueType>
-inline const ValueType* any_cast(const unique_any* any)
-{
- return any_cast<ValueType>(const_cast<unique_any *>(any));
-}
-
-template<typename ValueType>
-inline ValueType* any_cast(unique_any* any)
-{
- if(any == nullptr || any->type() != typeid(ValueType))
- return nullptr;
- else
- return any->cast<ValueType>();
-}
-
-template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
-inline ValueType any_cast(const unique_any& any)
-{
- static_assert(std::is_constructible<ValueType, const _Vt&>::value,
- "any_cast type can't construct copy of contained object");
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- return static_cast<ValueType>(*temp);
-}
-
-template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
-inline ValueType any_cast(unique_any& any)
-{
- static_assert(std::is_constructible<ValueType, const _Vt&>::value,
- "any_cast type can't construct copy of contained object");
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- return static_cast<ValueType>(*temp);
-}
-
-template<typename ValueType, typename _Vt = std::remove_cv_t<ValueType> >
-inline ValueType any_cast(unique_any&& any)
-{
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- auto retValue = static_cast<ValueType>(std::move(*temp));
- any.reset();
- return std::move(retValue);
-}
-
-} // namespace util
-} // namespace mbgl
-
-namespace std {
-
-inline void swap(mbgl::util::unique_any& lhs, mbgl::util::unique_any& rhs) {
- lhs.swap(rhs);
-}
-
-} // namespace std