1// <experimental/any> -*- C++ -*- 2 3// Copyright (C) 2014-2016 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/bits/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 // This constructor intentionally doesn't initialize anything. 95 _Storage() = default; 96 97 // Prevent trivial copies of this type, buffer might hold a non-POD. 98 _Storage(const _Storage&) = delete; 99 _Storage& operator=(const _Storage&) = delete; 100 101 void* _M_ptr; 102 aligned_storage<sizeof(_M_ptr), alignof(void*)>::type _M_buffer; 103 }; 104 105 template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>, 106 bool _Fits = (sizeof(_Tp) <= sizeof(_Storage)) 107 && (alignof(_Tp) <= alignof(_Storage))> 108 using _Internal = std::integral_constant<bool, _Safe::value && _Fits>; 109 110 template<typename _Tp> 111 struct _Manager_internal; // uses small-object optimization 112 113 template<typename _Tp> 114 struct _Manager_external; // creates contained object on the heap 115 116 template<typename _Tp> 117 using _Manager = conditional_t<_Internal<_Tp>::value, 118 _Manager_internal<_Tp>, 119 _Manager_external<_Tp>>; 120 121 template<typename _Tp, typename _Decayed = decay_t<_Tp>> 122 using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>; 123 124 public: 125 // construct/destruct 126 127 /// Default constructor, creates an empty object. 128 any() noexcept : _M_manager(nullptr) { } 129 130 /// Copy constructor, copies the state of @p __other 131 any(const any& __other) 132 { 133 if (__other.empty()) 134 _M_manager = nullptr; 135 else 136 { 137 _Arg __arg; 138 __arg._M_any = this; 139 __other._M_manager(_Op_clone, &__other, &__arg); 140 } 141 } 142 143 /** 144 * @brief Move constructor, transfer the state from @p __other 145 * 146 * @post @c __other.empty() (this postcondition is a GNU extension) 147 */ 148 any(any&& __other) noexcept 149 { 150 if (__other.empty()) 151 _M_manager = nullptr; 152 else 153 { 154 _Arg __arg; 155 __arg._M_any = this; 156 __other._M_manager(_Op_xfer, &__other, &__arg); 157 } 158 } 159 160 /// Construct with a copy of @p __value as the contained object. 161 template <typename _ValueType, typename _Tp = _Decay<_ValueType>, 162 typename _Mgr = _Manager<_Tp>, 163 typename enable_if<is_constructible<_Tp, _ValueType&&>::value, 164 bool>::type = true> 165 any(_ValueType&& __value) 166 : _M_manager(&_Mgr::_S_manage) 167 { 168 _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value)); 169 static_assert(is_copy_constructible<_Tp>::value, 170 "The contained object must be CopyConstructible"); 171 } 172 173 /// Construct with a copy of @p __value as the contained object. 174 template <typename _ValueType, typename _Tp = _Decay<_ValueType>, 175 typename _Mgr = _Manager<_Tp>, 176 typename enable_if<!is_constructible<_Tp, _ValueType&&>::value, 177 bool>::type = false> 178 any(_ValueType&& __value) 179 : _M_manager(&_Mgr::_S_manage) 180 { 181 _Mgr::_S_create(_M_storage, __value); 182 static_assert(is_copy_constructible<_Tp>::value, 183 "The contained object must be CopyConstructible"); 184 } 185 186 /// Destructor, calls @c clear() 187 ~any() { clear(); } 188 189 // assignments 190 191 /// Copy the state of another object. 192 any& operator=(const any& __rhs) 193 { 194 if (__rhs.empty()) 195 clear(); 196 else if (this != &__rhs) 197 { 198 if (!empty()) 199 _M_manager(_Op_destroy, this, nullptr); 200 _Arg __arg; 201 __arg._M_any = this; 202 __rhs._M_manager(_Op_clone, &__rhs, &__arg); 203 } 204 return *this; 205 } 206 207 /** 208 * @brief Move assignment operator 209 * 210 * @post @c __rhs.empty() (not guaranteed for other implementations) 211 */ 212 any& operator=(any&& __rhs) noexcept 213 { 214 if (__rhs.empty()) 215 clear(); 216 else if (this != &__rhs) 217 { 218 if (!empty()) 219 _M_manager(_Op_destroy, this, nullptr); 220 _Arg __arg; 221 __arg._M_any = this; 222 __rhs._M_manager(_Op_xfer, &__rhs, &__arg); 223 } 224 return *this; 225 } 226 227 /// Store a copy of @p __rhs as the contained object. 228 template<typename _ValueType> 229 enable_if_t<!is_same<any, decay_t<_ValueType>>::value, any&> 230 operator=(_ValueType&& __rhs) 231 { 232 *this = any(std::forward<_ValueType>(__rhs)); 233 return *this; 234 } 235 236 // modifiers 237 238 /// If not empty, destroy the contained object. 239 void clear() noexcept 240 { 241 if (!empty()) 242 { 243 _M_manager(_Op_destroy, this, nullptr); 244 _M_manager = nullptr; 245 } 246 } 247 248 /// Exchange state with another object. 249 void swap(any& __rhs) noexcept 250 { 251 if (empty() && __rhs.empty()) 252 return; 253 254 if (!empty() && !__rhs.empty()) 255 { 256 if (this == &__rhs) 257 return; 258 259 any __tmp; 260 _Arg __arg; 261 __arg._M_any = &__tmp; 262 __rhs._M_manager(_Op_xfer, &__rhs, &__arg); 263 __arg._M_any = &__rhs; 264 _M_manager(_Op_xfer, this, &__arg); 265 __arg._M_any = this; 266 __tmp._M_manager(_Op_xfer, &__tmp, &__arg); 267 } 268 else 269 { 270 any* __empty = empty() ? this : &__rhs; 271 any* __full = empty() ? &__rhs : this; 272 _Arg __arg; 273 __arg._M_any = __empty; 274 __full->_M_manager(_Op_xfer, __full, &__arg); 275 } 276 } 277 278 // observers 279 280 /// Reports whether there is a contained object or not. 281 bool empty() const noexcept { return _M_manager == nullptr; } 282 283#if __cpp_rtti 284 /// The @c typeid of the contained object, or @c typeid(void) if empty. 285 const type_info& type() const noexcept 286 { 287 if (empty()) 288 return typeid(void); 289 _Arg __arg; 290 _M_manager(_Op_get_type_info, this, &__arg); 291 return *__arg._M_typeinfo; 292 } 293#endif 294 295 template<typename _Tp> 296 static constexpr bool __is_valid_cast() 297 { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; } 298 299 private: 300 enum _Op { 301 _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer 302 }; 303 304 union _Arg 305 { 306 void* _M_obj; 307 const std::type_info* _M_typeinfo; 308 any* _M_any; 309 }; 310 311 void (*_M_manager)(_Op, const any*, _Arg*); 312 _Storage _M_storage; 313 314 template<typename _Tp> 315 friend void* __any_caster(const any* __any); 316 317 // Manage in-place contained object. 318 template<typename _Tp> 319 struct _Manager_internal 320 { 321 static void 322 _S_manage(_Op __which, const any* __anyp, _Arg* __arg); 323 324 template<typename _Up> 325 static void 326 _S_create(_Storage& __storage, _Up&& __value) 327 { 328 void* __addr = &__storage._M_buffer; 329 ::new (__addr) _Tp(std::forward<_Up>(__value)); 330 } 331 }; 332 333 // Manage external contained object. 334 template<typename _Tp> 335 struct _Manager_external 336 { 337 static void 338 _S_manage(_Op __which, const any* __anyp, _Arg* __arg); 339 340 template<typename _Up> 341 static void 342 _S_create(_Storage& __storage, _Up&& __value) 343 { 344 __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); 345 } 346 }; 347 }; 348 349 /// Exchange the states of two @c any objects. 350 inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } 351 352 /** 353 * @brief Access the contained object. 354 * 355 * @tparam _ValueType A const-reference or CopyConstructible type. 356 * @param __any The object to access. 357 * @return The contained object. 358 * @throw bad_any_cast If <code> 359 * __any.type() != typeid(remove_reference_t<_ValueType>) 360 * </code> 361 */ 362 template<typename _ValueType> 363 inline _ValueType any_cast(const any& __any) 364 { 365 static_assert(any::__is_valid_cast<_ValueType>(), 366 "Template argument must be a reference or CopyConstructible type"); 367 auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any); 368 if (__p) 369 return *__p; 370 __throw_bad_any_cast(); 371 } 372 373 /** 374 * @brief Access the contained object. 375 * 376 * @tparam _ValueType A reference or CopyConstructible type. 377 * @param __any The object to access. 378 * @return The contained object. 379 * @throw bad_any_cast If <code> 380 * __any.type() != typeid(remove_reference_t<_ValueType>) 381 * </code> 382 * 383 * @{ 384 */ 385 template<typename _ValueType> 386 inline _ValueType any_cast(any& __any) 387 { 388 static_assert(any::__is_valid_cast<_ValueType>(), 389 "Template argument must be a reference or CopyConstructible type"); 390 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); 391 if (__p) 392 return *__p; 393 __throw_bad_any_cast(); 394 } 395 396 template<typename _ValueType, 397 typename enable_if<!is_move_constructible<_ValueType>::value 398 || is_lvalue_reference<_ValueType>::value, 399 bool>::type = true> 400 inline _ValueType any_cast(any&& __any) 401 { 402 static_assert(any::__is_valid_cast<_ValueType>(), 403 "Template argument must be a reference or CopyConstructible type"); 404 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); 405 if (__p) 406 return *__p; 407 __throw_bad_any_cast(); 408 } 409 410 template<typename _ValueType, 411 typename enable_if<is_move_constructible<_ValueType>::value 412 && !is_lvalue_reference<_ValueType>::value, 413 bool>::type = false> 414 inline _ValueType any_cast(any&& __any) 415 { 416 static_assert(any::__is_valid_cast<_ValueType>(), 417 "Template argument must be a reference or CopyConstructible type"); 418 auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); 419 if (__p) 420 return std::move(*__p); 421 __throw_bad_any_cast(); 422 } 423 // @} 424 425 template<typename _Tp> 426 void* __any_caster(const any* __any) 427 { 428 struct _None { }; 429 using _Up = decay_t<_Tp>; 430 using _Vp = conditional_t<is_copy_constructible<_Up>::value, _Up, _None>; 431 if (__any->_M_manager != &any::_Manager<_Vp>::_S_manage) 432 return nullptr; 433 any::_Arg __arg; 434 __any->_M_manager(any::_Op_access, __any, &__arg); 435 return __arg._M_obj; 436 } 437 438 /** 439 * @brief Access the contained object. 440 * 441 * @tparam _ValueType The type of the contained object. 442 * @param __any A pointer to the object to access. 443 * @return The address of the contained object if <code> 444 * __any != nullptr && __any.type() == typeid(_ValueType) 445 * </code>, otherwise a null pointer. 446 * 447 * @{ 448 */ 449 template<typename _ValueType> 450 inline const _ValueType* any_cast(const any* __any) noexcept 451 { 452 if (__any) 453 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); 454 return nullptr; 455 } 456 457 template<typename _ValueType> 458 inline _ValueType* any_cast(any* __any) noexcept 459 { 460 if (__any) 461 return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); 462 return nullptr; 463 } 464 // @} 465 466 template<typename _Tp> 467 void 468 any::_Manager_internal<_Tp>:: 469 _S_manage(_Op __which, const any* __any, _Arg* __arg) 470 { 471 // The contained object is in _M_storage._M_buffer 472 auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer); 473 switch (__which) 474 { 475 case _Op_access: 476 __arg->_M_obj = const_cast<_Tp*>(__ptr); 477 break; 478 case _Op_get_type_info: 479#if __cpp_rtti 480 __arg->_M_typeinfo = &typeid(_Tp); 481#endif 482 break; 483 case _Op_clone: 484 ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); 485 __arg->_M_any->_M_manager = __any->_M_manager; 486 break; 487 case _Op_destroy: 488 __ptr->~_Tp(); 489 break; 490 case _Op_xfer: 491 ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); 492 __ptr->~_Tp(); 493 __arg->_M_any->_M_manager = __any->_M_manager; 494 const_cast<any*>(__any)->_M_manager = nullptr; 495 break; 496 } 497 } 498 499 template<typename _Tp> 500 void 501 any::_Manager_external<_Tp>:: 502 _S_manage(_Op __which, const any* __any, _Arg* __arg) 503 { 504 // The contained object is *_M_storage._M_ptr 505 auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr); 506 switch (__which) 507 { 508 case _Op_access: 509 __arg->_M_obj = const_cast<_Tp*>(__ptr); 510 break; 511 case _Op_get_type_info: 512#if __cpp_rtti 513 __arg->_M_typeinfo = &typeid(_Tp); 514#endif 515 break; 516 case _Op_clone: 517 __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); 518 __arg->_M_any->_M_manager = __any->_M_manager; 519 break; 520 case _Op_destroy: 521 delete __ptr; 522 break; 523 case _Op_xfer: 524 __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr; 525 __arg->_M_any->_M_manager = __any->_M_manager; 526 const_cast<any*>(__any)->_M_manager = nullptr; 527 break; 528 } 529 } 530 531 // @} group any 532_GLIBCXX_END_NAMESPACE_VERSION 533} // namespace fundamentals_v1 534} // namespace experimental 535} // namespace std 536 537#endif // C++14 538 539#endif // _GLIBCXX_EXPERIMENTAL_ANY 540