MapLibre Native Core
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
conversion_impl.hpp
Go to the documentation of this file.
1 #pragma once
2 
6 #include <mbgl/style/layer.hpp>
10 #include <mbgl/util/feature.hpp>
11 #include <mbgl/util/geojson.hpp>
12 #include <mbgl/util/traits.hpp>
13 
14 #include <mapbox/compatibility/value.hpp>
15 
16 #include <array>
17 #include <chrono>
18 #include <string>
19 #include <type_traits>
20 #include <optional>
21 
22 namespace mbgl {
23 namespace style {
24 
91 namespace conversion {
92 
93 template <typename T>
94 class ConversionTraits;
95 
96 class Convertible {
97 public:
98  template <typename T>
99  // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
100  Convertible(T&& value) : vtable(vtableForType<std::decay_t<T>>()) {
101  static_assert(sizeof(Storage) >= sizeof(std::decay_t<T>), "Storage must be large enough to hold value type");
102  new (static_cast<void*>(&storage)) std::decay_t<T>(std::forward<T>(value));
103  }
104 
105  Convertible(Convertible&& v) noexcept : vtable(v.vtable) {
106  // NOLINTNEXTLINE(performance-move-const-arg)
107  vtable->move(std::move(v.storage), storage);
108  }
109 
111  vtable->destroy(storage);
112  }
113 
115  if (this != &v) {
116  vtable->destroy(storage);
117  vtable = v.vtable;
118  // NOLINTNEXTLINE(performance-move-const-arg)
119  vtable->move(std::move(v.storage), storage);
120  }
121  return *this;
122  }
123 
124  Convertible() = delete;
125  Convertible(const Convertible&) = delete;
126  Convertible& operator=(const Convertible&) = delete;
127 
128  friend inline bool isUndefined(const Convertible& v) {
129  assert(v.vtable);
130  return v.vtable->isUndefined(v.storage);
131  }
132 
133  friend inline bool isArray(const Convertible& v) {
134  assert(v.vtable);
135  return v.vtable->isArray(v.storage);
136  }
137 
138  friend inline std::size_t arrayLength(const Convertible& v) {
139  assert(v.vtable);
140  return v.vtable->arrayLength(v.storage);
141  }
142 
143  friend inline Convertible arrayMember(const Convertible& v, std::size_t i) {
144  assert(v.vtable);
145  return v.vtable->arrayMember(v.storage, i);
146  }
147 
148  friend inline bool isObject(const Convertible& v) {
149  assert(v.vtable);
150  return v.vtable->isObject(v.storage);
151  }
152 
153  friend inline std::optional<Convertible> objectMember(const Convertible& v, const char * name) {
154  assert(v.vtable);
155  return v.vtable->objectMember(v.storage, name);
156  }
157 
158  friend inline std::optional<Error> eachMember(const Convertible& v, const std::function<std::optional<Error> (const std::string&, const Convertible&)>& fn) {
159  assert(v.vtable);
160  return v.vtable->eachMember(v.storage, fn);
161  }
162 
163  friend inline std::optional<bool> toBool(const Convertible& v) {
164  assert(v.vtable);
165  return v.vtable->toBool(v.storage);
166  }
167 
168  friend inline std::optional<float> toNumber(const Convertible& v) {
169  assert(v.vtable);
170  return v.vtable->toNumber(v.storage);
171  }
172 
173  friend inline std::optional<double> toDouble(const Convertible& v) {
174  assert(v.vtable);
175  return v.vtable->toDouble(v.storage);
176  }
177 
178  friend inline std::optional<std::string> toString(const Convertible& v) {
179  assert(v.vtable);
180  return v.vtable->toString(v.storage);
181  }
182 
183  friend inline std::optional<Value> toValue(const Convertible& v) {
184  assert(v.vtable);
185  return v.vtable->toValue(v.storage);
186  }
187 
188  friend inline std::optional<GeoJSON> toGeoJSON(const Convertible& v, Error& error) {
189  assert(v.vtable);
190  return v.vtable->toGeoJSON(v.storage, error);
191  }
192 
193 private:
194 #if __ANDROID__
195  // Android: JSValue* or mbgl::android::Value
196  using Storage = std::aligned_storage_t<32, 8>;
197 #elif __QT__
198  // Qt: JSValue* or QVariant
199  using Storage = std::aligned_storage_t<32, 8>;
200 #else
201  // Node: JSValue* or v8::Local<v8::Value>
202  // iOS/macOS: JSValue* or id
203  using Storage = std::aligned_storage_t<8, 8>;
204 #endif
205 
206  struct VTable {
207  void (*move) (Storage&& src, Storage& dest);
208  void (*destroy) (Storage&);
209 
210  bool (*isUndefined) (const Storage&);
211 
212  bool (*isArray) (const Storage&);
213  std::size_t (*arrayLength) (const Storage&);
214  Convertible (*arrayMember) (const Storage&, std::size_t);
215 
216  bool (*isObject) (const Storage&);
217  std::optional<Convertible> (*objectMember) (const Storage&, const char *);
218  std::optional<Error> (*eachMember) (const Storage&, const std::function<std::optional<Error> (const std::string&, const Convertible&)>&);
219 
220  std::optional<bool> (*toBool) (const Storage&);
221  std::optional<float> (*toNumber) (const Storage&);
222  std::optional<double> (*toDouble) (const Storage&);
223  std::optional<std::string> (*toString) (const Storage&);
224  std::optional<Value> (*toValue) (const Storage&);
225 
226  // https://github.com/mapbox/mapbox-gl-native/issues/5623
227  std::optional<GeoJSON> (*toGeoJSON) (const Storage&, Error&);
228  };
229 
230  // Extracted this function from the table below to work around a GCC bug with differing
231  // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
232  template <typename T>
233  static auto vtableEachMember(const Storage& s, const std::function<std::optional<Error>(const std::string&, const Convertible&)>& fn) {
234  return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
235  return fn(k, Convertible(std::move(v)));
236  });
237  }
238 
239  template <typename T>
240  static VTable* vtableForType() {
241  using Traits = ConversionTraits<T>;
242  static VTable vtable = {
243  [] (Storage&& src, Storage& dest) {
244  new (static_cast<void*>(&dest)) T(reinterpret_cast<T&&>(src));
245  },
246  [] (Storage& s) {
247  reinterpret_cast<T&>(s).~T();
248  },
249  [] (const Storage& s) {
250  return Traits::isUndefined(reinterpret_cast<const T&>(s));
251  },
252  [] (const Storage& s) {
253  return Traits::isArray(reinterpret_cast<const T&>(s));
254  },
255  [] (const Storage& s) {
256  return Traits::arrayLength(reinterpret_cast<const T&>(s));
257  },
258  [] (const Storage& s, std::size_t i) {
259  return Convertible(Traits::arrayMember(reinterpret_cast<const T&>(s), i));
260  },
261  [] (const Storage& s) {
262  return Traits::isObject(reinterpret_cast<const T&>(s));
263  },
264  [] (const Storage& s, const char * key) {
265  std::optional<T> member = Traits::objectMember(reinterpret_cast<const T&>(s), key);
266  if (member) {
267  return std::optional<Convertible>(Convertible(std::move(*member)));
268  } else {
269  return std::optional<Convertible>();
270  }
271  },
272  vtableEachMember<T>,
273  [] (const Storage& s) {
274  return Traits::toBool(reinterpret_cast<const T&>(s));
275  },
276  [] (const Storage& s) {
277  return Traits::toNumber(reinterpret_cast<const T&>(s));
278  },
279  [] (const Storage& s) {
280  return Traits::toDouble(reinterpret_cast<const T&>(s));
281  },
282  [] (const Storage& s) {
283  return Traits::toString(reinterpret_cast<const T&>(s));
284  },
285  [] (const Storage& s) {
286  return Traits::toValue(reinterpret_cast<const T&>(s));
287  },
288  [] (const Storage& s, Error& err) {
289  return Traits::toGeoJSON(reinterpret_cast<const T&>(s), err);
290  }
291  };
292  return &vtable;
293  }
294 
295  VTable* vtable;
296  Storage storage;
297 };
298 
299 template <class T, class...Args>
300 std::optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
301  return Converter<T>()(value, error, std::forward<Args>(args)...);
302 }
303 
304 template <>
306  static Value make(const ColorRampPropertyValue& value) { return value.getExpression().serialize(); }
307 };
308 
309 template <>
311  static Value make(const TransitionOptions& value) { return value.serialize(); }
312 };
313 
314 template <>
316  static Value make(const Color& color) { return color.serialize(); }
317 };
318 
319 template <typename T>
320 struct ValueFactory<T, typename std::enable_if_t<(!std::is_enum_v<T> && !is_linear_container<T>::value)>> {
321  static Value make(const T& arg) { return {arg}; }
322 };
323 
324 template <typename T>
325 struct ValueFactory<T, typename std::enable_if_t<std::is_enum_v<T>>> {
326  static Value make(T arg) { return {Enum<T>::toString(arg)}; }
327 };
328 
329 template <typename T>
330 struct ValueFactory<T, typename std::enable_if_t<is_linear_container<T>::value>> {
331  static Value make(const T& arg) {
332  mapbox::base::ValueArray result;
333  result.reserve(arg.size());
334  for (const auto& item : arg) {
335  result.emplace_back(ValueFactory<std::decay_t<decltype(item)>>::make(item));
336  }
337  return result;
338  }
339 };
340 
341 template <>
343  static Value make(const Position& position) {
344  return ValueFactory<std::array<float, 3>>::make(position.getSpherical());
345  }
346 };
347 
348 template <>
350  static Value make(const Rotation& rotation) { return {rotation.getAngle()}; }
351 };
352 
353 template <>
354 struct ValueFactory<float> {
355  static Value make(float f) { return f; }
356 };
357 
358 template <typename T>
359 Value makeValue(T&& arg) {
360  return ValueFactory<std::decay_t<T>>::make(std::forward<T>(arg));
361 }
362 
363 template <typename T>
365  return value.match([](const Undefined&) -> StyleProperty { return {}; },
366  [](const Color& c) -> StyleProperty {
368  },
369  [](const PropertyExpression<T>& fn) -> StyleProperty {
370  return {fn.getExpression().serialize(), StyleProperty::Kind::Expression};
371  },
372  [](const auto& t) -> StyleProperty {
374  });
375 }
376 
378  if (!value.isDefined()) return {};
380 }
381 
383  if (value.isUndefined()) return {};
385 }
386 
387 } // namespace conversion
388 } // namespace style
389 } // namespace mbgl
mbgl::Value serialize() const
static const char * toString(T)
const expression::Expression & getExpression() const
std::array< float, 3 > getSpherical() const
Definition: position.hpp:29
auto match(Ts &&... ts) const
double getAngle() const noexcept
Definition: rotation.hpp:14
Generic representation of a style property.
mapbox::base::Value serialize() const
friend std::optional< std::string > toString(const Convertible &v)
friend bool isObject(const Convertible &v)
friend std::optional< bool > toBool(const Convertible &v)
Convertible & operator=(Convertible &&v) noexcept
friend std::optional< Value > toValue(const Convertible &v)
Convertible(const Convertible &)=delete
Convertible(Convertible &&v) noexcept
friend std::optional< GeoJSON > toGeoJSON(const Convertible &v, Error &error)
friend std::optional< Convertible > objectMember(const Convertible &v, const char *name)
friend std::optional< Error > eachMember(const Convertible &v, const std::function< std::optional< Error >(const std::string &, const Convertible &)> &fn)
friend bool isArray(const Convertible &v)
friend Convertible arrayMember(const Convertible &v, std::size_t i)
friend std::optional< double > toDouble(const Convertible &v)
friend bool isUndefined(const Convertible &v)
friend std::optional< float > toNumber(const Convertible &v)
friend std::size_t arrayLength(const Convertible &v)
Convertible & operator=(const Convertible &)=delete
virtual mbgl::Value serialize() const
Definition: expression.hpp:213
StyleProperty makeStyleProperty(const PropertyValue< T > &value)
std::optional< T > convert(const Convertible &value, Error &error, Args &&...args)
std::unique_ptr< Expression > error(std::string)
std::unique_ptr< Expression > toString(std::unique_ptr< Expression >, std::unique_ptr< Expression > def=nullptr)
std::unique_ptr< Expression > string(std::unique_ptr< Expression >, std::unique_ptr< Expression > def=nullptr)
constexpr ErrorType Error
Definition: type.hpp:92
Definition: actor.hpp:15
mapbox::base::Value Value
Definition: feature.hpp:11
Definition: tile_id.hpp:256
static Value make(const ColorRampPropertyValue &value)
static Value make(const Position &position)
static Value make(const Rotation &rotation)
static Value make(const TransitionOptions &value)