1 #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 
17 template <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'
29 template <class Type>
isSmallType()30 bool 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.
41 template <class LastType = int>
assertEmpty(std::experimental::any const & a)42 void 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'.
49 template <class Type>
50 void 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'.
58 template <class Type>
modifyValue(std::experimental::any & a,int value)59 void 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'.
66 template <int Dummy = 0>
67 struct 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 
resetsmall_type75     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 
small_typesmall_type84     explicit small_type(int val) : value(val) {
85         ++count;
86     }
87 
throwsmall_type88     small_type(small_type const & other) throw() {
89         value = other.value;
90         ++count;
91         ++copied;
92         ++const_copied;
93     }
94 
throwsmall_type95     small_type(small_type& other) throw() {
96         value = other.value;
97         ++count;
98         ++copied;
99         ++non_const_copied;
100     }
101 
throwsmall_type102     small_type(small_type && other) throw() {
103         value = other.value;
104         other.value = 0;
105         ++count;
106         ++moved;
107     }
108 
~small_typesmall_type109     ~small_type() {
110         value = -1;
111         --count;
112     }
113 
114 private:
115     small_type& operator=(small_type const&) = delete;
116     small_type& operator=(small_type&&) = delete;
117 };
118 
119 template <int Dummy>
120 int small_type<Dummy>::count = 0;
121 
122 template <int Dummy>
123 int small_type<Dummy>::copied = 0;
124 
125 template <int Dummy>
126 int small_type<Dummy>::moved = 0;
127 
128 template <int Dummy>
129 int small_type<Dummy>::const_copied = 0;
130 
131 template <int Dummy>
132 int small_type<Dummy>::non_const_copied = 0;
133 
134 typedef small_type<> small;
135 typedef small_type<1> small1;
136 typedef small_type<2> small2;
137 
138 
139 // A test type that will NOT trigger the small object optimization in any.
140 template <int Dummy = 0>
141 struct 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 
resetlarge_type149     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 
large_typelarge_type158     large_type(int val) : value(val) {
159         ++count;
160         data[0] = 0;
161     }
162 
large_typelarge_type163     large_type(large_type const & other) {
164         value = other.value;
165         ++count;
166         ++copied;
167         ++const_copied;
168     }
169 
large_typelarge_type170     large_type(large_type & other) {
171         value = other.value;
172         ++count;
173         ++copied;
174         ++non_const_copied;
175     }
176 
large_typelarge_type177     large_type(large_type && other) {
178         value = other.value;
179         other.value = 0;
180         ++count;
181         ++moved;
182     }
183 
~large_typelarge_type184     ~large_type()  {
185         value = 0;
186         --count;
187     }
188 
189 private:
190     large_type& operator=(large_type const&) = delete;
191     large_type& operator=(large_type &&) = delete;
192     int data[10];
193 };
194 
195 template <int Dummy>
196 int large_type<Dummy>::count = 0;
197 
198 template <int Dummy>
199 int large_type<Dummy>::copied = 0;
200 
201 template <int Dummy>
202 int large_type<Dummy>::moved = 0;
203 
204 template <int Dummy>
205 int large_type<Dummy>::const_copied = 0;
206 
207 template <int Dummy>
208 int large_type<Dummy>::non_const_copied = 0;
209 
210 typedef large_type<> large;
211 typedef large_type<1> large1;
212 typedef large_type<2> large2;
213 
214 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
215 // and 'throws_on_move'.
216 struct my_any_exception {};
217 
throwMyAnyExpression()218 void 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.
228 struct small_throws_on_copy
229 {
230     static int count;
231     int value;
232 
valuesmall_throws_on_copy233     explicit small_throws_on_copy(int val = 0) : value(val) {
234         ++count;
235     }
236 
small_throws_on_copysmall_throws_on_copy237     small_throws_on_copy(small_throws_on_copy const &) {
238         throwMyAnyExpression();
239     }
240 
throwsmall_throws_on_copy241     small_throws_on_copy(small_throws_on_copy && other) throw() {
242         value = other.value;
243         ++count;
244     }
245 
~small_throws_on_copysmall_throws_on_copy246     ~small_throws_on_copy() {
247         --count;
248     }
249 private:
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 
254 int 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.
258 struct large_throws_on_copy
259 {
260     static int count;
261     int value = 0;
262 
valuelarge_throws_on_copy263     explicit large_throws_on_copy(int val = 0) : value(val) {
264         data[0] = 0;
265         ++count;
266     }
267 
large_throws_on_copylarge_throws_on_copy268     large_throws_on_copy(large_throws_on_copy const &) {
269          throwMyAnyExpression();
270     }
271 
throwlarge_throws_on_copy272     large_throws_on_copy(large_throws_on_copy && other) throw() {
273         value = other.value;
274         ++count;
275     }
276 
~large_throws_on_copylarge_throws_on_copy277     ~large_throws_on_copy() {
278         --count;
279     }
280 
281 private:
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 
287 int 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'.
291 struct throws_on_move
292 {
293     static int count;
294     int value;
295 
valuethrows_on_move296     explicit throws_on_move(int val = 0) : value(val) { ++count; }
297 
throws_on_movethrows_on_move298     throws_on_move(throws_on_move const & other) {
299         value = other.value;
300         ++count;
301     }
302 
throws_on_movethrows_on_move303     throws_on_move(throws_on_move &&) {
304         throwMyAnyExpression();
305     }
306 
~throws_on_movethrows_on_move307     ~throws_on_move() {
308         --count;
309     }
310 private:
311     throws_on_move& operator=(throws_on_move const&) = delete;
312     throws_on_move& operator=(throws_on_move &&) = delete;
313 };
314 
315 int throws_on_move::count = 0;
316 
317 
318 #endif
319