libstdc++
experimental/any
Go to the documentation of this file.
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>
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47namespace experimental
48{
49inline 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));
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);
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");
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,
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.
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
typename remove_cv< _Tp >::type remove_cv_t
Alias template for remove_cv.
Definition type_traits:1609
typename enable_if< _Cond, _Tp >::type enable_if_t
Alias template for enable_if.
Definition type_traits:2614
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:104
_ValueType any_cast(const any &__any)
Access the contained object.
void swap(any &__x, any &__y) noexcept
Exchange the states of two any objects.
ISO C++ entities toplevel namespace is std.
Part of RTTI.
Definition typeinfo:93
Thrown during incorrect typecasting.
Definition typeinfo:221
A type-safe container of any type.
Definition any:81
is_lvalue_reference
Definition type_traits:477
is_copy_constructible
Definition type_traits:1011
Alignment type.
Definition type_traits:2114
Define a member typedef type only if a boolean constant is true.
Definition type_traits:2229
Exception class thrown by a failed any_cast.
virtual const char * what() const noexcept
A type-safe container of any type.
bool empty() const noexcept
Reports whether there is a contained object or not.
any(const any &__other)
Copy constructor, copies the state of __other.
any(any &&__other) noexcept
Move constructor, transfer the state from __other.
any & operator=(any &&__rhs) noexcept
Move assignment operator.
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.
any() noexcept
Default constructor, creates an empty object.
void swap(any &__rhs) noexcept
Exchange state with another object.
any & operator=(const any &__rhs)
Copy the state of another object.
any(_ValueType &&__value)
Construct with a copy of __value as the contained object.
enable_if_t<!is_same< any, decay_t< _ValueType > >::value, any & > operator=(_ValueType &&__rhs)
Store a copy of __rhs as the contained object.