1// <experimental/any> -*- C++ -*- 2 3// Copyright (C) 2014-2015 Free Software Foundation, Inc. 4// 5// This file is part of the GNU ISO C++ Library. This library is free 6// software; you can redistribute it and/or modify it under the 7// terms of the GNU General Public License as published by the 8// Free Software Foundation; either version 3, or (at your option) 9// any later version. 10 11// This library is distributed in the hope that it will be useful, 12// but WITHOUT ANY WARRANTY; without even the implied warranty of 13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14// GNU General Public License for more details. 15 16// Under Section 7 of GPL version 3, you are granted additional 17// permissions described in the GCC Runtime Library Exception, version 18// 3.1, as published by the Free Software Foundation. 19 20// You should have received a copy of the GNU General Public License and 21// a copy of the GCC Runtime Library Exception along with this program; 22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23// <http://www.gnu.org/licenses/>. 24 25/** @file experimental/any 26 * This is a TS C++ Library header. 27 */ 28 29#ifndef _GLIBCXX_EXPERIMENTAL_ANY 30#define _GLIBCXX_EXPERIMENTAL_ANY 1 31 32#pragma GCC system_header 33 34#if __cplusplus <= 201103L 35# include <bits/c++14_warning.h> 36#else 37 38#include <typeinfo> 39#include <new> 40#include <utility> 41#include <type_traits> 42#include <experimental/lfts_config.h> 43 44namespace std _GLIBCXX_VISIBILITY(default) 45{ 46namespace experimental 47{ 48inline namespace fundamentals_v1 49{ 50_GLIBCXX_BEGIN_NAMESPACE_VERSION 51 52 /** 53 * @defgroup any Type-safe container of any type 54 * @ingroup experimental 55 * 56 * A type-safe container for single values of value types, as 57 * described in n3804 "Any Library Proposal (Revision 3)". 58 * 59 * @{ 60 */ 61 62#define __cpp_lib_experimental_any 201411 63 64 /** 65 * @brief Exception class thrown by a failed @c any_cast 66 * @ingroup exceptions 67 */ 68 class bad_any_cast : public bad_cast 69 { 70 public: 71 virtual const char* what() const noexcept { return "bad any_cast"; } 72 }; 73 74 [[gnu::noreturn]] inline void __throw_bad_any_cast() 75 { 76#if __cpp_exceptions 77 throw bad_any_cast{}; 78#else 79 __builtin_abort(); 80#endif 81 } 82 83 /** 84 * @brief A type-safe container of any type. 85 * 86 * An @c any object's state is either empty or it stores a contained object 87 * of CopyConstructible type. 88 */ 89 class any 90 { 91 // Holds either pointer to a heap object or the contained object itself. 92 union _Storage 93 { 94 void* _M_ptr; 95 std::aligned_storage<sizeof(_M_ptr), sizeof(_M_ptr)>::type _M_buffer; 96 }; 97 98 template<typename _Tp, typename _Safe = is_trivially_copyable<_Tp>, 99 bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))> 100 using _Internal = std::integral_constant<bool, _Safe::value && _Fits>; 101 102 template<typename _Tp> 103 struct _Manager_internal; // uses small-object optimization 104 105 template<typename _Tp> 106 struct _Manager_external; // creates contained object on the heap 107 108 template<typename _Tp> 109 using _Manager = conditional_t<_Internal<_Tp>::value, 110 _Manager_internal<_Tp>, 111 _Manager_external<_Tp>>; 112 113 template<typename _Tp, typename _Decayed = decay_t<_Tp>> 114 using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>; 115 116 public: 117 // construct/destruct 118 119 /// Default constructor, creates an empty object. 120 any() noexcept : _M_manager(nullptr) { } 121 122 /// Copy constructor, copies the state of @p __other 123 any(const any& __other) : _M_manager(__other._M_manager) 124 { 125 if (!__other.empty()) 126 { 127 _Arg __arg; 128 __arg._M_any = this; 129 _M_manager(_Op_clone, &__other, &__arg); 130 } 131 } 132 133 /** 134 * @brief Move constructor, transfer the state from @p __other 135 * 136 * @post @c __other.empty() (not guaranteed for other implementations) 137 */ 138 any(any&& __other) noexcept 139 : _M_manager(__other._M_manager), 140 _M_storage(__other._M_storage) 141 { __other._M_manager = nullptr; } 142 143 /// Construct with a copy of @p __value as the contained object. 144 template <typename _ValueType, typename _Tp = _Decay<_ValueType>, 145 typename _Mgr = _Manager<_Tp>> 146 any(_ValueType&& __value) 147 : _M_manager(&_Mgr::_S_manage), 148 _M_storage(_Mgr::_S_create(std::forward<_ValueType>(__value))) 149 { 150 static_assert(is_copy_constructible<_Tp>::value, 151 "The contained object must be CopyConstructible"); 152 } 153 154 /// Destructor, calls @c clear() 155 ~any() { clear(); } 156 157 // assignments 158 159 /// Copy the state of 160 any& operator=(const any& __rhs) 161 { 162 any(__rhs).swap(*this); 163 return *this; 164 } 165 166 /** 167 * @brief Move assignment operator 168 * 169 * @post @c __rhs.empty() (not guaranteed for other implementations) 170 */ 171 any& operator=(any&& __rhs) noexcept 172 { 173 any(std::move(__rhs)).swap(*this); 174 return *this; 175 } 176 177 /// Store a copy of @p __rhs as the contained object. 178 template<typename _ValueType> 179 any& operator=(_ValueType&& __rhs) 180 { 181 any(std::forward<_ValueType>(__rhs)).swap(*this); 182 return *this; 183 } 184 185 // modifiers 186 187 /// If not empty, destroy the contained object. 188 void clear() noexcept 189 { 190 if (!empty()) 191 { 192 _M_manager(_Op_destroy, this, nullptr); 193 _M_manager = nullptr; 194 } 195 } 196 197 /// Exchange state with another object. 198 void swap(any& __rhs) noexcept 199 { 200 std::swap(_M_manager, __rhs._M_manager); 201 std::swap(_M_storage, __rhs._M_storage); 202 } 203 204 // observers 205 206 /// Reports whether there is a contained object or not. 207 bool empty() const noexcept { return _M_manager == nullptr; } 208 209#if __cpp_rtti 210 /// The @c typeid of the contained object, or @c typeid(void) if empty. 211 const type_info& type() const noexcept 212 { 213 if (empty()) 214 return typeid(void); 215 _Arg __arg; 216 _M_manager(_Op_get_type_info, this, &__arg); 217 return *__arg._M_typeinfo; 218 } 219#endif 220 221 template<typename _Tp> 222 static constexpr bool __is_valid_cast() 223 { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; } 224 225 private: 226 enum _Op { _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy }; 227 228 union _Arg 229 { 230 void* _M_obj; 231 const std::type_info* _M_typeinfo; 232 any* _M_any; 233 }; 234 235 void (*_M_manager)(_Op, const any*, _Arg*); 236 _Storage _M_storage; 237 238 template<typename _Tp> 239 friend void* __any_caster(const any* __any); 240 241 // Manage in-place contained object. 242 template<typename _Tp> 243 struct _Manager_internal 244 { 245 static void 246 _S_manage(_Op __which, const any* __anyp, _Arg* __arg); 247 248 template<typename _Up> 249 static _Storage 250 _S_create(_Up&& __value) 251 { 252 _Storage __storage; 253 void* __addr = &__storage._M_buffer; 254 ::new (__addr) _Tp(std::forward<_Up>(__value)); 255 return __storage; 256 } 257 258 template<typename _Alloc, typename _Up> 259 static _Storage 260 _S_alloc(const _Alloc&, _Up&& __value) 261 { 262 return _S_create(std::forward<_Up>(__value)); 263 } 264 }; 265 266 // Manage external contained object. 267 template<typename _Tp> 268 struct _Manager_external 269 { 270 static void 271 _S_manage(_Op __which, const any* __anyp, _Arg* __arg); 272 273 template<typename _Up> 274 static _Storage 275 _S_create(_Up&& __value) 276 { 277 _Storage __storage; 278 __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); 279 return __storage; 280 } 281 }; 282 }; 283 284 /// Exchange the states of two @c any objects. 285 inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } 286 287 /** 288 * @brief Access the contained object. 289 * 290 * @tparam _ValueType A const-reference or CopyConstructible type. 291 * @param __any The object to access. 292 * @return The contained object. 293 * @throw bad_any_cast If <code> 294 * __any.type() != typeid(remove_reference_t<_ValueType>) 295 * </code> 296 */ 297 template<typename _ValueType> 298 inline _ValueType any_cast(const any& __any) 299 { 300 static_assert(any::__is_valid_cast<_ValueType>(), 301 "Template argument must be a reference or CopyConstructible type"); 302 auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any); 303 if (__p) 304 return *__p; 305 __throw_bad_any_cast(); 306 } 307 308 /** 309 * @brief Access the contained object. 310 * 311 * @tparam _ValueType A reference or CopyConstructible type. 312 * @param __any The object to access. 313 * @return The contained object. 314 * @throw bad_any_cast If <code> 315 * __any.type() != typeid(remove_reference_t<_ValueType>) 316 * </code> 317 * 318 * @{ 319 */ 320 template<typename _ValueType> 321 inline _ValueType any_cast(any& __any) 322 { 323 static_assert(any::__is_valid_cast<_ValueType>(), 324 "Template argument must be a reference or CopyConstructible type"); 325 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); 326 if (__p) 327 return *__p; 328 __throw_bad_any_cast(); 329 } 330 331 template<typename _ValueType> 332 inline _ValueType any_cast(any&& __any) 333 { 334 static_assert(any::__is_valid_cast<_ValueType>(), 335 "Template argument must be a reference or CopyConstructible type"); 336 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); 337 if (__p) 338 return *__p; 339 __throw_bad_any_cast(); 340 } 341 // @} 342 343 template<typename _Tp> 344 void* __any_caster(const any* __any) 345 { 346 struct _None { }; 347 using _Up = decay_t<_Tp>; 348 using _Vp = conditional_t<is_copy_constructible<_Up>::value, _Up, _None>; 349 if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) 350 return nullptr; 351 any::_Arg __arg; 352 __any->_M_manager(any::_Op_access, __any, &__arg); 353 return __arg._M_obj; 354 } 355 356 /** 357 * @brief Access the contained object. 358 * 359 * @tparam _ValueType The type of the contained object. 360 * @param __any A pointer to the object to access. 361 * @return The address of the contained object if <code> 362 * __any != nullptr && __any.type() == typeid(_ValueType) 363 * </code>, otherwise a null pointer. 364 * 365 * @{ 366 */ 367 template<typename _ValueType> 368 inline const _ValueType* any_cast(const any* __any) noexcept 369 { 370 if (__any) 371 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); 372 return nullptr; 373 } 374 375 template<typename _ValueType> 376 inline _ValueType* any_cast(any* __any) noexcept 377 { 378 if (__any) 379 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); 380 return nullptr; 381 } 382 // @} 383 384 template<typename _Tp> 385 void 386 any::_Manager_internal<_Tp>:: 387 _S_manage(_Op __which, const any* __any, _Arg* __arg) 388 { 389 // The contained object is in _M_storage._M_buffer 390 auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer); 391 switch (__which) 392 { 393 case _Op_access: 394 __arg->_M_obj = const_cast<_Tp*>(__ptr); 395 break; 396 case _Op_get_type_info: 397#if __cpp_rtti 398 __arg->_M_typeinfo = &typeid(_Tp); 399#endif 400 break; 401 case _Op_clone: 402 ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); 403 break; 404 case _Op_destroy: 405 __ptr->~_Tp(); 406 break; 407 } 408 } 409 410 template<typename _Tp> 411 void 412 any::_Manager_external<_Tp>:: 413 _S_manage(_Op __which, const any* __any, _Arg* __arg) 414 { 415 // The contained object is *_M_storage._M_ptr 416 auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr); 417 switch (__which) 418 { 419 case _Op_access: 420 __arg->_M_obj = const_cast<_Tp*>(__ptr); 421 break; 422 case _Op_get_type_info: 423#if __cpp_rtti 424 __arg->_M_typeinfo = &typeid(_Tp); 425#endif 426 break; 427 case _Op_clone: 428 __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); 429 break; 430 case _Op_destroy: 431 delete __ptr; 432 break; 433 } 434 } 435 436 // @} group any 437_GLIBCXX_END_NAMESPACE_VERSION 438} // namespace fundamentals_v1 439} // namespace experimental 440} // namespace std 441 442#endif // C++14 443 444#endif // _GLIBCXX_EXPERIMENTAL_ANY 445