text: #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
  