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