• 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 T>
26   struct IsSmallObject
27     : public std::integral_constant<bool
28         , sizeof(T) <= (sizeof(void*)*3)
29           && std::alignment_of<void*>::value
30              % std::alignment_of<T>::value == 0
31           && std::is_nothrow_move_constructible<T>::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 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
59 void assertContains(std::experimental::any const& a, int value = 1) {
60     assert(!a.empty());
61     RTTI_ASSERT(a.type() == typeid(Type));
62     assert(std::experimental::any_cast<Type const &>(a).value == value);
63 }
64 
65 // Modify the value of a "test type" stored within an any to the specified
66 // 'value'.
67 template <class Type>
68 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
modifyValue(std::experimental::any & a,int value)69 void modifyValue(std::experimental::any& a, int value) {
70     assert(!a.empty());
71     RTTI_ASSERT(a.type() == typeid(Type));
72     std::experimental::any_cast<Type&>(a).value = value;
73 }
74 
75 // A test type that will trigger the small object optimization within 'any'.
76 template <int Dummy = 0>
77 struct small_type
78 {
79     static int count;
80     static int copied;
81     static int moved;
82     static int const_copied;
83     static int non_const_copied;
84 
resetsmall_type85     static void reset() {
86         small_type::copied = 0;
87         small_type::moved = 0;
88         small_type::const_copied = 0;
89         small_type::non_const_copied = 0;
90     }
91 
92     int value;
93 
small_typesmall_type94     explicit small_type(int val) : value(val) {
95         ++count;
96     }
97 
throwsmall_type98     small_type(small_type const & other) throw() {
99         value = other.value;
100         ++count;
101         ++copied;
102         ++const_copied;
103     }
104 
throwsmall_type105     small_type(small_type& other) throw() {
106         value = other.value;
107         ++count;
108         ++copied;
109         ++non_const_copied;
110     }
111 
throwsmall_type112     small_type(small_type && other) throw() {
113         value = other.value;
114         other.value = 0;
115         ++count;
116         ++moved;
117     }
118 
~small_typesmall_type119     ~small_type() {
120         value = -1;
121         --count;
122     }
123 
124 private:
125     small_type& operator=(small_type const&) = delete;
126     small_type& operator=(small_type&&) = delete;
127 };
128 
129 template <int Dummy>
130 int small_type<Dummy>::count = 0;
131 
132 template <int Dummy>
133 int small_type<Dummy>::copied = 0;
134 
135 template <int Dummy>
136 int small_type<Dummy>::moved = 0;
137 
138 template <int Dummy>
139 int small_type<Dummy>::const_copied = 0;
140 
141 template <int Dummy>
142 int small_type<Dummy>::non_const_copied = 0;
143 
144 typedef small_type<> small;
145 typedef small_type<1> small1;
146 typedef small_type<2> small2;
147 
148 
149 // A test type that will NOT trigger the small object optimization in any.
150 template <int Dummy = 0>
151 struct large_type
152 {
153     static int count;
154     static int copied;
155     static int moved;
156     static int const_copied;
157     static int non_const_copied;
158 
resetlarge_type159     static void reset() {
160         large_type::copied = 0;
161         large_type::moved  = 0;
162         large_type::const_copied = 0;
163         large_type::non_const_copied = 0;
164     }
165 
166     int value;
167 
large_typelarge_type168     large_type(int val) : value(val) {
169         ++count;
170         data[0] = 0;
171     }
172 
large_typelarge_type173     large_type(large_type const & other) {
174         value = other.value;
175         ++count;
176         ++copied;
177         ++const_copied;
178     }
179 
large_typelarge_type180     large_type(large_type & other) {
181         value = other.value;
182         ++count;
183         ++copied;
184         ++non_const_copied;
185     }
186 
large_typelarge_type187     large_type(large_type && other) {
188         value = other.value;
189         other.value = 0;
190         ++count;
191         ++moved;
192     }
193 
~large_typelarge_type194     ~large_type()  {
195         value = 0;
196         --count;
197     }
198 
199 private:
200     large_type& operator=(large_type const&) = delete;
201     large_type& operator=(large_type &&) = delete;
202     int data[10];
203 };
204 
205 template <int Dummy>
206 int large_type<Dummy>::count = 0;
207 
208 template <int Dummy>
209 int large_type<Dummy>::copied = 0;
210 
211 template <int Dummy>
212 int large_type<Dummy>::moved = 0;
213 
214 template <int Dummy>
215 int large_type<Dummy>::const_copied = 0;
216 
217 template <int Dummy>
218 int large_type<Dummy>::non_const_copied = 0;
219 
220 typedef large_type<> large;
221 typedef large_type<1> large1;
222 typedef large_type<2> large2;
223 
224 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
225 // and 'throws_on_move'.
226 struct my_any_exception {};
227 
throwMyAnyExpression()228 void throwMyAnyExpression() {
229 #if !defined(TEST_HAS_NO_EXCEPTIONS)
230         throw my_any_exception();
231 #else
232         assert(false && "Exceptions are disabled");
233 #endif
234 }
235 
236 // A test type that will trigger the small object optimization within 'any'.
237 // this type throws if it is copied.
238 struct small_throws_on_copy
239 {
240     static int count;
241     int value;
242 
valuesmall_throws_on_copy243     explicit small_throws_on_copy(int val = 0) : value(val) {
244         ++count;
245     }
246 
small_throws_on_copysmall_throws_on_copy247     small_throws_on_copy(small_throws_on_copy const &) {
248         throwMyAnyExpression();
249     }
250 
throwsmall_throws_on_copy251     small_throws_on_copy(small_throws_on_copy && other) throw() {
252         value = other.value;
253         ++count;
254     }
255 
~small_throws_on_copysmall_throws_on_copy256     ~small_throws_on_copy() {
257         --count;
258     }
259 private:
260     small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
261     small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
262 };
263 
264 int small_throws_on_copy::count = 0;
265 
266 // A test type that will NOT trigger the small object optimization within 'any'.
267 // this type throws if it is copied.
268 struct large_throws_on_copy
269 {
270     static int count;
271     int value = 0;
272 
valuelarge_throws_on_copy273     explicit large_throws_on_copy(int val = 0) : value(val) {
274         data[0] = 0;
275         ++count;
276     }
277 
large_throws_on_copylarge_throws_on_copy278     large_throws_on_copy(large_throws_on_copy const &) {
279          throwMyAnyExpression();
280     }
281 
throwlarge_throws_on_copy282     large_throws_on_copy(large_throws_on_copy && other) throw() {
283         value = other.value;
284         ++count;
285     }
286 
~large_throws_on_copylarge_throws_on_copy287     ~large_throws_on_copy() {
288         --count;
289     }
290 
291 private:
292     large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
293     large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
294     int data[10];
295 };
296 
297 int large_throws_on_copy::count = 0;
298 
299 // A test type that throws when it is moved. This object will NOT trigger
300 // the small object optimization in 'any'.
301 struct throws_on_move
302 {
303     static int count;
304     int value;
305 
valuethrows_on_move306     explicit throws_on_move(int val = 0) : value(val) { ++count; }
307 
throws_on_movethrows_on_move308     throws_on_move(throws_on_move const & other) {
309         value = other.value;
310         ++count;
311     }
312 
throws_on_movethrows_on_move313     throws_on_move(throws_on_move &&) {
314         throwMyAnyExpression();
315     }
316 
~throws_on_movethrows_on_move317     ~throws_on_move() {
318         --count;
319     }
320 private:
321     throws_on_move& operator=(throws_on_move const&) = delete;
322     throws_on_move& operator=(throws_on_move &&) = delete;
323 };
324 
325 int throws_on_move::count = 0;
326 
327 
328 #endif
329