blob: ae332d5e0a5fe89f6daf64eccec392359272979b [file] [log] [blame]
Eric Fiselier38236b52016-01-19 21:52:04 +00001//===----------------------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Eric Fiselier3461dbc2015-07-31 02:24:58 +00009#ifndef ANY_HELPERS_H
10#define ANY_HELPERS_H
11
Eric Fiselier3461dbc2015-07-31 02:24:58 +000012#include <typeinfo>
13#include <type_traits>
14#include <cassert>
15
Eric Fiselier324506b2016-08-11 03:13:11 +000016namespace std { namespace experimental {} }
17
Eric Fiselier3461dbc2015-07-31 02:24:58 +000018#include "test_macros.h"
Eric Fiselier324506b2016-08-11 03:13:11 +000019#include "type_id.h"
Eric Fiselier3461dbc2015-07-31 02:24:58 +000020
21#if !defined(TEST_HAS_NO_RTTI)
22#define RTTI_ASSERT(X) assert(X)
23#else
24#define RTTI_ASSERT(X)
25#endif
26
27template <class _Tp>
28 struct IsSmallObject
29 : public std::integral_constant<bool
30 , sizeof(_Tp) <= (sizeof(void*)*3)
31 && std::alignment_of<void*>::value
32 % std::alignment_of<_Tp>::value == 0
33 && std::is_nothrow_move_constructible<_Tp>::value
34 >
35 {};
36
Eric Fiselier324506b2016-08-11 03:13:11 +000037template <class T>
38bool containsType(std::any const& a) {
39#if !defined(TEST_HAS_NO_RTTI)
40 return a.type() == typeid(T);
41#else
42 return a.has_value() && std::any_cast<T>(&a) != nullptr;
43#endif
44}
Eric Fiselier3461dbc2015-07-31 02:24:58 +000045
46// Return 'true' if 'Type' will be considered a small type by 'any'
47template <class Type>
48bool isSmallType() {
Eric Fiselier3461dbc2015-07-31 02:24:58 +000049 return IsSmallObject<Type>::value;
Eric Fiselier3461dbc2015-07-31 02:24:58 +000050}
51
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.
54template <class LastType = int>
Eric Fiselier324506b2016-08-11 03:13:11 +000055void assertEmpty(std::any const& a) {
56 using namespace std;
57 assert(!a.has_value());
Eric Fiselier3461dbc2015-07-31 02:24:58 +000058 RTTI_ASSERT(a.type() == typeid(void));
Eric Fiselier324506b2016-08-11 03:13:11 +000059 assert(any_cast<LastType const>(&a) == nullptr);
Eric Fiselier3461dbc2015-07-31 02:24:58 +000060}
61
62// Assert that an 'any' object stores the specified 'Type' and 'value'.
63template <class Type>
Eric Fiselier324506b2016-08-11 03:13:11 +000064void assertContains(std::any const& a, int value = 1) {
65 assert(a.has_value());
66 assert(containsType<Type>(a));
67 assert(std::any_cast<Type const &>(a).value == value);
68}
69
70template <>
71void assertContains<int>(std::any const& a, int value) {
72 assert(a.has_value());
73 assert(containsType<int>(a));
74 assert(std::any_cast<int const &>(a) == value);
Eric Fiselier3461dbc2015-07-31 02:24:58 +000075}
76
77// Modify the value of a "test type" stored within an any to the specified
78// 'value'.
79template <class Type>
Eric Fiselier324506b2016-08-11 03:13:11 +000080void modifyValue(std::any& a, int value) {
81 using namespace std;
82 using namespace std::experimental;
83 assert(a.has_value());
84 assert(containsType<Type>(a));
85 any_cast<Type&>(a).value = value;
Eric Fiselier3461dbc2015-07-31 02:24:58 +000086}
87
88// A test type that will trigger the small object optimization within 'any'.
89template <int Dummy = 0>
90struct small_type
91{
92 static int count;
93 static int copied;
94 static int moved;
95 static int const_copied;
96 static int non_const_copied;
97
98 static void reset() {
99 small_type::copied = 0;
100 small_type::moved = 0;
101 small_type::const_copied = 0;
102 small_type::non_const_copied = 0;
103 }
104
105 int value;
106
Eric Fiselier324506b2016-08-11 03:13:11 +0000107 explicit small_type(int val = 0) : value(val) {
108 ++count;
109 }
110 explicit small_type(int, int val, int) : value(val) {
111 ++count;
112 }
113 small_type(std::initializer_list<int> il) : value(*il.begin()) {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000114 ++count;
115 }
116
Eric Fiselier324506b2016-08-11 03:13:11 +0000117 small_type(small_type const & other) noexcept {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000118 value = other.value;
119 ++count;
120 ++copied;
121 ++const_copied;
122 }
123
Eric Fiselier324506b2016-08-11 03:13:11 +0000124 small_type(small_type& other) noexcept {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000125 value = other.value;
126 ++count;
127 ++copied;
128 ++non_const_copied;
129 }
130
Eric Fiselier324506b2016-08-11 03:13:11 +0000131 small_type(small_type && other) noexcept {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000132 value = other.value;
133 other.value = 0;
134 ++count;
135 ++moved;
136 }
137
138 ~small_type() {
139 value = -1;
140 --count;
141 }
142
143private:
144 small_type& operator=(small_type const&) = delete;
145 small_type& operator=(small_type&&) = delete;
146};
147
148template <int Dummy>
149int small_type<Dummy>::count = 0;
150
151template <int Dummy>
152int small_type<Dummy>::copied = 0;
153
154template <int Dummy>
155int small_type<Dummy>::moved = 0;
156
157template <int Dummy>
158int small_type<Dummy>::const_copied = 0;
159
160template <int Dummy>
161int small_type<Dummy>::non_const_copied = 0;
162
163typedef small_type<> small;
164typedef small_type<1> small1;
165typedef small_type<2> small2;
166
167
168// A test type that will NOT trigger the small object optimization in any.
169template <int Dummy = 0>
170struct large_type
171{
172 static int count;
173 static int copied;
174 static int moved;
175 static int const_copied;
176 static int non_const_copied;
177
178 static void reset() {
179 large_type::copied = 0;
180 large_type::moved = 0;
181 large_type::const_copied = 0;
182 large_type::non_const_copied = 0;
183 }
184
185 int value;
186
Eric Fiselier324506b2016-08-11 03:13:11 +0000187 large_type(int val = 0) : value(val) {
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000188 ++count;
189 data[0] = 0;
190 }
Eric Fiselier324506b2016-08-11 03:13:11 +0000191 large_type(int, int val, int) : value(val) {
192 ++count;
193 data[0] = 0;
194 }
195 large_type(std::initializer_list<int> il) : value(*il.begin()) {
196 ++count;
197 }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000198 large_type(large_type const & other) {
199 value = other.value;
200 ++count;
201 ++copied;
202 ++const_copied;
203 }
204
205 large_type(large_type & other) {
206 value = other.value;
207 ++count;
208 ++copied;
209 ++non_const_copied;
210 }
211
212 large_type(large_type && other) {
213 value = other.value;
214 other.value = 0;
215 ++count;
216 ++moved;
217 }
218
219 ~large_type() {
220 value = 0;
221 --count;
222 }
223
224private:
225 large_type& operator=(large_type const&) = delete;
226 large_type& operator=(large_type &&) = delete;
227 int data[10];
228};
229
230template <int Dummy>
231int large_type<Dummy>::count = 0;
232
233template <int Dummy>
234int large_type<Dummy>::copied = 0;
235
236template <int Dummy>
237int large_type<Dummy>::moved = 0;
238
239template <int Dummy>
240int large_type<Dummy>::const_copied = 0;
241
242template <int Dummy>
243int large_type<Dummy>::non_const_copied = 0;
244
245typedef large_type<> large;
246typedef large_type<1> large1;
247typedef large_type<2> large2;
248
249// The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
250// and 'throws_on_move'.
251struct my_any_exception {};
252
253void throwMyAnyExpression() {
254#if !defined(TEST_HAS_NO_EXCEPTIONS)
255 throw my_any_exception();
256#else
257 assert(false && "Exceptions are disabled");
258#endif
259}
260
261// A test type that will trigger the small object optimization within 'any'.
262// this type throws if it is copied.
263struct small_throws_on_copy
264{
265 static int count;
Eric Fiselier324506b2016-08-11 03:13:11 +0000266 static int copied;
267 static int moved;
268 static void reset() { count = copied = moved = 0; }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000269 int value;
270
271 explicit small_throws_on_copy(int val = 0) : value(val) {
272 ++count;
273 }
Eric Fiselier324506b2016-08-11 03:13:11 +0000274 explicit small_throws_on_copy(int, int val, int) : value(val) {
275 ++count;
276 }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000277 small_throws_on_copy(small_throws_on_copy const &) {
278 throwMyAnyExpression();
279 }
280
281 small_throws_on_copy(small_throws_on_copy && other) throw() {
282 value = other.value;
Eric Fiselier324506b2016-08-11 03:13:11 +0000283 ++count; ++moved;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000284 }
285
286 ~small_throws_on_copy() {
287 --count;
288 }
289private:
290 small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
291 small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
292};
293
294int small_throws_on_copy::count = 0;
Eric Fiselier324506b2016-08-11 03:13:11 +0000295int small_throws_on_copy::copied = 0;
296int small_throws_on_copy::moved = 0;
297
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000298
299// A test type that will NOT trigger the small object optimization within 'any'.
300// this type throws if it is copied.
301struct large_throws_on_copy
302{
303 static int count;
Eric Fiselier324506b2016-08-11 03:13:11 +0000304 static int copied;
305 static int moved;
306 static void reset() { count = copied = moved = 0; }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000307 int value = 0;
308
309 explicit large_throws_on_copy(int val = 0) : value(val) {
310 data[0] = 0;
311 ++count;
312 }
Eric Fiselier324506b2016-08-11 03:13:11 +0000313 explicit large_throws_on_copy(int, int val, int) : value(val) {
314 data[0] = 0;
315 ++count;
316 }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000317 large_throws_on_copy(large_throws_on_copy const &) {
318 throwMyAnyExpression();
319 }
320
321 large_throws_on_copy(large_throws_on_copy && other) throw() {
322 value = other.value;
Eric Fiselier324506b2016-08-11 03:13:11 +0000323 ++count; ++moved;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000324 }
325
326 ~large_throws_on_copy() {
327 --count;
328 }
329
330private:
331 large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
332 large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
333 int data[10];
334};
335
336int large_throws_on_copy::count = 0;
Eric Fiselier324506b2016-08-11 03:13:11 +0000337int large_throws_on_copy::copied = 0;
338int large_throws_on_copy::moved = 0;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000339
340// A test type that throws when it is moved. This object will NOT trigger
341// the small object optimization in 'any'.
342struct throws_on_move
343{
344 static int count;
Eric Fiselier324506b2016-08-11 03:13:11 +0000345 static int copied;
346 static int moved;
347 static void reset() { count = copied = moved = 0; }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000348 int value;
349
350 explicit throws_on_move(int val = 0) : value(val) { ++count; }
Eric Fiselier324506b2016-08-11 03:13:11 +0000351 explicit throws_on_move(int, int val, int) : value(val) { ++count; }
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000352 throws_on_move(throws_on_move const & other) {
353 value = other.value;
Eric Fiselier324506b2016-08-11 03:13:11 +0000354 ++count; ++copied;
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000355 }
356
357 throws_on_move(throws_on_move &&) {
358 throwMyAnyExpression();
359 }
360
361 ~throws_on_move() {
362 --count;
363 }
364private:
365 throws_on_move& operator=(throws_on_move const&) = delete;
366 throws_on_move& operator=(throws_on_move &&) = delete;
367};
368
369int throws_on_move::count = 0;
Eric Fiselier324506b2016-08-11 03:13:11 +0000370int throws_on_move::copied = 0;
371int throws_on_move::moved = 0;
372
373struct small_tracked_t {
374 small_tracked_t()
375 : arg_types(&makeArgumentID<>()) {}
376 small_tracked_t(small_tracked_t const&) noexcept
377 : arg_types(&makeArgumentID<small_tracked_t const&>()) {}
378 small_tracked_t(small_tracked_t &&) noexcept
379 : arg_types(&makeArgumentID<small_tracked_t &&>()) {}
380 template <class ...Args>
381 explicit small_tracked_t(Args&&...)
382 : arg_types(&makeArgumentID<Args...>()) {}
383 template <class ...Args>
384 explicit small_tracked_t(std::initializer_list<int>, Args&&...)
385 : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
386
387 TypeID const* arg_types;
388};
389static_assert(IsSmallObject<small_tracked_t>::value, "must be small");
390
391struct large_tracked_t {
392 large_tracked_t()
393 : arg_types(&makeArgumentID<>()) { dummy[0] = 42; }
394 large_tracked_t(large_tracked_t const&) noexcept
395 : arg_types(&makeArgumentID<large_tracked_t const&>()) {}
396 large_tracked_t(large_tracked_t &&) noexcept
397 : arg_types(&makeArgumentID<large_tracked_t &&>()) {}
398 template <class ...Args>
399 explicit large_tracked_t(Args&&...)
400 : arg_types(&makeArgumentID<Args...>()) {}
401 template <class ...Args>
402 explicit large_tracked_t(std::initializer_list<int>, Args&&...)
403 : arg_types(&makeArgumentID<std::initializer_list<int>, Args...>()) {}
404
405 TypeID const* arg_types;
406 int dummy[10];
407};
408
409static_assert(!IsSmallObject<large_tracked_t>::value, "must be small");
410
411
412template <class Type, class ...Args>
413void assertArgsMatch(std::any const& a) {
414 using namespace std;
415 using namespace std::experimental;
416 assert(a.has_value());
417 assert(containsType<Type>(a));
418 assert(any_cast<Type const &>(a).arg_types == &makeArgumentID<Args...>());
419};
Eric Fiselier3461dbc2015-07-31 02:24:58 +0000420
421
422#endif