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