|
- /// \file
- // Range v3 library
- //
- // Copyright Eric Niebler 2015-present
- //
- // Use, modification and distribution is subject to the
- // Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // Project home: https://github.com/ericniebler/range-v3
- //
-
- #ifndef RANGES_V3_UTILITY_ANY_HPP
- #define RANGES_V3_UTILITY_ANY_HPP
-
- #include <memory>
- #include <type_traits>
- #include <typeinfo>
-
- #include <meta/meta.hpp>
-
- #include <concepts/concepts.hpp>
-
- #include <range/v3/range_fwd.hpp>
-
- #include <range/v3/utility/swap.hpp>
-
- RANGES_DIAGNOSTIC_PUSH
- RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
-
- namespace ranges
- {
- struct bad_any_cast : std::bad_cast
- {
- virtual const char * what() const noexcept override
- {
- return "bad any_cast";
- }
- };
-
- struct RANGES_DEPRECATED(
- "ranges::any will be going away in the not-too-distant future. "
- "We suggest you use std::any or boost::any instead (or simply steal "
- "this header and maintain it yourself).") any;
-
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &);
-
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const &);
-
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &&);
-
- template<typename T>
- T * any_cast(any *) noexcept;
-
- template<typename T>
- T const * any_cast(any const *) noexcept;
-
- struct any
- {
- private:
- template<typename T>
- friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(any &);
-
- template<typename T>
- friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
- any const &);
-
- template<typename T>
- friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
- any &&);
-
- template<typename T>
- friend T * any_cast(any *) noexcept;
-
- template<typename T>
- friend T const * any_cast(any const *) noexcept;
-
- struct interface
- {
- virtual ~interface()
- {}
- virtual interface * clone() const = 0;
- virtual std::type_info const & type() const noexcept = 0;
- };
-
- template<typename T>
- struct impl final : interface
- {
- private:
- T obj;
-
- public:
- impl() = default;
- impl(T o)
- : obj(std::move(o))
- {}
- T & get()
- {
- return obj;
- }
- T const & get() const
- {
- return obj;
- }
- impl * clone() const override
- {
- return new impl{obj};
- }
- std::type_info const & type() const noexcept override
- {
- return typeid(T);
- }
- };
-
- std::unique_ptr<interface> ptr_;
-
- public:
- any() noexcept = default;
- template<typename TRef, typename T = detail::decay_t<TRef>>
- CPP_ctor(any)(TRef && t)( //
- requires copyable<T> && (!same_as<T, any>))
- : ptr_(new impl<T>(static_cast<TRef &&>(t)))
- {}
- any(any &&) noexcept = default;
- any(any const & that)
- : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
- {}
- any & operator=(any &&) noexcept = default;
- any & operator=(any const & that)
- {
- ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr);
- return *this;
- }
- template<typename TRef, typename T = detail::decay_t<TRef>>
- auto operator=(TRef && t) -> CPP_ret(any &)( //
- requires copyable<T> && (!same_as<T, any>))
- {
- any{static_cast<TRef &&>(t)}.swap(*this);
- return *this;
- }
- void clear() noexcept
- {
- ptr_.reset();
- }
- bool empty() const noexcept
- {
- return !ptr_;
- }
- std::type_info const & type() const noexcept
- {
- return ptr_ ? ptr_->type() : typeid(void);
- }
- void swap(any & that) noexcept
- {
- ptr_.swap(that.ptr_);
- }
-
- #if !RANGES_BROKEN_CPO_LOOKUP
- friend void swap(any & x, any & y) noexcept
- {
- x.swap(y);
- }
- #endif
- };
-
- #if RANGES_BROKEN_CPO_LOOKUP
- namespace _any_
- {
- inline void swap(any & x, any & y) noexcept
- {
- x.swap(y);
- }
- } // namespace _any_
- #endif
-
- /// \throw bad_any_cast
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any & x)
- {
- if(x.type() != typeid(detail::decay_t<T>))
- throw bad_any_cast{};
- return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
- }
-
- /// \overload
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const & x)
- {
- if(x.type() != typeid(detail::decay_t<T>))
- throw bad_any_cast{};
- return static_cast<any::impl<detail::decay_t<T>> const *>(x.ptr_.get())->get();
- }
-
- /// \overload
- template<typename T>
- meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any && x)
- {
- if(x.type() != typeid(detail::decay_t<T>))
- throw bad_any_cast{};
- return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
- }
-
- /// \overload
- template<typename T>
- T * any_cast(any * p) noexcept
- {
- if(p && p->ptr_)
- if(any::impl<T> * q = dynamic_cast<any::impl<T> *>(p->ptr_.get()))
- return &q->get();
- return nullptr;
- }
-
- /// \overload
- template<typename T>
- T const * any_cast(any const * p) noexcept
- {
- if(p && p->ptr_)
- if(any::impl<T> const * q = dynamic_cast<any::impl<T> const *>(p->ptr_.get()))
- return &q->get();
- return nullptr;
- }
- } // namespace ranges
-
- RANGES_DIAGNOSTIC_POP
-
- #endif
|