diff options
author | Asheem Mamoowala <asheem.mamoowala@mapbox.com> | 2017-11-16 18:38:27 -0800 |
---|---|---|
committer | Asheem Mamoowala <asheem.mamoowala@mapbox.com> | 2017-11-22 13:56:38 -0800 |
commit | 3067b77c650f5dea0c00a7a92a9fc927e028c742 (patch) | |
tree | 407bf2b4bf19678f1e7c2418f4fd0b4e18fbfef6 /include | |
parent | ba63d06cfc09b016ce0ddfcaaa297bd259cadf09 (diff) | |
download | qtlocation-mapboxgl-3067b77c650f5dea0c00a7a92a9fc927e028c742.tar.gz |
[core, ios, macos] Implement unique_any and remove linb::any
Diffstat (limited to 'include')
-rw-r--r-- | include/mbgl/style/layer.hpp | 4 | ||||
-rw-r--r-- | include/mbgl/style/source.hpp | 4 | ||||
-rw-r--r-- | include/mbgl/util/any.hpp | 10 | ||||
-rw-r--r-- | include/mbgl/util/unique_any.hpp | 275 |
4 files changed, 279 insertions, 14 deletions
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index c6a3c0e735..eb2dbf830b 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -1,7 +1,7 @@ #pragma once #include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/any.hpp> +#include <mbgl/util/unique_any.hpp> #include <mbgl/util/immutable.hpp> #include <mbgl/style/layer_type.hpp> #include <mbgl/style/types.hpp> @@ -126,7 +126,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. - any peer; + util::unique_any peer; }; } // namespace style diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp index cec9619451..0b6a6c72d9 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/any.hpp> +#include <mbgl/util/unique_any.hpp> #include <mbgl/util/immutable.hpp> #include <mbgl/style/types.hpp> @@ -76,7 +76,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. - any peer; + util::unique_any peer; }; } // namespace style diff --git a/include/mbgl/util/any.hpp b/include/mbgl/util/any.hpp deleted file mode 100644 index eea64b188a..0000000000 --- a/include/mbgl/util/any.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include <linb/any.hpp> - -namespace mbgl { - -using linb::any; -using linb::any_cast; - -} // namespace mbgl diff --git a/include/mbgl/util/unique_any.hpp b/include/mbgl/util/unique_any.hpp new file mode 100644 index 0000000000..d488930a03 --- /dev/null +++ b/include/mbgl/util/unique_any.hpp @@ -0,0 +1,275 @@ +#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 { + destroy(dest); + dest.dynamic = src.dynamic; + } + + void destroy(Storage& s) override { + if (s.dynamic) { + delete reinterpret_cast<ValueType*>(s.dynamic); + } + s.dynamic = nullptr; + } + + const std::type_info& type() override { + return typeid(ValueType); + } + }; + + template <typename ValueType> + struct VTableStack : public VTable { + void move(Storage&& src, Storage& dest) override { + auto srcValue = reinterpret_cast<ValueType&&>(src.stack); + new (static_cast<void*>(&dest.stack)) ValueType(std::move(srcValue)); + srcValue.~ValueType(); + } + + 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 (static_cast<void*>(&storage.stack)) _Vt(std::forward<ValueType>(value)); + } + + template <typename ValueType, typename _Vt> + std::enable_if_t<!AllocateOnStack<_Vt>::value> + createStorage(ValueType&& value) { + storage.dynamic = static_cast<void*>(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 |