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>
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>::value,
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