]>
Commit | Line | Data |
---|---|---|
74b21c65 | 1 | // <experimental/any> -*- C++ -*- |
2 | ||
f1717362 | 3 | // Copyright (C) 2014-2016 Free Software Foundation, Inc. |
74b21c65 | 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 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_EXPERIMENTAL_ANY | |
30 | #define _GLIBCXX_EXPERIMENTAL_ANY 1 | |
31 | ||
32 | #pragma GCC system_header | |
33 | ||
34 | #if __cplusplus <= 201103L | |
35 | # include <bits/c++14_warning.h> | |
36 | #else | |
37 | ||
38 | #include <typeinfo> | |
82fe3c60 | 39 | #include <new> |
74b21c65 | 40 | #include <utility> |
41 | #include <type_traits> | |
74b21c65 | 42 | |
43 | namespace std _GLIBCXX_VISIBILITY(default) | |
44 | { | |
45 | namespace experimental | |
46 | { | |
0a394876 | 47 | inline namespace fundamentals_v1 |
74b21c65 | 48 | { |
49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
50 | ||
51 | /** | |
52 | * @defgroup any Type-safe container of any type | |
53 | * @ingroup experimental | |
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 | ||
82fe3c60 | 61 | #define __cpp_lib_experimental_any 201411 |
a5118bd7 | 62 | |
74b21c65 | 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: | |
0a394876 | 70 | virtual const char* what() const noexcept { return "bad any_cast"; } |
74b21c65 | 71 | }; |
72 | ||
73 | [[gnu::noreturn]] inline void __throw_bad_any_cast() | |
74 | { | |
0fcfaa33 | 75 | #if __cpp_exceptions |
74b21c65 | 76 | throw bad_any_cast{}; |
77 | #else | |
78 | __builtin_abort(); | |
79 | #endif | |
80 | } | |
81 | ||
82 | /** | |
8787f26b | 83 | * @brief A type-safe container of any type. |
84 | * | |
85 | * An @c any object's state is either empty or it stores a contained object | |
86 | * of CopyConstructible type. | |
87 | */ | |
74b21c65 | 88 | class any |
89 | { | |
90 | // Holds either pointer to a heap object or the contained object itself. | |
91 | union _Storage | |
92 | { | |
e6f39ac0 | 93 | // This constructor intentionally doesn't initialize anything. |
94 | _Storage() = default; | |
95 | ||
96 | // Prevent trivial copies of this type, buffer might hold a non-POD. | |
97 | _Storage(const _Storage&) = delete; | |
98 | _Storage& operator=(const _Storage&) = delete; | |
99 | ||
74b21c65 | 100 | void* _M_ptr; |
82bc5f13 | 101 | aligned_storage<sizeof(_M_ptr), alignof(void*)>::type _M_buffer; |
74b21c65 | 102 | }; |
103 | ||
82fe3c60 | 104 | template<typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>, |
82bc5f13 | 105 | bool _Fits = (sizeof(_Tp) <= sizeof(_Storage)) |
106 | && (alignof(_Tp) <= alignof(_Storage))> | |
74b21c65 | 107 | using _Internal = std::integral_constant<bool, _Safe::value && _Fits>; |
108 | ||
109 | template<typename _Tp> | |
110 | struct _Manager_internal; // uses small-object optimization | |
111 | ||
112 | template<typename _Tp> | |
113 | struct _Manager_external; // creates contained object on the heap | |
114 | ||
115 | template<typename _Tp> | |
116 | using _Manager = conditional_t<_Internal<_Tp>::value, | |
117 | _Manager_internal<_Tp>, | |
118 | _Manager_external<_Tp>>; | |
119 | ||
74b21c65 | 120 | template<typename _Tp, typename _Decayed = decay_t<_Tp>> |
121 | using _Decay = enable_if_t<!is_same<_Decayed, any>::value, _Decayed>; | |
122 | ||
123 | public: | |
124 | // construct/destruct | |
125 | ||
126 | /// Default constructor, creates an empty object. | |
127 | any() noexcept : _M_manager(nullptr) { } | |
128 | ||
129 | /// Copy constructor, copies the state of @p __other | |
e6f39ac0 | 130 | any(const any& __other) |
74b21c65 | 131 | { |
e6f39ac0 | 132 | if (__other.empty()) |
133 | _M_manager = nullptr; | |
134 | else | |
74b21c65 | 135 | { |
136 | _Arg __arg; | |
137 | __arg._M_any = this; | |
e6f39ac0 | 138 | __other._M_manager(_Op_clone, &__other, &__arg); |
74b21c65 | 139 | } |
140 | } | |
141 | ||
142 | /** | |
143 | * @brief Move constructor, transfer the state from @p __other | |
144 | * | |
e6f39ac0 | 145 | * @post @c __other.empty() (this postcondition is a GNU extension) |
74b21c65 | 146 | */ |
147 | any(any&& __other) noexcept | |
e6f39ac0 | 148 | { |
149 | if (__other.empty()) | |
150 | _M_manager = nullptr; | |
151 | else | |
152 | { | |
153 | _Arg __arg; | |
154 | __arg._M_any = this; | |
155 | __other._M_manager(_Op_xfer, &__other, &__arg); | |
156 | } | |
157 | } | |
74b21c65 | 158 | |
159 | /// Construct with a copy of @p __value as the contained object. | |
160 | template <typename _ValueType, typename _Tp = _Decay<_ValueType>, | |
161 | typename _Mgr = _Manager<_Tp>> | |
162 | any(_ValueType&& __value) | |
e6f39ac0 | 163 | : _M_manager(&_Mgr::_S_manage) |
74b21c65 | 164 | { |
e6f39ac0 | 165 | _Mgr::_S_create(_M_storage, std::forward<_ValueType>(__value)); |
74b21c65 | 166 | static_assert(is_copy_constructible<_Tp>::value, |
167 | "The contained object must be CopyConstructible"); | |
168 | } | |
169 | ||
74b21c65 | 170 | /// Destructor, calls @c clear() |
171 | ~any() { clear(); } | |
172 | ||
173 | // assignments | |
174 | ||
e6f39ac0 | 175 | /// Copy the state of another object. |
74b21c65 | 176 | any& operator=(const any& __rhs) |
177 | { | |
e6f39ac0 | 178 | if (__rhs.empty()) |
179 | clear(); | |
70d02607 | 180 | else if (this != &__rhs) |
e6f39ac0 | 181 | { |
182 | if (!empty()) | |
183 | _M_manager(_Op_destroy, this, nullptr); | |
184 | _Arg __arg; | |
185 | __arg._M_any = this; | |
186 | __rhs._M_manager(_Op_clone, &__rhs, &__arg); | |
187 | } | |
74b21c65 | 188 | return *this; |
189 | } | |
190 | ||
191 | /** | |
192 | * @brief Move assignment operator | |
193 | * | |
194 | * @post @c __rhs.empty() (not guaranteed for other implementations) | |
195 | */ | |
196 | any& operator=(any&& __rhs) noexcept | |
197 | { | |
e6f39ac0 | 198 | if (__rhs.empty()) |
199 | clear(); | |
70d02607 | 200 | else if (this != &__rhs) |
e6f39ac0 | 201 | { |
202 | if (!empty()) | |
203 | _M_manager(_Op_destroy, this, nullptr); | |
204 | _Arg __arg; | |
205 | __arg._M_any = this; | |
206 | __rhs._M_manager(_Op_xfer, &__rhs, &__arg); | |
207 | } | |
74b21c65 | 208 | return *this; |
209 | } | |
210 | ||
211 | /// Store a copy of @p __rhs as the contained object. | |
212 | template<typename _ValueType> | |
70d02607 | 213 | enable_if_t<!is_same<any, decay_t<_ValueType>>::value, any&> |
214 | operator=(_ValueType&& __rhs) | |
74b21c65 | 215 | { |
e6f39ac0 | 216 | *this = any(std::forward<_ValueType>(__rhs)); |
74b21c65 | 217 | return *this; |
218 | } | |
219 | ||
220 | // modifiers | |
221 | ||
222 | /// If not empty, destroy the contained object. | |
223 | void clear() noexcept | |
224 | { | |
225 | if (!empty()) | |
226 | { | |
227 | _M_manager(_Op_destroy, this, nullptr); | |
228 | _M_manager = nullptr; | |
229 | } | |
230 | } | |
231 | ||
232 | /// Exchange state with another object. | |
233 | void swap(any& __rhs) noexcept | |
70d02607 | 234 | { |
235 | if (empty() && __rhs.empty()) | |
236 | return; | |
237 | ||
238 | if (!empty() && !__rhs.empty()) | |
239 | { | |
240 | if (this == &__rhs) | |
241 | return; | |
242 | ||
243 | any __tmp; | |
244 | _Arg __arg; | |
245 | __arg._M_any = &__tmp; | |
246 | __rhs._M_manager(_Op_xfer, &__rhs, &__arg); | |
247 | __arg._M_any = &__rhs; | |
248 | _M_manager(_Op_xfer, this, &__arg); | |
249 | __arg._M_any = this; | |
250 | __tmp._M_manager(_Op_xfer, &__tmp, &__arg); | |
251 | } | |
252 | else | |
253 | { | |
254 | any* __empty = empty() ? this : &__rhs; | |
255 | any* __full = empty() ? &__rhs : this; | |
256 | _Arg __arg; | |
257 | __arg._M_any = __empty; | |
258 | __full->_M_manager(_Op_xfer, __full, &__arg); | |
259 | } | |
260 | } | |
74b21c65 | 261 | |
262 | // observers | |
263 | ||
264 | /// Reports whether there is a contained object or not. | |
265 | bool empty() const noexcept { return _M_manager == nullptr; } | |
266 | ||
0fcfaa33 | 267 | #if __cpp_rtti |
74b21c65 | 268 | /// The @c typeid of the contained object, or @c typeid(void) if empty. |
269 | const type_info& type() const noexcept | |
270 | { | |
271 | if (empty()) | |
272 | return typeid(void); | |
273 | _Arg __arg; | |
274 | _M_manager(_Op_get_type_info, this, &__arg); | |
275 | return *__arg._M_typeinfo; | |
276 | } | |
277 | #endif | |
278 | ||
279 | template<typename _Tp> | |
280 | static constexpr bool __is_valid_cast() | |
281 | { return __or_<is_reference<_Tp>, is_copy_constructible<_Tp>>::value; } | |
282 | ||
283 | private: | |
e6f39ac0 | 284 | enum _Op { |
285 | _Op_access, _Op_get_type_info, _Op_clone, _Op_destroy, _Op_xfer | |
286 | }; | |
74b21c65 | 287 | |
288 | union _Arg | |
289 | { | |
290 | void* _M_obj; | |
291 | const std::type_info* _M_typeinfo; | |
292 | any* _M_any; | |
293 | }; | |
294 | ||
295 | void (*_M_manager)(_Op, const any*, _Arg*); | |
296 | _Storage _M_storage; | |
297 | ||
298 | template<typename _Tp> | |
4db9cc57 | 299 | friend void* __any_caster(const any* __any); |
74b21c65 | 300 | |
301 | // Manage in-place contained object. | |
302 | template<typename _Tp> | |
303 | struct _Manager_internal | |
304 | { | |
305 | static void | |
306 | _S_manage(_Op __which, const any* __anyp, _Arg* __arg); | |
307 | ||
308 | template<typename _Up> | |
e6f39ac0 | 309 | static void |
310 | _S_create(_Storage& __storage, _Up&& __value) | |
74b21c65 | 311 | { |
74b21c65 | 312 | void* __addr = &__storage._M_buffer; |
313 | ::new (__addr) _Tp(std::forward<_Up>(__value)); | |
74b21c65 | 314 | } |
315 | }; | |
316 | ||
317 | // Manage external contained object. | |
318 | template<typename _Tp> | |
319 | struct _Manager_external | |
320 | { | |
321 | static void | |
322 | _S_manage(_Op __which, const any* __anyp, _Arg* __arg); | |
323 | ||
324 | template<typename _Up> | |
e6f39ac0 | 325 | static void |
326 | _S_create(_Storage& __storage, _Up&& __value) | |
74b21c65 | 327 | { |
74b21c65 | 328 | __storage._M_ptr = new _Tp(std::forward<_Up>(__value)); |
74b21c65 | 329 | } |
330 | }; | |
74b21c65 | 331 | }; |
332 | ||
333 | /// Exchange the states of two @c any objects. | |
334 | inline void swap(any& __x, any& __y) noexcept { __x.swap(__y); } | |
335 | ||
336 | /** | |
337 | * @brief Access the contained object. | |
338 | * | |
339 | * @tparam _ValueType A const-reference or CopyConstructible type. | |
340 | * @param __any The object to access. | |
341 | * @return The contained object. | |
342 | * @throw bad_any_cast If <code> | |
343 | * __any.type() != typeid(remove_reference_t<_ValueType>) | |
344 | * </code> | |
345 | */ | |
346 | template<typename _ValueType> | |
347 | inline _ValueType any_cast(const any& __any) | |
348 | { | |
349 | static_assert(any::__is_valid_cast<_ValueType>(), | |
350 | "Template argument must be a reference or CopyConstructible type"); | |
351 | auto __p = any_cast<add_const_t<remove_reference_t<_ValueType>>>(&__any); | |
352 | if (__p) | |
353 | return *__p; | |
354 | __throw_bad_any_cast(); | |
355 | } | |
356 | ||
357 | /** | |
358 | * @brief Access the contained object. | |
359 | * | |
360 | * @tparam _ValueType A reference or CopyConstructible type. | |
361 | * @param __any The object to access. | |
362 | * @return The contained object. | |
363 | * @throw bad_any_cast If <code> | |
364 | * __any.type() != typeid(remove_reference_t<_ValueType>) | |
365 | * </code> | |
8787f26b | 366 | * |
367 | * @{ | |
74b21c65 | 368 | */ |
369 | template<typename _ValueType> | |
370 | inline _ValueType any_cast(any& __any) | |
371 | { | |
372 | static_assert(any::__is_valid_cast<_ValueType>(), | |
373 | "Template argument must be a reference or CopyConstructible type"); | |
374 | auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); | |
375 | if (__p) | |
376 | return *__p; | |
377 | __throw_bad_any_cast(); | |
378 | } | |
379 | ||
74b21c65 | 380 | template<typename _ValueType> |
381 | inline _ValueType any_cast(any&& __any) | |
382 | { | |
383 | static_assert(any::__is_valid_cast<_ValueType>(), | |
384 | "Template argument must be a reference or CopyConstructible type"); | |
385 | auto __p = any_cast<remove_reference_t<_ValueType>>(&__any); | |
386 | if (__p) | |
387 | return *__p; | |
388 | __throw_bad_any_cast(); | |
389 | } | |
8787f26b | 390 | // @} |
74b21c65 | 391 | |
4db9cc57 | 392 | template<typename _Tp> |
393 | void* __any_caster(const any* __any) | |
394 | { | |
395 | if (__any->_M_manager != &any::_Manager<decay_t<_Tp>>::_S_manage) | |
396 | return nullptr; | |
397 | any::_Arg __arg; | |
398 | __any->_M_manager(any::_Op_access, __any, &__arg); | |
399 | return __arg._M_obj; | |
400 | } | |
401 | ||
74b21c65 | 402 | /** |
403 | * @brief Access the contained object. | |
404 | * | |
405 | * @tparam _ValueType The type of the contained object. | |
406 | * @param __any A pointer to the object to access. | |
407 | * @return The address of the contained object if <code> | |
408 | * __any != nullptr && __any.type() == typeid(_ValueType) | |
409 | * </code>, otherwise a null pointer. | |
8787f26b | 410 | * |
411 | * @{ | |
74b21c65 | 412 | */ |
413 | template<typename _ValueType> | |
414 | inline const _ValueType* any_cast(const any* __any) noexcept | |
415 | { | |
416 | if (__any) | |
417 | return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); | |
418 | return nullptr; | |
419 | } | |
420 | ||
74b21c65 | 421 | template<typename _ValueType> |
422 | inline _ValueType* any_cast(any* __any) noexcept | |
423 | { | |
424 | if (__any) | |
425 | return static_cast<_ValueType*>(__any_caster<_ValueType>(__any)); | |
426 | return nullptr; | |
427 | } | |
8787f26b | 428 | // @} |
74b21c65 | 429 | |
74b21c65 | 430 | template<typename _Tp> |
431 | void | |
432 | any::_Manager_internal<_Tp>:: | |
433 | _S_manage(_Op __which, const any* __any, _Arg* __arg) | |
434 | { | |
435 | // The contained object is in _M_storage._M_buffer | |
436 | auto __ptr = reinterpret_cast<const _Tp*>(&__any->_M_storage._M_buffer); | |
437 | switch (__which) | |
438 | { | |
439 | case _Op_access: | |
440 | __arg->_M_obj = const_cast<_Tp*>(__ptr); | |
441 | break; | |
442 | case _Op_get_type_info: | |
0fcfaa33 | 443 | #if __cpp_rtti |
74b21c65 | 444 | __arg->_M_typeinfo = &typeid(_Tp); |
445 | #endif | |
446 | break; | |
447 | case _Op_clone: | |
448 | ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); | |
e6f39ac0 | 449 | __arg->_M_any->_M_manager = __any->_M_manager; |
74b21c65 | 450 | break; |
451 | case _Op_destroy: | |
452 | __ptr->~_Tp(); | |
453 | break; | |
e6f39ac0 | 454 | case _Op_xfer: |
455 | ::new(&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr); | |
456 | __ptr->~_Tp(); | |
457 | __arg->_M_any->_M_manager = __any->_M_manager; | |
458 | const_cast<any*>(__any)->_M_manager = nullptr; | |
459 | break; | |
74b21c65 | 460 | } |
461 | } | |
462 | ||
463 | template<typename _Tp> | |
464 | void | |
465 | any::_Manager_external<_Tp>:: | |
466 | _S_manage(_Op __which, const any* __any, _Arg* __arg) | |
467 | { | |
468 | // The contained object is *_M_storage._M_ptr | |
469 | auto __ptr = static_cast<const _Tp*>(__any->_M_storage._M_ptr); | |
470 | switch (__which) | |
471 | { | |
472 | case _Op_access: | |
473 | __arg->_M_obj = const_cast<_Tp*>(__ptr); | |
474 | break; | |
475 | case _Op_get_type_info: | |
0fcfaa33 | 476 | #if __cpp_rtti |
74b21c65 | 477 | __arg->_M_typeinfo = &typeid(_Tp); |
478 | #endif | |
479 | break; | |
480 | case _Op_clone: | |
481 | __arg->_M_any->_M_storage._M_ptr = new _Tp(*__ptr); | |
e6f39ac0 | 482 | __arg->_M_any->_M_manager = __any->_M_manager; |
74b21c65 | 483 | break; |
484 | case _Op_destroy: | |
485 | delete __ptr; | |
486 | break; | |
e6f39ac0 | 487 | case _Op_xfer: |
488 | __arg->_M_any->_M_storage._M_ptr = __any->_M_storage._M_ptr; | |
489 | __arg->_M_any->_M_manager = __any->_M_manager; | |
490 | const_cast<any*>(__any)->_M_manager = nullptr; | |
491 | break; | |
74b21c65 | 492 | } |
493 | } | |
494 | ||
74b21c65 | 495 | // @} group any |
496 | _GLIBCXX_END_NAMESPACE_VERSION | |
0a394876 | 497 | } // namespace fundamentals_v1 |
74b21c65 | 498 | } // namespace experimental |
499 | } // namespace std | |
500 | ||
501 | #endif // C++14 | |
502 | ||
503 | #endif // _GLIBCXX_EXPERIMENTAL_ANY |