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 //===----------------------------------------------------------------------===//
13 #include <type_traits>
16 namespace std
{ namespace experimental
{} }
18 #include "test_macros.h"
21 #if !defined(TEST_HAS_NO_RTTI)
22 #define RTTI_ASSERT(X) assert(X)
24 #define RTTI_ASSERT(X)
29 : public std::integral_constant
<bool
30 , sizeof(T
) <= sizeof(std::any
) - sizeof(void*)
31 && std::alignment_of
<void*>::value
32 % std::alignment_of
<T
>::value
== 0
33 && std::is_nothrow_move_constructible
<T
>::value
38 bool containsType(std::any
const& a
) {
39 #if !defined(TEST_HAS_NO_RTTI)
40 return a
.type() == typeid(T
);
42 return a
.has_value() && std::any_cast
<T
>(&a
) != nullptr;
46 // Return 'true' if 'Type' will be considered a small type by 'any'
49 return IsSmallObject
<Type
>::value
;
52 // Assert that an object is empty. If the object used to contain an object
53 // of type 'LastType' check that it can no longer be accessed.
54 template <class LastType
= int>
55 void assertEmpty(std::any
const& a
) {
56 assert(!a
.has_value());
57 RTTI_ASSERT(a
.type() == typeid(void));
58 assert(std::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
) {
92 assert(a
.has_value());
93 assert(containsType
<Type
>(a
));
94 std::any_cast
<Type
&>(a
).value
= value
;
97 // A test type that will trigger the small object optimization within 'any'.
98 template <int Dummy
= 0>
104 static int const_copied
;
105 static int non_const_copied
;
107 static void reset() {
108 small_type::copied
= 0;
109 small_type::moved
= 0;
110 small_type::const_copied
= 0;
111 small_type::non_const_copied
= 0;
116 explicit small_type(int val
= 0) : value(val
) {
119 explicit small_type(int, int val
, int) : value(val
) {
122 small_type(std::initializer_list
<int> il
) : value(*il
.begin()) {
126 small_type(small_type
const & other
) noexcept
{
133 small_type(small_type
& other
) noexcept
{
140 small_type(small_type
&& other
) noexcept
{
153 small_type
& operator=(small_type
const&) = delete;
154 small_type
& operator=(small_type
&&) = delete;
158 int small_type
<Dummy
>::count
= 0;
161 int small_type
<Dummy
>::copied
= 0;
164 int small_type
<Dummy
>::moved
= 0;
167 int small_type
<Dummy
>::const_copied
= 0;
170 int small_type
<Dummy
>::non_const_copied
= 0;
172 typedef small_type
<> small
;
173 typedef small_type
<1> small1
;
174 typedef small_type
<2> small2
;
177 // A test type that will NOT trigger the small object optimization in any.
178 template <int Dummy
= 0>
184 static int const_copied
;
185 static int non_const_copied
;
187 static void reset() {
188 large_type::copied
= 0;
189 large_type::moved
= 0;
190 large_type::const_copied
= 0;
191 large_type::non_const_copied
= 0;
196 large_type(int val
= 0) : value(val
) {
200 large_type(int, int val
, int) : value(val
) {
204 large_type(std::initializer_list
<int> il
) : value(*il
.begin()) {
207 large_type(large_type
const & other
) {
214 large_type(large_type
& other
) {
221 large_type(large_type
&& other
) {
234 large_type
& operator=(large_type
const&) = delete;
235 large_type
& operator=(large_type
&&) = delete;
240 int large_type
<Dummy
>::count
= 0;
243 int large_type
<Dummy
>::copied
= 0;
246 int large_type
<Dummy
>::moved
= 0;
249 int large_type
<Dummy
>::const_copied
= 0;
252 int large_type
<Dummy
>::non_const_copied
= 0;
254 typedef large_type
<> large
;
255 typedef large_type
<1> large1
;
256 typedef large_type
<2> large2
;
258 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
259 // and 'throws_on_move'.
260 struct my_any_exception
{};
262 void throwMyAnyExpression() {
263 #if !defined(TEST_HAS_NO_EXCEPTIONS)
264 throw my_any_exception();
266 assert(false && "Exceptions are disabled");
270 // A test type that will trigger the small object optimization within 'any'.
271 // this type throws if it is copied.
272 struct small_throws_on_copy
277 static void reset() { count
= copied
= moved
= 0; }
280 explicit small_throws_on_copy(int val
= 0) : value(val
) {
283 explicit small_throws_on_copy(int, int val
, int) : value(val
) {
286 small_throws_on_copy(small_throws_on_copy
const &) {
287 throwMyAnyExpression();
290 small_throws_on_copy(small_throws_on_copy
&& other
) throw() {
295 ~small_throws_on_copy() {
299 small_throws_on_copy
& operator=(small_throws_on_copy
const&) = delete;
300 small_throws_on_copy
& operator=(small_throws_on_copy
&&) = delete;
303 int small_throws_on_copy::count
= 0;
304 int small_throws_on_copy::copied
= 0;
305 int small_throws_on_copy::moved
= 0;
308 // A test type that will NOT trigger the small object optimization within 'any'.
309 // this type throws if it is copied.
310 struct large_throws_on_copy
315 static void reset() { count
= copied
= moved
= 0; }
318 explicit large_throws_on_copy(int val
= 0) : value(val
) {
322 explicit large_throws_on_copy(int, int val
, int) : value(val
) {
326 large_throws_on_copy(large_throws_on_copy
const &) {
327 throwMyAnyExpression();
330 large_throws_on_copy(large_throws_on_copy
&& other
) throw() {
335 ~large_throws_on_copy() {
340 large_throws_on_copy
& operator=(large_throws_on_copy
const&) = delete;
341 large_throws_on_copy
& operator=(large_throws_on_copy
&&) = delete;
345 int large_throws_on_copy::count
= 0;
346 int large_throws_on_copy::copied
= 0;
347 int large_throws_on_copy::moved
= 0;
349 // A test type that throws when it is moved. This object will NOT trigger
350 // the small object optimization in 'any'.
351 struct throws_on_move
356 static void reset() { count
= copied
= moved
= 0; }
359 explicit throws_on_move(int val
= 0) : value(val
) { ++count
; }
360 explicit throws_on_move(int, int val
, int) : value(val
) { ++count
; }
361 throws_on_move(throws_on_move
const & other
) {
366 throws_on_move(throws_on_move
&&) {
367 throwMyAnyExpression();
374 throws_on_move
& operator=(throws_on_move
const&) = delete;
375 throws_on_move
& operator=(throws_on_move
&&) = delete;
378 int throws_on_move::count
= 0;
379 int throws_on_move::copied
= 0;
380 int throws_on_move::moved
= 0;
382 struct small_tracked_t
{
384 : arg_types(&makeArgumentID
<>()) {}
385 small_tracked_t(small_tracked_t
const&) noexcept
386 : arg_types(&makeArgumentID
<small_tracked_t
const&>()) {}
387 small_tracked_t(small_tracked_t
&&) noexcept
388 : arg_types(&makeArgumentID
<small_tracked_t
&&>()) {}
389 template <class ...Args
>
390 explicit small_tracked_t(Args
&&...)
391 : arg_types(&makeArgumentID
<Args
...>()) {}
392 template <class ...Args
>
393 explicit small_tracked_t(std::initializer_list
<int>, Args
&&...)
394 : arg_types(&makeArgumentID
<std::initializer_list
<int>, Args
...>()) {}
396 TypeID
const* arg_types
;
398 static_assert(IsSmallObject
<small_tracked_t
>::value
, "must be small");
400 struct large_tracked_t
{
402 : arg_types(&makeArgumentID
<>()) { dummy
[0] = 42; }
403 large_tracked_t(large_tracked_t
const&) noexcept
404 : arg_types(&makeArgumentID
<large_tracked_t
const&>()) {}
405 large_tracked_t(large_tracked_t
&&) noexcept
406 : arg_types(&makeArgumentID
<large_tracked_t
&&>()) {}
407 template <class ...Args
>
408 explicit large_tracked_t(Args
&&...)
409 : arg_types(&makeArgumentID
<Args
...>()) {}
410 template <class ...Args
>
411 explicit large_tracked_t(std::initializer_list
<int>, Args
&&...)
412 : arg_types(&makeArgumentID
<std::initializer_list
<int>, Args
...>()) {}
414 TypeID
const* arg_types
;
415 int dummy
[sizeof(std::any
) / sizeof(int) + 1];
418 static_assert(!IsSmallObject
<large_tracked_t
>::value
, "must not be small");
421 template <class Type
, class ...Args
>
422 void assertArgsMatch(std::any
const& a
) {
423 assert(a
.has_value());
424 assert(containsType
<Type
>(a
));
425 assert(std::any_cast
<Type
const &>(a
).arg_types
== &makeArgumentID
<Args
...>());