Home | History | Annotate | Line # | Download | only in experimental
      1 // <experimental/any> -*- C++ -*-
      2 
      3 // Copyright (C) 2014-2022 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  *  @ingroup libfund-ts
     28  */
     29 
     30 #ifndef _GLIBCXX_EXPERIMENTAL_ANY
     31 #define _GLIBCXX_EXPERIMENTAL_ANY 1
     32 
     33 #pragma GCC system_header
     34 
     35 #if __cplusplus >= 201402L
     36 
     37 #include <typeinfo>
     38 #include <new>
     39 #include <type_traits>
     40 #include <bits/move.h>
     41 #include <experimental/bits/lfts_config.h>
     42 
     43 namespace std _GLIBCXX_VISIBILITY(default)
     44 {
     45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     46 
     47 namespace experimental
     48 {
     49 inline namespace fundamentals_v1
     50 {
     51   /**
     52    * @defgroup any Type-safe container of any type
     53    * @ingroup libfund-ts
     54    *
     55    * A type-safe container for single values of value types, as
     56    * described in n3804 "Any Library Proposal (Revision 3)".
     57    *
     58    * @{
     59    */
     60 
     61 #define __cpp_lib_experimental_any 201411
     62 
     63   /**
     64    *  @brief Exception class thrown by a failed @c any_cast
     65    *  @ingroup exceptions
     66    */
     67   class bad_any_cast : public bad_cast
     68   {
     69   public:
     70     virtual const char* what() const noexcept { return "bad any_cast"; }
     71   };
     72 
     73   /// @cond undocumented
     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   /// @endcond
     83 
     84   /**
     85    *  @brief A type-safe container of any type.
     86    * 
     87    *  An @c any object's state is either empty or it stores a contained object
     88    *  of CopyConstructible type.
     89    */
     90   class any
     91   {
     92     // Holds either pointer to a heap object or the contained object itself.
     93     union _Storage
     94     {
     95       // This constructor intentionally doesn't initialize anything.
     96       _Storage() = default;
     97 
     98       // Prevent trivial copies of this type, buffer might hold a non-POD.
     99       _Storage(const _Storage&) = delete;
    100       _Storage& operator=(const _Storage&) = delete;
    101 
    102       void* _M_ptr;
    103       aligned_storage<sizeof(_M_ptr), alignof(void*)>::type _M_buffer;
    104     };
    105 
    106     template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
    107 	     bool _Fits = (sizeof(_Tp) <= sizeof(_Storage))
    108 			  && (alignof(_Tp) <= alignof(_Storage))>
    109       using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
    110 
    111     template<typename _Tp>
    112       struct _Manager_internal; // uses small-object optimization
    113 
    114     template<typename _Tp>
    115       struct _Manager_external; // creates contained object on the heap
    116 
    117     template<typename _Tp>
    118       using _Manager = __conditional_t<_Internal<_Tp>::value,
    119 				       _Manager_internal<_Tp>,
    120 				       _Manager_external<_Tp>>;
    121 
    122     template<typename _Tp, typename _Decayed = decay_t<_Tp>>
    123       using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>;
    124 
    125   public:
    126     // construct/destruct
    127 
    128     /// Default constructor, creates an empty object.
    129     any() noexcept : _M_manager(nullptr) { }
    130 
    131     /// Copy constructor, copies the state of @p __other
    132     any(const any& __other)
    133     {
    134       if (__other.empty())
    135 	_M_manager = nullptr;
    136       else
    137 	{
    138 	  _Arg __arg;
    139 	  __arg._M_any = this;
    140 	  __other._M_manager(_Op_clone, &__other, &__arg);
    141 	}
    142     }
    143 
    144     /**
    145      * @brief Move constructor, transfer the state from @p __other
    146      *
    147      * @post @c __other.empty() (this postcondition is a GNU extension)
    148      */
    149     any(any&& __other) noexcept
    150     {
    151       if (__other.empty())
    152 	_M_manager = nullptr;
    153       else
    154 	{
    155 	  _Arg __arg;
    156 	  __arg._M_any = this;
    157 	  __other._M_manager(_Op_xfer, &__other, &__arg);
    158 	}
    159     }
    160 
    161     /// Construct with a copy of @p __value as the contained object.
    162     template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
    163 	      typename _Mgr = _Manager<_Tp>,
    164               typename enable_if<is_constructible<_Tp, _ValueType&&>::value,
    165                                  bool>::type = true>
    166       any(_ValueType&& __value)
    167       : _M_manager(&_Mgr::_S_manage)
    168       {
    169         _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value));
    170 	static_assert(is_copy_constructible<_Tp>::value,
    171 		      "The contained object must be CopyConstructible");
    172       }
    173 
    174     /// Construct with a copy of @p __value as the contained object.
    175     template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
    176 	      typename _Mgr = _Manager<_Tp>,
    177               typename enable_if<!is_constructible<_Tp, _ValueType&&>::value,
    178                                  bool>::type = false>
    179       any(_ValueType&& __value)
    180       : _M_manager(&_Mgr::_S_manage)
    181       {
    182         _Mgr::_S_create(_M_storage, __value);
    183 	static_assert(is_copy_constructible<_Tp>::value,
    184 		      "The contained object must be CopyConstructible");
    185       }
    186 
    187     /// Destructor, calls @c clear()
    188     ~any() { clear(); }
    189 
    190     // assignments
    191 
    192     /// Copy the state of another object.
    193     any& operator=(const any& __rhs)
    194     {
    195       *this = any(__rhs);
    196       return *this;
    197     }
    198 
    199     /**
    200      * @brief Move assignment operator
    201      *
    202      * @post @c __rhs.empty() (not guaranteed for other implementations)
    203      */
    204     any& operator=(any&& __rhs) noexcept
    205     {
    206       if (__rhs.empty())
    207 	clear();
    208       else if (this != &__rhs)
    209 	{
    210 	  clear();
    211 	  _Arg __arg;
    212 	  __arg._M_any = this;
    213 	  __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
    214 	}
    215       return *this;
    216     }
    217 
    218     /// Store a copy of @p __rhs as the contained object.
    219     template<typename _ValueType>
    220       enable_if_t<!is_same<any, decay_t<_ValueType>>::value, any&>
    221       operator=(_ValueType&& __rhs)
    222       {
    223 	*this = any(std::forward<_ValueType>(__rhs));
    224 	return *this;
    225       }
    226 
    227     // modifiers
    228 
    229     /// If not empty, destroy the contained object.
    230     void clear() noexcept
    231     {
    232       if (!empty())
    233       {
    234 	_M_manager(_Op_destroy, this, nullptr);
    235 	_M_manager = nullptr;
    236       }
    237     }
    238 
    239     /// Exchange state with another object.
    240     void swap(any& __rhs) noexcept
    241     {
    242       if (empty() && __rhs.empty())
    243 	return;
    244 
    245       if (!empty() && !__rhs.empty())
    246 	{
    247 	  if (this == &__rhs)
    248 	    return;
    249 
    250 	  any __tmp;
    251 	  _Arg __arg;
    252 	  __arg._M_any = &__tmp;
    253 	  __rhs._M_manager(_Op_xfer, &__rhs, &__arg);
    254 	  __arg._M_any = &__rhs;
    255 	  _M_manager(_Op_xfer, this, &__arg);
    256 	  __arg._M_any = this;
    257 	  __tmp._M_manager(_Op_xfer, &__tmp, &__arg);
    258 	}
    259       else
    260 	{
    261 	  any* __empty = empty() ? this : &__rhs;
    262 	  any* __full = empty() ? &__rhs : this;
    263 	  _Arg __arg;
    264 	  __arg._M_any = __empty;
    265 	  __full->_M_manager(_Op_xfer, __full, &__arg);
    266 	}
    267     }
    268 
    269     // observers
    270 
    271     /// Reports whether there is a contained object or not.
    272     _GLIBCXX_NODISCARD bool empty() const noexcept { return _M_manager == nullptr; }
    273 
    274 #if __cpp_rtti
    275     /// The @c typeid of the contained object, or @c typeid(void) if empty.
    276     const type_info& type() const noexcept
    277     {
    278       if (empty())
    279 	return typeid(void);
    280       _Arg __arg;
    281       _M_manager(_Op_get_type_info, this, &__arg);
    282       return *__arg._M_typeinfo;
    283     }
    284 #endif
    285 
    286     template<typename _Tp>
    287       static constexpr bool __is_valid_cast()
    288       { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; }
    289 
    290   private:
    291     enum _Op {
    292 	_Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer
    293     };
    294 
    295     union _Arg
    296     {
    297 	void* _M_obj;
    298 	const std::type_info* _M_typeinfo;
    299 	any* _M_any;
    300     };
    301 
    302     void (*_M_manager)(_Op, const any*, _Arg*);
    303     _Storage _M_storage;
    304 
    305     template<typename _Tp>
    306       friend enable_if_t<is_object<_Tp>::value, void*>
    307       __any_caster(const any* __any);
    308 
    309     // Manage in-place contained object.
    310     template<typename _Tp>
    311       struct _Manager_internal
    312       {
    313 	static void
    314 	_S_manage(_Op __which, const any* __anyp, _Arg* __arg);
    315 
    316 	template<typename _Up>
    317 	  static void
    318 	  _S_create(_Storage& __storage, _Up&& __value)
    319 	  {
    320 	    void* __addr = &__storage._M_buffer;
    321 	    ::new (__addr) _Tp(std::forward<_Up>(__value));
    322 	  }
    323       };
    324 
    325     // Manage external contained object.
    326     template<typename _Tp>
    327       struct _Manager_external
    328       {
    329 	static void
    330 	_S_manage(_Op __which, const any* __anyp, _Arg* __arg);
    331 
    332 	template<typename _Up>
    333 	  static void
    334 	  _S_create(_Storage& __storage, _Up&& __value)
    335 	  {
    336 	    __storage._M_ptr = new _Tp(std::forward<_Up>(__value));
    337 	  }
    338       };
    339   };
    340 
    341   /// Exchange the states of two @c any objects.
    342   inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); }
    343 
    344   /**
    345    * @brief Access the contained object.
    346    *
    347    * @tparam  _ValueType  A const-reference or CopyConstructible type.
    348    * @param   __any       The object to access.
    349    * @return  The contained object.
    350    * @throw   bad_any_cast If <code>
    351    *          __any.type() != typeid(remove_reference_t<_ValueType>)
    352    *          </code>
    353    */
    354   template<typename _ValueType>
    355     inline _ValueType any_cast(const any& __any)
    356     {
    357       static_assert(any::__is_valid_cast<_ValueType>(),
    358 	  "Template argument must be a reference or CopyConstructible type");
    359       auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any);
    360       if (__p)
    361 	return *__p;
    362       __throw_bad_any_cast();
    363     }
    364 
    365   /**
    366    * @brief Access the contained object.
    367    *
    368    * @tparam  _ValueType  A reference or CopyConstructible type.
    369    * @param   __any       The object to access.
    370    * @return  The contained object.
    371    * @throw   bad_any_cast If <code>
    372    *          __any.type() != typeid(remove_reference_t<_ValueType>)
    373    *          </code>
    374    *
    375    * @{
    376    */
    377   template<typename _ValueType>
    378     inline _ValueType any_cast(any& __any)
    379     {
    380       static_assert(any::__is_valid_cast<_ValueType>(),
    381 	  "Template argument must be a reference or CopyConstructible type");
    382       auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
    383       if (__p)
    384 	return *__p;
    385       __throw_bad_any_cast();
    386     }
    387 
    388   template<typename _ValueType,
    389            typename enable_if<!is_move_constructible<_ValueType>::value
    390                               || is_lvalue_reference<_ValueType>::value,
    391                               bool>::type = true>
    392     inline _ValueType any_cast(any&& __any)
    393     {
    394       static_assert(any::__is_valid_cast<_ValueType>(),
    395 	  "Template argument must be a reference or CopyConstructible type");
    396       auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
    397       if (__p)
    398 	return *__p;
    399       __throw_bad_any_cast();
    400     }
    401 
    402   template<typename _ValueType,
    403            typename enable_if<is_move_constructible<_ValueType>::value
    404                               && !is_lvalue_reference<_ValueType>::value,
    405                               bool>::type = false>
    406     inline _ValueType any_cast(any&& __any)
    407     {
    408       static_assert(any::__is_valid_cast<_ValueType>(),
    409 	  "Template argument must be a reference or CopyConstructible type");
    410       auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
    411       if (__p)
    412 	return std::move(*__p);
    413       __throw_bad_any_cast();
    414     }
    415   /// @}
    416 
    417   /// @cond undocumented
    418   template<typename _Tp>
    419     enable_if_t<is_object<_Tp>::value, void*>
    420     __any_caster(const any* __any)
    421     {
    422       // any_cast<T> returns non-null if __any->type() == typeid(T) and
    423       // typeid(T) ignores cv-qualifiers so remove them:
    424       using _Up = remove_cv_t<_Tp>;
    425       // The contained value has a decayed type, so if decay_t<U> is not U,
    426       // then it's not possible to have a contained value of type U.
    427       using __does_not_decay = is_same<decay_t<_Up>, _Up>;
    428       // Only copy constructible types can be used for contained values.
    429       using __is_copyable = is_copy_constructible<_Up>;
    430       // If the type _Tp could never be stored in an any we don't want to
    431       // instantiate _Manager<_Tp>, so use _Manager<any::_Op> instead, which
    432       // is explicitly specialized and has a no-op _S_manage function.
    433       using _Vp = __conditional_t<__and_<__does_not_decay, __is_copyable>{},
    434 				  _Up, any::_Op>;
    435       // First try comparing function addresses, which works without RTTI
    436       if (__any->_M_manager == &any::_Manager<_Vp>::_S_manage
    437 #if __cpp_rtti
    438 	  || __any->type() == typeid(_Tp)
    439 #endif
    440 	  )
    441 	{
    442 	  any::_Arg __arg;
    443 	  __any->_M_manager(any::_Op_access, __any, &__arg);
    444 	  return __arg._M_obj;
    445 	}
    446       return nullptr;
    447     }
    448 
    449   // This overload exists so that std::any_cast<void(*)()>(a) is well-formed.
    450   template<typename _Tp>
    451     enable_if_t<!is_object<_Tp>::value, _Tp*>
    452     __any_caster(const any*) noexcept
    453     { return nullptr; }
    454   /// @endcond
    455 
    456   /**
    457    * @brief Access the contained object.
    458    *
    459    * @tparam  _ValueType  The type of the contained object.
    460    * @param   __any       A pointer to the object to access.
    461    * @return  The address of the contained object if <code>
    462    *          __any != nullptr && __any.type() == typeid(_ValueType)
    463    *          </code>, otherwise a null pointer.
    464    *
    465    * @{
    466    */
    467   template<typename _ValueType>
    468     inline const _ValueType* any_cast(const any* __any) noexcept
    469     {
    470       if (__any)
    471 	return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
    472       return nullptr;
    473     }
    474 
    475   template<typename _ValueType>
    476     inline _ValueType* any_cast(any* __any) noexcept
    477     {
    478       if (__any)
    479 	return static_cast<_ValueType*>(__any_caster<_ValueType>(__any));
    480       return nullptr;
    481     }
    482   /// @}
    483 
    484   template<typename _Tp>
    485     void
    486     any::_Manager_internal<_Tp>::
    487     _S_manage(_Op __which, const any* __any, _Arg* __arg)
    488     {
    489       // The contained object is in _M_storage._M_buffer
    490       auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer);
    491       switch (__which)
    492       {
    493       case _Op_access:
    494 	__arg->_M_obj = const_cast<_Tp*>(__ptr);
    495 	break;
    496       case _Op_get_type_info:
    497 #if __cpp_rtti
    498 	__arg->_M_typeinfo = &typeid(_Tp);
    499 #endif
    500 	break;
    501       case _Op_clone:
    502 	::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
    503 	__arg->_M_any->_M_manager = __any->_M_manager;
    504 	break;
    505       case _Op_destroy:
    506 	__ptr->~_Tp();
    507 	break;
    508       case _Op_xfer:
    509 	::new(&__arg->_M_any->_M_storage._M_buffer) _Tp
    510 	  (std::move(*const_cast<_Tp*>(__ptr)));
    511 	__ptr->~_Tp();
    512 	__arg->_M_any->_M_manager = __any->_M_manager;
    513 	const_cast<any*>(__any)->_M_manager = nullptr;
    514 	break;
    515       }
    516     }
    517 
    518   template<typename _Tp>
    519     void
    520     any::_Manager_external<_Tp>::
    521     _S_manage(_Op __which, const any* __any, _Arg* __arg)
    522     {
    523       // The contained object is *_M_storage._M_ptr
    524       auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr);
    525       switch (__which)
    526       {
    527       case _Op_access:
    528 	__arg->_M_obj = const_cast<_Tp*>(__ptr);
    529 	break;
    530       case _Op_get_type_info:
    531 #if __cpp_rtti
    532 	__arg->_M_typeinfo = &typeid(_Tp);
    533 #endif
    534 	break;
    535       case _Op_clone:
    536 	__arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr);
    537 	__arg->_M_any->_M_manager = __any->_M_manager;
    538 	break;
    539       case _Op_destroy:
    540 	delete __ptr;
    541 	break;
    542       case _Op_xfer:
    543 	__arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr;
    544 	__arg->_M_any->_M_manager = __any->_M_manager;
    545 	const_cast<any*>(__any)->_M_manager = nullptr;
    546 	break;
    547       }
    548     }
    549 
    550   // Dummy specialization used by __any_caster.
    551   template<>
    552     struct any::_Manager_internal<any::_Op>
    553     {
    554       static void
    555       _S_manage(_Op, const any*, _Arg*) { }
    556     };
    557 
    558   /// @} group any
    559 } // namespace fundamentals_v1
    560 } // namespace experimental
    561 
    562 _GLIBCXX_END_NAMESPACE_VERSION
    563 } // namespace std
    564 
    565 #endif // C++14
    566 
    567 #endif // _GLIBCXX_EXPERIMENTAL_ANY
    568