1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
12 #include <type_traits>
15 namespace std
{ namespace experimental
{} }
17 #include "test_macros.h"
20 #if !defined(TEST_HAS_NO_RTTI)
21 #define RTTI_ASSERT(X) assert(X)
23 #define RTTI_ASSERT(X)
28 : public std::integral_constant
<bool
29 , sizeof(T
) <= sizeof(std::any
) - sizeof(void*)
30 && std::alignment_of
<void*>::value
31 % std::alignment_of
<T
>::value
== 0
32 && std::is_nothrow_move_constructible
<T
>::value
37 bool containsType(std::any
const& a
) {
38 #if !defined(TEST_HAS_NO_RTTI)
39 return a
.type() == typeid(T
);
41 return a
.has_value() && std::any_cast
<T
>(&a
) != nullptr;
45 // Return 'true' if 'Type' will be considered a small type by 'any'
48 return IsSmallObject
<Type
>::value
;
51 // Assert that an object is empty. If the object used to contain an object
52 // of type 'LastType' check that it can no longer be accessed.
53 template <class LastType
= int>
54 void assertEmpty(std::any
const& a
) {
56 assert(!a
.has_value());
57 RTTI_ASSERT(a
.type() == typeid(void));
58 assert(any_cast
<LastType
const>(&a
) == nullptr);
62 constexpr auto has_value_member(int) -> decltype(std::declval
<Type
&>().value
, true)
64 template <class> constexpr bool has_value_member(long) { return false; }
67 // Assert that an 'any' object stores the specified 'Type' and 'value'.
69 std::enable_if_t
<has_value_member
<Type
>(0)>
70 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
71 assertContains(std::any
const& a
, int value
) {
72 assert(a
.has_value());
73 assert(containsType
<Type
>(a
));
74 assert(std::any_cast
<Type
const &>(a
).value
== value
);
77 template <class Type
, class Value
>
78 std::enable_if_t
<!has_value_member
<Type
>(0)>
79 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
80 assertContains(std::any
const& a
, Value value
) {
81 assert(a
.has_value());
82 assert(containsType
<Type
>(a
));
83 assert(std::any_cast
<Type
const &>(a
) == value
);
87 // Modify the value of a "test type" stored within an any to the specified
90 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
91 void modifyValue(std::any
& a
, int value
) {
93 using namespace std::experimental
;
94 assert(a
.has_value());
95 assert(containsType
<Type
>(a
));
96 any_cast
<Type
&>(a
).value
= value
;
99 // A test type that will trigger the small object optimization within 'any'.
100 template <int Dummy
= 0>
106 static int const_copied
;
107 static int non_const_copied
;
109 static void reset() {
110 small_type::copied
= 0;
111 small_type::moved
= 0;
112 small_type::const_copied
= 0;
113 small_type::non_const_copied
= 0;
118 explicit small_type(int val
= 0) : value(val
) {
121 explicit small_type(int, int val
, int) : value(val
) {
124 small_type(std::initializer_list
<int> il
) : value(*il
.begin()) {
128 small_type(small_type
const & other
) noexcept
{
135 small_type(small_type
& other
) noexcept
{
142 small_type(small_type
&& other
) noexcept
{
155 small_type
& operator=(small_type
const&) = delete;
156 small_type
& operator=(small_type
&&) = delete;
160 int small_type
<Dummy
>::count
= 0;
163 int small_type
<Dummy
>::copied
= 0;
166 int small_type
<Dummy
>::moved
= 0;
169 int small_type
<Dummy
>::const_copied
= 0;
172 int small_type
<Dummy
>::non_const_copied
= 0;
174 typedef small_type
<> small
;
175 typedef small_type
<1> small1
;
176 typedef small_type
<2> small2
;
179 // A test type that will NOT trigger the small object optimization in any.
180 template <int Dummy
= 0>
186 static int const_copied
;
187 static int non_const_copied
;
189 static void reset() {
190 large_type::copied
= 0;
191 large_type::moved
= 0;
192 large_type::const_copied
= 0;
193 large_type::non_const_copied
= 0;
198 large_type(int val
= 0) : value(val
) {
202 large_type(int, int val
, int) : value(val
) {
206 large_type(std::initializer_list
<int> il
) : value(*il
.begin()) {
209 large_type(large_type
const & other
) {
216 large_type(large_type
& other
) {
223 large_type(large_type
&& other
) {
236 large_type
& operator=(large_type
const&) = delete;
237 large_type
& operator=(large_type
&&) = delete;
242 int large_type
<Dummy
>::count
= 0;
245 int large_type
<Dummy
>::copied
= 0;
248 int large_type
<Dummy
>::moved
= 0;
251 int large_type
<Dummy
>::const_copied
= 0;
254 int large_type
<Dummy
>::non_const_copied
= 0;
256 typedef large_type
<> large
;
257 typedef large_type
<1> large1
;
258 typedef large_type
<2> large2
;
260 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
261 // and 'throws_on_move'.
262 struct my_any_exception
{};
264 void throwMyAnyExpression() {
265 #if !defined(TEST_HAS_NO_EXCEPTIONS)
266 throw my_any_exception();
268 assert(false && "Exceptions are disabled");
272 // A test type that will trigger the small object optimization within 'any'.
273 // this type throws if it is copied.
274 struct small_throws_on_copy
279 static void reset() { count
= copied
= moved
= 0; }
282 explicit small_throws_on_copy(int val
= 0) : value(val
) {
285 explicit small_throws_on_copy(int, int val
, int) : value(val
) {
288 small_throws_on_copy(small_throws_on_copy
const &) {
289 throwMyAnyExpression();
292 small_throws_on_copy(small_throws_on_copy
&& other
) throw() {
297 ~small_throws_on_copy() {
301 small_throws_on_copy
& operator=(small_throws_on_copy
const&) = delete;
302 small_throws_on_copy
& operator=(small_throws_on_copy
&&) = delete;
305 int small_throws_on_copy::count
= 0;
306 int small_throws_on_copy::copied
= 0;
307 int small_throws_on_copy::moved
= 0;
310 // A test type that will NOT trigger the small object optimization within 'any'.
311 // this type throws if it is copied.
312 struct large_throws_on_copy
317 static void reset() { count
= copied
= moved
= 0; }
320 explicit large_throws_on_copy(int val
= 0) : value(val
) {
324 explicit large_throws_on_copy(int, int val
, int) : value(val
) {
328 large_throws_on_copy(large_throws_on_copy
const &) {
329 throwMyAnyExpression();
332 large_throws_on_copy(large_throws_on_copy
&& other
) throw() {
337 ~large_throws_on_copy() {
342 large_throws_on_copy
& operator=(large_throws_on_copy
const&) = delete;
343 large_throws_on_copy
& operator=(large_throws_on_copy
&&) = delete;
347 int large_throws_on_copy::count
= 0;
348 int large_throws_on_copy::copied
= 0;
349 int large_throws_on_copy::moved
= 0;
351 // A test type that throws when it is moved. This object will NOT trigger
352 // the small object optimization in 'any'.
353 struct throws_on_move
358 static void reset() { count
= copied
= moved
= 0; }
361 explicit throws_on_move(int val
= 0) : value(val
) { ++count
; }
362 explicit throws_on_move(int, int val
, int) : value(val
) { ++count
; }
363 throws_on_move(throws_on_move
const & other
) {
368 throws_on_move(throws_on_move
&&) {
369 throwMyAnyExpression();
376 throws_on_move
& operator=(throws_on_move
const&) = delete;
377 throws_on_move
& operator=(throws_on_move
&&) = delete;
380 int throws_on_move::count
= 0;
381 int throws_on_move::copied
= 0;
382 int throws_on_move::moved
= 0;
384 struct small_tracked_t
{
386 : arg_types(&makeArgumentID
<>()) {}
387 small_tracked_t(small_tracked_t
const&) noexcept
388 : arg_types(&makeArgumentID
<small_tracked_t
const&>()) {}
389 small_tracked_t(small_tracked_t
&&) noexcept
390 : arg_types(&makeArgumentID
<small_tracked_t
&&>()) {}
391 template <class ...Args
>
392 explicit small_tracked_t(Args
&&...)
393 : arg_types(&makeArgumentID
<Args
...>()) {}
394 template <class ...Args
>
395 explicit small_tracked_t(std::initializer_list
<int>, Args
&&...)
396 : arg_types(&makeArgumentID
<std::initializer_list
<int>, Args
...>()) {}
398 TypeID
const* arg_types
;
400 static_assert(IsSmallObject
<small_tracked_t
>::value
, "must be small");
402 struct large_tracked_t
{
404 : arg_types(&makeArgumentID
<>()) { dummy
[0] = 42; }
405 large_tracked_t(large_tracked_t
const&) noexcept
406 : arg_types(&makeArgumentID
<large_tracked_t
const&>()) {}
407 large_tracked_t(large_tracked_t
&&) noexcept
408 : arg_types(&makeArgumentID
<large_tracked_t
&&>()) {}
409 template <class ...Args
>
410 explicit large_tracked_t(Args
&&...)
411 : arg_types(&makeArgumentID
<Args
...>()) {}
412 template <class ...Args
>
413 explicit large_tracked_t(std::initializer_list
<int>, Args
&&...)
414 : arg_types(&makeArgumentID
<std::initializer_list
<int>, Args
...>()) {}
416 TypeID
const* arg_types
;
417 int dummy
[sizeof(std::any
) / sizeof(int) + 1];
420 static_assert(!IsSmallObject
<large_tracked_t
>::value
, "must not be small");
423 template <class Type
, class ...Args
>
424 void assertArgsMatch(std::any
const& a
) {
426 using namespace std::experimental
;
427 assert(a
.has_value());
428 assert(containsType
<Type
>(a
));
429 assert(any_cast
<Type
const &>(a
).arg_types
== &makeArgumentID
<Args
...>());