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