/************************************************************************************ ** ** Copyright 2021 Shaoguang ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, and to permit persons to whom the Software is furnished ** to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in all ** copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ** SOFTWARE. ** ************************************************************************************/ #ifndef ANY_H #define ANY_H #include #include #include namespace detail { template using _bool_constant = std::integral_constant; // _or template struct _or; template<> struct _or<> : public std::false_type { }; template struct _or<_B1> : public _B1 { }; template struct _or<_B1, _B2> : public std::conditional<_B1::value, _B1, _B2>::type { }; template struct _or<_B1, _B2, _B3, _Bn...> : public std::conditional<_B1::value, _B1, _or<_B2, _B3, _Bn...>>::type { }; // _and template struct _and; template<> struct _and<> : public std::true_type { }; template struct _and<_B1> : public _B1 { }; template struct _and<_B1, _B2> : public std::conditional<_B1::value, _B2, _B1>::type { }; template struct _and<_B1, _B2, _B3, _Bn...> : public std::conditional<_B1::value, _and<_B2, _B3, _Bn...>, _B1>::type { }; // _and_v template constexpr bool _and_v() noexcept { return _and<_Bn...>::value; } // _not template struct _not : public _bool_constant { }; // _in_place_type_t template struct _in_place_type_t { explicit _in_place_type_t() = default; }; // _is_in_place_type template struct _is_in_place_type_impl : std::false_type { }; template struct _is_in_place_type_impl<_in_place_type_t<_Tp>> : std::true_type { }; template struct _is_in_place_type : public _is_in_place_type_impl<_Tp> { }; } // namespace detail /** * \class bad_any_cast * \brief Exception thrown by the value-returning forms of any_cast on a type mismatch. * * Defines a type of object to be thrown by the value-returning forms of any_cast on failure. */ class bad_any_cast : public std::bad_cast { public: /** * Returns an explanatory string. */ virtual const char* what() const noexcept; }; [[noreturn]] inline void throw_bad_any_cast() { throw bad_any_cast{}; } /** * \class any * \brief The class any describes a type-safe container for single values of any type. * * An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, * and this is referred to as the state of the class any object. The stored instance is called the contained object. * Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent. * * The non-member any_cast functions provide type-safe access to the contained object. */ class any { // Holds either pointer to a heap object or the contained object itself. union Storage { constexpr Storage() : m_ptr(nullptr) {} // Prevent trivial copies of this type, buffer might hold a non-POD. Storage(const Storage&) = delete; Storage& operator=(const Storage&) = delete; void* m_ptr; std::aligned_storage::type m_buffer; }; template, bool _Fits = (sizeof(_Tp) <= sizeof(Storage)) && (alignof(_Tp) <= alignof(Storage))> using Internal = std::integral_constant; template struct Manager_internal; // uses small-object optimization template struct Manager_external; // creates contained object on the heap template using Manager = typename std::conditional::value, Manager_internal<_Tp>, Manager_external<_Tp>>::type; template::type> using Decay = typename std::enable_if::value, _Decayed>::type; /** Emplace with an object created from \a args as the contained object. */ template > void _do_emplace(_Args&&... args) { reset(); Mgr::S_create(m_storage, std::forward<_Args>(args)...); m_manager = &Mgr::S_manage; } /** Emplace with an object created from \a list and \a list as the contained object. */ template > void _do_emplace(std::initializer_list<_Up> list, _Args&&... args) { reset(); Mgr::S_create(m_storage, list, std::forward<_Args>(args)...); m_manager = &Mgr::S_manage; } public: // // construct/destruct // /** * Default constructor, creates an empty object. */ constexpr any() noexcept; /** * Copy constructor, copies the state of \a other */ any(const any& other); /** * Move constructor, transfer the state from \a other. */ any(any&& other) noexcept; template using _any_constructible = std::enable_if, std::is_constructible<_Tp, _Args...>>::value, _Res>; template using _any_constructible_t = typename _any_constructible::type; /** * Construct with a copy of \a value as the contained object. */ template , typename Mgr = Manager<_Tp>, _any_constructible_t<_Tp, _ValueType&&> = true, typename std::enable_if::value, bool>::type = true> any(_ValueType&& value) : m_manager(&Mgr::S_manage) { Mgr::S_create(m_storage, std::forward<_ValueType>(value)); } /** * Construct with a copy of \a value as the contained object. */ template , typename Mgr = Manager<_Tp>, typename std::enable_if, detail::_not>, detail::_not>>(), bool>::value = false> any(_ValueType&& value) : m_manager(&Mgr::S_manage) { Mgr::S_create(m_storage, value); } /** * Construct with an object created from @p __args as the contained object. */ template , typename Mgr = Manager<_Tp>, _any_constructible_t<_Tp, _Args&& ... > = false> explicit any(detail::_in_place_type_t<_ValueType>, _Args&&... args) : m_manager(&Mgr::S_manage) { Mgr::S_create(m_storage, std::forward<_Args>(args)...); } /** * Construct with an object created from \a list and \a args as the contained object. */ template , typename Mgr = Manager<_Tp>, _any_constructible_t<_Tp, std::initializer_list<_Up>, _Args&&...> = false> explicit any(detail::_in_place_type_t<_ValueType>, std::initializer_list<_Up> list, _Args&&... args) : m_manager(&Mgr::S_manage) { Mgr::S_create(m_storage, list, std::forward<_Args>(args)...); } /** * Destructor, calls \c reset() */ ~any(); // // assignments // /** * Copy the state of another object. */ any& operator=(const any& rhs); /** * Move assignment operator * * \note \c !rhs.has_value() (not guaranteed for other implementations) */ any& operator=(any&& rhs) noexcept; /** * Store a copy of \a rhs as the contained object. */ template typename std::enable_if>::value, any&>::type operator=(_ValueType&& rhs) { *this = any(std::forward<_ValueType>(rhs)); return *this; } /** * Emplace with an object created from @p __args as the contained object. */ template typename _any_constructible&, Decay<_ValueType>, _Args&&...>::type emplace(_Args&&... args) { _do_emplace>(std::forward<_Args>(args)...); any::ManageArg marg; this->m_manager(any::MOAccess, this, &marg); return *static_cast*>(marg._obj); } /** * Emplace with an object created from \a list and\a args as the contained object. */ template typename _any_constructible&, Decay<_ValueType>, std::initializer_list<_Up>, _Args&&...>::type emplace(std::initializer_list<_Up> list, _Args&&... args) { _do_emplace, _Up>(list, std::forward<_Args>(args)...); any::ManageArg marg; this->m_manager(any::MOAccess, this, &marg); return *static_cast*>(marg._obj); } // // modifiers // /** * If not empty, destroy the contained object. */ void reset() noexcept; /** * Exchange state with another object. */ void swap(any& rhs) noexcept; // // observers // /** * bool has_value() const noexcept */ bool has_value() const noexcept; #if __cpp_rtti /** * The \c typeid of the contained object, or \c typeid(void) if empty. */ const std::type_info& type() const noexcept; #endif template static constexpr bool _is_valid_cast() { return detail::_or, std::is_copy_constructible<_Tp>>::value; } private: enum ManageOption { MOAccess, MOGetTypeInfo, MOClone, MODestroy, MOXfer }; union ManageArg { void* _obj; const std::type_info* _typeinfo; any* _any; }; void(*m_manager)(ManageOption, const any*, ManageArg*); Storage m_storage; template friend void* _any_caster(const any* __any); // Manage in-place contained object. template struct Manager_internal { static void S_manage(ManageOption which, const any* anyp, ManageArg* arg); template static void S_create(Storage& storage, _Up&& value) { void* addr = &storage.m_buffer; ::new (addr) _Tp(std::forward<_Up>(value)); } template static void S_create(Storage& storage, _Args&&... args) { void* addr = &storage.m_buffer; ::new (addr) _Tp(std::forward<_Args>(args)...); } }; // Manage external contained object. template struct Manager_external { static void S_manage(ManageOption __which, const any* __anyp, ManageArg* __arg); template static void S_create(Storage& storage, _Up&& value) { storage.m_ptr = new _Tp(std::forward<_Up>(value)); } template static void S_create(Storage& storage, _Args&&... __args) { storage.m_ptr = new _Tp(std::forward<_Args>(__args)...); } }; }; /** * Exchange the states of two \a any objects. */ inline void swap(any& x, any& y) noexcept { x.swap(y); } /** * Create an any holding a \c _Tp constructed from \a args. */ template any make_any(_Args&&... args) { constexpr detail::_in_place_type_t<_Tp> __in_place_type; return any(__in_place_type, std::forward<_Args>(args)...); } /** * Create an any holding a \c _Tp constructed from \a list and \a args. */ template any make_any(std::initializer_list<_Up> list, _Args&&... args) { return any(detail::_in_place_type_t<_Tp>(), list, std::forward<_Args>(args)...); } /** * Access the contained object. * * \tparam _ValueType A const-reference or CopyConstructible type. * \param a The object to access. * \return The contained object. * \throw bad_any_cast If * \code * a.type() != typeid(remove_reference_t<_ValueType>) * \endcode */ template inline _ValueType any_cast(const any& a) { using _Up = typename std::remove_cv<_ValueType>::type; static_assert(any::_is_valid_cast<_ValueType>(), "Template argument must be a reference or CopyConstructible type"); static_assert(std::is_constructible<_ValueType, const _Up&>::value, "Template argument must be constructible from a const value."); auto resultp = any_cast<_Up>(&a); if (resultp) { return static_cast<_ValueType>(*resultp); } throw_bad_any_cast(); } /** * Access the contained object. * * \tparam _ValueType A const-reference or CopyConstructible type. * \param a The object to access. * \return The contained object. * \throw bad_any_cast If * \code * a.type() != typeid(remove_reference_t<_ValueType>) * \endcode */ template inline _ValueType any_cast(any& a) { using _Up = typename std::remove_cv<_ValueType>::type; static_assert(any::_is_valid_cast<_ValueType>(), "Template argument must be a reference or CopyConstructible type"); static_assert(std::is_constructible<_ValueType, _Up&>::value, "Template argument must be constructible from an lvalue."); auto resultp = any_cast<_Up>(&a); if (resultp) { return static_cast<_ValueType>(*resultp); } throw_bad_any_cast(); } template inline _ValueType any_cast(any&& a) { using _Up = typename std::remove_cv<_ValueType>::type; static_assert(any::_is_valid_cast<_ValueType>(), "Template argument must be a reference or CopyConstructible type"); static_assert(std::is_constructible<_ValueType, _Up>::value, "Template argument must be constructible from an rvalue."); auto resultp = any_cast<_Up>(&a); if (resultp) { return static_cast<_ValueType>(std::move(*resultp)); } throw_bad_any_cast(); } /// \cond undocumented template void* _any_caster(const any* a) { // any_cast returns non-null if __any->type() == typeid(T) and // typeid(T) ignores cv-qualifiers so remove them: using _Up = typename std::remove_cv<_Tp>::type; // The contained value has a decayed type, so if decay_t is not U, // then it's not possible to have a contained value of type U: if (!std::is_same::type, _Up>::value) { return nullptr; } // Only copy constructible types can be used for contained values: else if (!std::is_copy_constructible<_Up>::value) { return nullptr; } // First try comparing function addresses, which works without RTTI else if (a->m_manager == &any::Manager<_Up>::S_manage #if __cpp_rtti || a->type() == typeid(_Tp) #endif ) { any::ManageArg marg; a->m_manager(any::MOAccess, a, &marg); return marg._obj; } return nullptr; } /// @endcond /** * Access the contained object. * * \tparam _ValueType A const-reference or CopyConstructible type. * \param a The object to access. * \return The contained object. * \throw bad_any_cast If * \code * a != nullptr && a.type() == typeid(_ValueType) * \endcode * * @{ */ template inline const _ValueType* any_cast(const any* a) noexcept { if (std::is_object<_ValueType>::value) { if (a) { return static_cast<_ValueType*>(_any_caster<_ValueType>(a)); } } return nullptr; } template inline _ValueType* any_cast(any* __any) noexcept { if (std::is_object<_ValueType>::value) { if (__any) { return static_cast<_ValueType*>(_any_caster<_ValueType>(__any)); } } return nullptr; } /** @} */ template void any::Manager_internal<_Tp>::S_manage(ManageOption which, const any* a, ManageArg* arg) { // The contained object is in _M_storage._M_buffer auto ptr = reinterpret_cast(&a->m_storage.m_buffer); switch (which) { case MOAccess: arg->_obj = const_cast<_Tp*>(ptr); break; case MOGetTypeInfo: #if __cpp_rtti arg->_typeinfo = &typeid(_Tp); #endif break; case MOClone: ::new(&arg->_any->m_storage.m_buffer) _Tp(*ptr); arg->_any->m_manager = a->m_manager; break; case MODestroy: ptr->~_Tp(); break; case MOXfer: ::new(&arg->_any->m_storage.m_buffer) _Tp (std::move(*const_cast<_Tp*>(ptr))); ptr->~_Tp(); arg->_any->m_manager = a->m_manager; const_cast(a)->m_manager = nullptr; break; } } template void any::Manager_external<_Tp>::S_manage(ManageOption which, const any* a, ManageArg* arg) { // The contained object is *_M_storage._M_ptr auto ptr = static_cast(a->m_storage.m_ptr); switch (which) { case MOAccess: arg->_obj = const_cast<_Tp*>(ptr); break; case MOGetTypeInfo: #if __cpp_rtti arg->_typeinfo = &typeid(_Tp); #endif break; case MOClone: arg->_any->m_storage.m_ptr = new _Tp(*ptr); arg->_any->m_manager = a->m_manager; break; case MODestroy: delete ptr; break; case MOXfer: arg->_any->m_storage.m_ptr = a->m_storage.m_ptr; arg->_any->m_manager = a->m_manager; const_cast(a)->m_manager = nullptr; break; } } #endif // ANY_H