1 /// \file
2 // Range v3 library
3 //
4 //  Copyright Eric Niebler 2015-present
5 //
6 //  Use, modification and distribution is subject to the
7 //  Boost Software License, Version 1.0. (See accompanying
8 //  file LICENSE_1_0.txt or copy at
9 //  http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 //
13 
14 #ifndef RANGES_V3_UTILITY_ANY_HPP
15 #define RANGES_V3_UTILITY_ANY_HPP
16 
17 #include <memory>
18 #include <type_traits>
19 #include <typeinfo>
20 
21 #include <meta/meta.hpp>
22 
23 #include <concepts/concepts.hpp>
24 
25 #include <range/v3/range_fwd.hpp>
26 
27 #include <range/v3/utility/swap.hpp>
28 
29 #include <range/v3/detail/prologue.hpp>
30 
31 RANGES_DIAGNOSTIC_PUSH
32 RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS
33 
34 namespace ranges
35 {
36     struct bad_any_cast : std::bad_cast
37     {
whatranges::bad_any_cast38         virtual const char * what() const noexcept override
39         {
40             return "bad any_cast";
41         }
42     };
43 
44     struct RANGES_DEPRECATED(
45         "ranges::any will be going away in the not-too-distant future. "
46         "We suggest you use std::any or boost::any instead (or simply steal "
47         "this header and maintain it yourself).") any;
48 
49     template<typename T>
50     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &);
51 
52     template<typename T>
53     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const &);
54 
55     template<typename T>
56     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any &&);
57 
58     template<typename T>
59     T * any_cast(any *) noexcept;
60 
61     template<typename T>
62     T const * any_cast(any const *) noexcept;
63 
64     struct any
65     {
66     private:
67         template<typename T>
68         friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(any &);
69 
70         template<typename T>
71         friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
72             any const &);
73 
74         template<typename T>
75         friend meta::if_c<std::is_reference<T>() || (bool)copyable<T>, T> any_cast(
76             any &&);
77 
78         template<typename T>
79         friend T * any_cast(any *) noexcept;
80 
81         template<typename T>
82         friend T const * any_cast(any const *) noexcept;
83 
84         struct interface
85         {
~interfaceranges::any::interface86             virtual ~interface()
87             {}
88             virtual interface * clone() const = 0;
89             virtual std::type_info const & type() const noexcept = 0;
90         };
91 
92         template<typename T>
93         struct impl final : interface
94         {
95         private:
96             T obj;
97 
98         public:
99             impl() = default;
implranges::any::impl100             impl(T o)
101               : obj(std::move(o))
102             {}
getranges::any::impl103             T & get()
104             {
105                 return obj;
106             }
getranges::any::impl107             T const & get() const
108             {
109                 return obj;
110             }
cloneranges::any::impl111             impl * clone() const override
112             {
113                 return new impl{obj};
114             }
typeranges::any::impl115             std::type_info const & type() const noexcept override
116             {
117                 return typeid(T);
118             }
119         };
120 
121         std::unique_ptr<interface> ptr_;
122 
123     public:
124         any() noexcept = default;
125         template(typename TRef, typename T = detail::decay_t<TRef>)(
126             /// \pre
127             requires copyable<T> AND (!same_as<T, any>)) //
128         any(TRef && t)
129           : ptr_(new impl<T>(static_cast<TRef &&>(t)))
130         {}
131         any(any &&) noexcept = default;
anyranges::any132         any(any const & that)
133           : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr}
134         {}
135         any & operator=(any &&) noexcept = default;
operator =ranges::any136         any & operator=(any const & that)
137         {
138             ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr);
139             return *this;
140         }
141         template(typename TRef, typename T = detail::decay_t<TRef>)(
142             /// \pre
143             requires copyable<T> AND (!same_as<T, any>)) //
144         any & operator=(TRef && t)
145         {
146             any{static_cast<TRef &&>(t)}.swap(*this);
147             return *this;
148         }
149         void clear() noexcept
150         {
151             ptr_.reset();
152         }
153         bool empty() const noexcept
154         {
155             return !ptr_;
156         }
157         std::type_info const & type() const noexcept
158         {
159             return ptr_ ? ptr_->type() : typeid(void);
160         }
161         void swap(any & that) noexcept
162         {
163             ptr_.swap(that.ptr_);
164         }
165 
166 #if !RANGES_BROKEN_CPO_LOOKUP
167         friend void swap(any & x, any & y) noexcept
168         {
169             x.swap(y);
170         }
171 #endif
172     };
173 
174 #if RANGES_BROKEN_CPO_LOOKUP
175     namespace _any_
176     {
177         inline void swap(any & x, any & y) noexcept
178         {
179             x.swap(y);
180         }
181     } // namespace _any_
182 #endif
183 
184     /// \throw bad_any_cast
185     template<typename T>
186     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any & x)
187     {
188         if(x.type() != typeid(detail::decay_t<T>))
189             throw bad_any_cast{};
190         return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
191     }
192 
193     /// \overload
194     template<typename T>
195     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any const & x)
196     {
197         if(x.type() != typeid(detail::decay_t<T>))
198             throw bad_any_cast{};
199         return static_cast<any::impl<detail::decay_t<T>> const *>(x.ptr_.get())->get();
200     }
201 
202     /// \overload
203     template<typename T>
204     meta::if_c<std::is_reference<T>() || copyable<T>, T> any_cast(any && x)
205     {
206         if(x.type() != typeid(detail::decay_t<T>))
207             throw bad_any_cast{};
208         return static_cast<any::impl<detail::decay_t<T>> *>(x.ptr_.get())->get();
209     }
210 
211     /// \overload
212     template<typename T>
213     T * any_cast(any * p) noexcept
214     {
215         if(p && p->ptr_)
216             if(any::impl<T> * q = dynamic_cast<any::impl<T> *>(p->ptr_.get()))
217                 return &q->get();
218         return nullptr;
219     }
220 
221     /// \overload
222     template<typename T>
223     T const * any_cast(any const * p) noexcept
224     {
225         if(p && p->ptr_)
226             if(any::impl<T> const * q = dynamic_cast<any::impl<T> const *>(p->ptr_.get()))
227                 return &q->get();
228         return nullptr;
229     }
230 } // namespace ranges
231 
232 RANGES_DIAGNOSTIC_POP
233 
234 #include <range/v3/detail/epilogue.hpp>
235 
236 #endif
237