#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