blob: 76b1922fb1f189f7341012e9551c6775b737f0a5 [file] [log] [blame]
Eric Fiselier7175a072015-07-31 02:24:58 +00001#ifndef ANY_HELPERS_H
2#define ANY_HELPERS_H
3
4#include <experimental/any>
5#include <typeinfo>
6#include <type_traits>
7#include <cassert>
8
9#include "test_macros.h"
10
11#if !defined(TEST_HAS_NO_RTTI)
12#define RTTI_ASSERT(X) assert(X)
13#else
14#define RTTI_ASSERT(X)
15#endif
16
17template <class _Tp>
18 struct IsSmallObject
19 : public std::integral_constant<bool
20 , sizeof(_Tp) <= (sizeof(void*)*3)
21 && std::alignment_of<void*>::value
22 % std::alignment_of<_Tp>::value == 0
23 && std::is_nothrow_move_constructible<_Tp>::value
24 >
25 {};
26
27
28// Return 'true' if 'Type' will be considered a small type by 'any'
29template <class Type>
30bool isSmallType() {
31#if defined(_LIBCPP_VERSION)
32 return std::experimental::__any_imp::_IsSmallObject<Type>::value;
33#else
34 return IsSmallObject<Type>::value;
35#endif
36
37}
38
39// Assert that an object is empty. If the object used to contain an object
40// of type 'LastType' check that it can no longer be accessed.
41template <class LastType = int>
42void assertEmpty(std::experimental::any const& a) {
43 assert(a.empty());
44 RTTI_ASSERT(a.type() == typeid(void));
45 assert(std::experimental::any_cast<LastType const>(&a) == nullptr);
46}
47
48// Assert that an 'any' object stores the specified 'Type' and 'value'.
49template <class Type>
50void assertContains(std::experimental::any const& a, int value = 1) {
51 assert(!a.empty());
52 RTTI_ASSERT(a.type() == typeid(Type));
53 assert(std::experimental::any_cast<Type const &>(a).value == value);
54}
55
56// Modify the value of a "test type" stored within an any to the specified
57// 'value'.
58template <class Type>
59void modifyValue(std::experimental::any& a, int value) {
60 assert(!a.empty());
61 RTTI_ASSERT(a.type() == typeid(Type));
62 std::experimental::any_cast<Type&>(a).value = value;
63}
64
65// A test type that will trigger the small object optimization within 'any'.
66template <int Dummy = 0>
67struct small_type
68{
69 static int count;
70 static int copied;
71 static int moved;
72 static int const_copied;
73 static int non_const_copied;
74
75 static void reset() {
76 small_type::copied = 0;
77 small_type::moved = 0;
78 small_type::const_copied = 0;
79 small_type::non_const_copied = 0;
80 }
81
82 int value;
83
84 explicit small_type(int val) : value(val) {
85 ++count;
86 }
87
88 small_type(small_type const & other) throw() {
89 value = other.value;
90 ++count;
91 ++copied;
92 ++const_copied;
93 }
94
95 small_type(small_type& other) throw() {
96 value = other.value;
97 ++count;
98 ++copied;
99 ++non_const_copied;
100 }
101
102 small_type(small_type && other) throw() {
103 value = other.value;
104 other.value = 0;
105 ++count;
106 ++moved;
107 }
108
109 ~small_type() {
110 value = -1;
111 --count;
112 }
113
114private:
115 small_type& operator=(small_type const&) = delete;
116 small_type& operator=(small_type&&) = delete;
117};
118
119template <int Dummy>
120int small_type<Dummy>::count = 0;
121
122template <int Dummy>
123int small_type<Dummy>::copied = 0;
124
125template <int Dummy>
126int small_type<Dummy>::moved = 0;
127
128template <int Dummy>
129int small_type<Dummy>::const_copied = 0;
130
131template <int Dummy>
132int small_type<Dummy>::non_const_copied = 0;
133
134typedef small_type<> small;
135typedef small_type<1> small1;
136typedef small_type<2> small2;
137
138
139// A test type that will NOT trigger the small object optimization in any.
140template <int Dummy = 0>
141struct large_type
142{
143 static int count;
144 static int copied;
145 static int moved;
146 static int const_copied;
147 static int non_const_copied;
148
149 static void reset() {
150 large_type::copied = 0;
151 large_type::moved = 0;
152 large_type::const_copied = 0;
153 large_type::non_const_copied = 0;
154 }
155
156 int value;
157
158 large_type(int val) : value(val) {
159 ++count;
160 data[0] = 0;
161 }
162
163 large_type(large_type const & other) {
164 value = other.value;
165 ++count;
166 ++copied;
167 ++const_copied;
168 }
169
170 large_type(large_type & other) {
171 value = other.value;
172 ++count;
173 ++copied;
174 ++non_const_copied;
175 }
176
177 large_type(large_type && other) {
178 value = other.value;
179 other.value = 0;
180 ++count;
181 ++moved;
182 }
183
184 ~large_type() {
185 value = 0;
186 --count;
187 }
188
189private:
190 large_type& operator=(large_type const&) = delete;
191 large_type& operator=(large_type &&) = delete;
192 int data[10];
193};
194
195template <int Dummy>
196int large_type<Dummy>::count = 0;
197
198template <int Dummy>
199int large_type<Dummy>::copied = 0;
200
201template <int Dummy>
202int large_type<Dummy>::moved = 0;
203
204template <int Dummy>
205int large_type<Dummy>::const_copied = 0;
206
207template <int Dummy>
208int large_type<Dummy>::non_const_copied = 0;
209
210typedef large_type<> large;
211typedef large_type<1> large1;
212typedef large_type<2> large2;
213
214// The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
215// and 'throws_on_move'.
216struct my_any_exception {};
217
218void throwMyAnyExpression() {
219#if !defined(TEST_HAS_NO_EXCEPTIONS)
220 throw my_any_exception();
221#else
222 assert(false && "Exceptions are disabled");
223#endif
224}
225
226// A test type that will trigger the small object optimization within 'any'.
227// this type throws if it is copied.
228struct small_throws_on_copy
229{
230 static int count;
231 int value;
232
233 explicit small_throws_on_copy(int val = 0) : value(val) {
234 ++count;
235 }
236
237 small_throws_on_copy(small_throws_on_copy const &) {
238 throwMyAnyExpression();
239 }
240
241 small_throws_on_copy(small_throws_on_copy && other) throw() {
242 value = other.value;
243 ++count;
244 }
245
246 ~small_throws_on_copy() {
247 --count;
248 }
249private:
250 small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
251 small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
252};
253
254int small_throws_on_copy::count = 0;
255
256// A test type that will NOT trigger the small object optimization within 'any'.
257// this type throws if it is copied.
258struct large_throws_on_copy
259{
260 static int count;
261 int value = 0;
262
263 explicit large_throws_on_copy(int val = 0) : value(val) {
264 data[0] = 0;
265 ++count;
266 }
267
268 large_throws_on_copy(large_throws_on_copy const &) {
269 throwMyAnyExpression();
270 }
271
272 large_throws_on_copy(large_throws_on_copy && other) throw() {
273 value = other.value;
274 ++count;
275 }
276
277 ~large_throws_on_copy() {
278 --count;
279 }
280
281private:
282 large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
283 large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
284 int data[10];
285};
286
287int large_throws_on_copy::count = 0;
288
289// A test type that throws when it is moved. This object will NOT trigger
290// the small object optimization in 'any'.
291struct throws_on_move
292{
293 static int count;
294 int value;
295
296 explicit throws_on_move(int val = 0) : value(val) { ++count; }
297
298 throws_on_move(throws_on_move const & other) {
299 value = other.value;
300 ++count;
301 }
302
303 throws_on_move(throws_on_move &&) {
304 throwMyAnyExpression();
305 }
306
307 ~throws_on_move() {
308 --count;
309 }
310private:
311 throws_on_move& operator=(throws_on_move const&) = delete;
312 throws_on_move& operator=(throws_on_move &&) = delete;
313};
314
315int throws_on_move::count = 0;
316
317
318#endif