libstdc++
experimental/any
Go to the documentation of this file.
1 // <experimental/any> -*- C++ -*-
2 
3 // Copyright (C) 2014-2020 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 <utility>
40 #include <type_traits>
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;
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>
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");
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,
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,
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>
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.
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
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:101
bool empty() const noexcept
Reports whether there is a contained object or not.
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition: type_traits:2554
enable_if_t<!is_same< any, decay_t< _ValueType > >::value, any & > operator=(_ValueType &&__rhs)
Store a copy of __rhs as the contained object.
typename remove_cv< _Tp >::type remove_cv_t
Alias template for remove_cv.
Definition: type_traits:1574
virtual const char * what() const noexcept
any() noexcept
Default constructor, creates an empty object.
any & operator=(any &&__rhs) noexcept
Move assignment operator.
Exception class thrown by a failed any_cast.
_ValueType any_cast(const any &__any)
Access the contained object.
Define a member typedef type only if a boolean constant is true.
Definition: type_traits:2182
Alignment type.
Definition: type_traits:2069
is_copy_constructible
Definition: type_traits:936
any & operator=(const any &__rhs)
Copy the state of another object.
is_same
Definition: type_traits:582
typename remove_reference< _Tp >::type remove_reference_t
Alias template for remove_reference.
Definition: type_traits:1635
any(const any &__other)
Copy constructor, copies the state of __other.
typename add_const< _Tp >::type add_const_t
Alias template for add_const.
Definition: type_traits:1578
~any()
Destructor, calls clear()
A type-safe container of any type.
Part of RTTI.
Definition: typeinfo:88
any(_ValueType &&__value)
Construct with a copy of __value as the contained object.
any(any &&__other) noexcept
Move constructor, transfer the state from __other.
is_lvalue_reference
Definition: type_traits:426
typename conditional< _Cond, _Iftrue, _Iffalse >::type conditional_t
Alias template for conditional.
Definition: type_traits:2558
void swap(any &__rhs) noexcept
Exchange state with another object.
const type_info & type() const noexcept
The typeid of the contained object, or typeid(void) if empty.
void clear() noexcept
If not empty, destroy the contained object.
Thrown during incorrect typecasting.If you attempt an invalid dynamic_cast expression, an instance of this class (or something derived from this class) is thrown.
Definition: typeinfo:190
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition: move.h:76