From 3067b77c650f5dea0c00a7a92a9fc927e028c742 Mon Sep 17 00:00:00 2001 From: Asheem Mamoowala Date: Thu, 16 Nov 2017 18:38:27 -0800 Subject: [core, ios, macos] Implement unique_any and remove linb::any --- include/mbgl/style/layer.hpp | 4 +- include/mbgl/style/source.hpp | 4 +- include/mbgl/util/any.hpp | 10 -- include/mbgl/util/unique_any.hpp | 275 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 279 insertions(+), 14 deletions(-) delete mode 100644 include/mbgl/util/any.hpp create mode 100644 include/mbgl/util/unique_any.hpp (limited to 'include/mbgl') 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 -#include +#include #include #include #include @@ -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 #include -#include +#include #include #include @@ -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 - -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 +#include +#include +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`) + * 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()` methods work similar to `std::any_cast()` 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(u2); + * + * unique_any u2; + * u2 = std::unique_ptr(new int); + * std::unique_ptr iPtr = any_cast>(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 = std::enable_if_t::value> > + unique_any(ValueType&& value) { + create(std::forward(value)); + } + + ~unique_any() { + reset(); + } + + unique_any& operator=(unique_any&& rhs) { + unique_any(std::move(rhs)).swap(*this); + return *this; + } + + template , unique_any>::value> > + unique_any& operator=(ValueType&& rhs) { + unique_any(std::forward(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::value>; + Storage() = default; + + void * dynamic { nullptr }; + StackStorage stack; + }; + + template + struct AllocateOnStack : std::integral_constant::value <= std::alignment_of::value + && std::is_nothrow_move_constructible::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 + 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(s.dynamic); + } + s.dynamic = nullptr; + } + + const std::type_info& type() override { + return typeid(ValueType); + } + }; + + template + struct VTableStack : public VTable { + void move(Storage&& src, Storage& dest) override { + auto srcValue = reinterpret_cast(src.stack); + new (static_cast(&dest.stack)) ValueType(std::move(srcValue)); + srcValue.~ValueType(); + } + + void destroy(Storage& s) override { + reinterpret_cast(s.stack).~ValueType(); + } + + const std::type_info& type() override { + return typeid(ValueType); + } + }; + + template + static VTable* vtableForType() { + using VTableType = std::conditional_t::value, VTableStack, VTableHeap >; + static VTableType vtable; + return &vtable; + } + + template + std::enable_if_t::value> + createStorage(ValueType&& value) { + new (static_cast(&storage.stack)) _Vt(std::forward(value)); + } + + template + std::enable_if_t::value> + createStorage(ValueType&& value) { + storage.dynamic = static_cast(new _Vt(std::forward(value))); + } + + template + void create(ValueType&& value) { + using _Vt = std::decay_t; + vtable = vtableForType<_Vt>(); + createStorage(std::forward(value)); + } + + VTable* vtable { nullptr }; + Storage storage; + +protected: + template + friend const ValueType* any_cast(const unique_any* operand) ; + + template + friend ValueType* any_cast(unique_any* operand) ; + + template > + ValueType* cast() + { + return reinterpret_cast( + AllocateOnStack<_Vt>::value ? &storage.stack : storage.dynamic); + } +}; + +template +inline const ValueType* any_cast(const unique_any* any) +{ + return any_cast(const_cast(any)); +} + +template +inline ValueType* any_cast(unique_any* any) +{ + if(any == nullptr || any->type() != typeid(ValueType)) + return nullptr; + else + return any->cast(); +} + +template > +inline ValueType any_cast(const unique_any& any) +{ + static_assert(std::is_constructible::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(*temp); +} + +template > +inline ValueType any_cast(unique_any& any) +{ + static_assert(std::is_constructible::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(*temp); +} + +template > +inline ValueType any_cast(unique_any&& any) +{ + auto temp = any_cast<_Vt>(&any); + if (temp == nullptr) { + throw bad_any_cast(); + } + auto retValue = static_cast(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 -- cgit v1.2.1