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
10 // UNSUPPORTED: c++98, c++03, c++11, c++14
11
12 // XFAIL: availability=macosx10.13
13 // XFAIL: availability=macosx10.12
14 // XFAIL: availability=macosx10.11
15 // XFAIL: availability=macosx10.10
16 // XFAIL: availability=macosx10.9
17 // XFAIL: availability=macosx10.8
18 // XFAIL: availability=macosx10.7
19
20 // <any>
21
22 // template <class T, class ...Args> T& emplace(Args&&...);
23 // template <class T, class U, class ...Args>
24 // T& emplace(initializer_list<U>, Args&&...);
25
26 #include <any>
27 #include <cassert>
28
29 #include "any_helpers.h"
30 #include "count_new.hpp"
31 #include "test_macros.h"
32
33 using std::any;
34 using std::any_cast;
35
36 struct Tracked {
37 static int count;
TrackedTracked38 Tracked() {++count;}
~TrackedTracked39 ~Tracked() { --count; }
40 };
41 int Tracked::count = 0;
42
43 template <class Type>
test_emplace_type()44 void test_emplace_type() {
45 // constructing from a small type should perform no allocations.
46 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
47 assert(Type::count == 0);
48 Type::reset();
49 {
50 any a(std::in_place_type<Tracked>);
51 assert(Tracked::count == 1);
52
53 auto &v = a.emplace<Type>();
54 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
55 assert(&v == std::any_cast<Type>(&a));
56
57 assert(Tracked::count == 0);
58 assert(Type::count == 1);
59 assert(Type::copied == 0);
60 assert(Type::moved == 0);
61 assertContains<Type>(a, 0);
62 }
63 assert(Type::count == 0);
64 Type::reset();
65 {
66 any a(std::in_place_type<Tracked>);
67 assert(Tracked::count == 1);
68
69 auto &v = a.emplace<Type>(101);
70 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
71 assert(&v == std::any_cast<Type>(&a));
72
73 assert(Tracked::count == 0);
74 assert(Type::count == 1);
75 assert(Type::copied == 0);
76 assert(Type::moved == 0);
77 assertContains<Type>(a, 101);
78 }
79 assert(Type::count == 0);
80 Type::reset();
81 {
82 any a(std::in_place_type<Tracked>);
83 assert(Tracked::count == 1);
84
85 auto &v = a.emplace<Type>(-1, 42, -1);
86 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
87 assert(&v == std::any_cast<Type>(&a));
88
89 assert(Tracked::count == 0);
90 assert(Type::count == 1);
91 assert(Type::copied == 0);
92 assert(Type::moved == 0);
93 assertContains<Type>(a, 42);
94 }
95 assert(Type::count == 0);
96 Type::reset();
97 }
98
99 template <class Type>
test_emplace_type_tracked()100 void test_emplace_type_tracked() {
101 // constructing from a small type should perform no allocations.
102 DisableAllocationGuard g(isSmallType<Type>()); ((void)g);
103 {
104 any a(std::in_place_type<Tracked>);
105 assert(Tracked::count == 1);
106 auto &v = a.emplace<Type>();
107 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
108 assert(&v == std::any_cast<Type>(&a));
109
110 assert(Tracked::count == 0);
111 assertArgsMatch<Type>(a);
112 }
113 {
114 any a(std::in_place_type<Tracked>);
115 assert(Tracked::count == 1);
116 auto &v = a.emplace<Type>(-1, 42, -1);
117 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
118 assert(&v == std::any_cast<Type>(&a));
119
120 assert(Tracked::count == 0);
121 assertArgsMatch<Type, int, int, int>(a);
122 }
123 // initializer_list constructor tests
124 {
125 any a(std::in_place_type<Tracked>);
126 assert(Tracked::count == 1);
127 auto &v = a.emplace<Type>({-1, 42, -1});
128 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
129 assert(&v == std::any_cast<Type>(&a));
130
131 assert(Tracked::count == 0);
132 assertArgsMatch<Type, std::initializer_list<int>>(a);
133 }
134 {
135 int x = 42;
136 any a(std::in_place_type<Tracked>);
137 assert(Tracked::count == 1);
138 auto &v = a.emplace<Type>({-1, 42, -1}, x);
139 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
140 assert(&v == std::any_cast<Type>(&a));
141
142 assert(Tracked::count == 0);
143 assertArgsMatch<Type, std::initializer_list<int>, int&>(a);
144 }
145 }
146
147 #ifndef TEST_HAS_NO_EXCEPTIONS
148
149 struct SmallThrows {
SmallThrowsSmallThrows150 SmallThrows(int) { throw 42; }
SmallThrowsSmallThrows151 SmallThrows(std::initializer_list<int>, int) { throw 42; }
152 };
153 static_assert(IsSmallObject<SmallThrows>::value, "");
154
155 struct LargeThrows {
LargeThrowsLargeThrows156 LargeThrows(int) { throw 42; }
LargeThrowsLargeThrows157 LargeThrows(std::initializer_list<int>, int) { throw 42; }
158 int data[sizeof(std::any)];
159 };
160 static_assert(!IsSmallObject<LargeThrows>::value, "");
161
162 template <class Type>
test_emplace_throws()163 void test_emplace_throws()
164 {
165 // any stores small type
166 {
167 std::any a(small{42});
168 assert(small::count == 1);
169 try {
170 auto &v = a.emplace<Type>(101);
171 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
172 assert(false);
173 } catch (int const&) {
174 }
175 assert(small::count == 0);
176 }
177 {
178 std::any a(small{42});
179 assert(small::count == 1);
180 try {
181 auto &v = a.emplace<Type>({1, 2, 3}, 101);
182 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
183 assert(false);
184 } catch (int const&) {
185 }
186 assert(small::count == 0);
187 }
188 // any stores large type
189 {
190 std::any a(large{42});
191 assert(large::count == 1);
192 try {
193 auto &v = a.emplace<Type>(101);
194 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
195 assert(false);
196 } catch (int const&) {
197 }
198 assert(large::count == 0);
199 }
200 {
201 std::any a(large{42});
202 assert(large::count == 1);
203 try {
204 auto &v = a.emplace<Type>({1, 2, 3}, 101);
205 static_assert( std::is_same_v<Type&, decltype(v)>, "" );
206 assert(false);
207 } catch (int const&) {
208 }
209 assert(large::count == 0);
210 }
211 }
212
213 #endif
214
215 template <class T, class ...Args>
has_emplace(int)216 constexpr auto has_emplace(int)
217 -> decltype(std::any{}.emplace<T>(std::declval<Args>()...), true) { return true; }
218
219 template <class ...Args>
has_emplace(long)220 constexpr bool has_emplace(long) { return false; }
221
222 template <class ...Args>
has_emplace()223 constexpr bool has_emplace() { return has_emplace<Args...>(0); }
224
225
226 template <class T, class IT, class ...Args>
has_emplace_init_list(int)227 constexpr auto has_emplace_init_list(int)
228 -> decltype(std::any{}.emplace<T>(
229 {std::declval<IT>(), std::declval<IT>(), std::declval<IT>()},
230 std::declval<Args>()...), true) { return true; }
231
232 template <class ...Args>
has_emplace_init_list(long)233 constexpr bool has_emplace_init_list(long) { return false; }
234
235 template <class ...Args>
has_emplace_init_list()236 constexpr bool has_emplace_init_list() { return has_emplace_init_list<Args...>(0); }
237
238
test_emplace_sfinae_constraints()239 void test_emplace_sfinae_constraints() {
240 {
241 static_assert(has_emplace<int>(), "");
242 static_assert(has_emplace<int, int>(), "");
243 static_assert(!has_emplace<int, int, int>(), "not constructible");
244 static_assert(!has_emplace_init_list<int, int>(), "not constructible from il");
245 }
246 {
247 static_assert(has_emplace<small>(), "");
248 static_assert(has_emplace<large>(), "");
249 static_assert(!has_emplace<small, void*>(), "");
250 static_assert(!has_emplace<large, void*>(), "");
251
252 static_assert(has_emplace_init_list<small, int>(), "");
253 static_assert(has_emplace_init_list<large, int>(), "");
254 static_assert(!has_emplace_init_list<small, void*>(), "");
255 static_assert(!has_emplace_init_list<large, void*>(), "");
256 }
257 {
258 // Test that the emplace SFINAE's away when the
259 // argument is non-copyable
260 struct NoCopy {
261 NoCopy() = default;
262 NoCopy(NoCopy const&) = delete;
263 NoCopy(int) {}
264 NoCopy(std::initializer_list<int>, int, int) {}
265 };
266 static_assert(!has_emplace<NoCopy>(), "");
267 static_assert(!has_emplace<NoCopy, int>(), "");
268 static_assert(!has_emplace_init_list<NoCopy, int, int, int>(), "");
269 static_assert(!has_emplace<NoCopy&>(), "");
270 static_assert(!has_emplace<NoCopy&, int>(), "");
271 static_assert(!has_emplace_init_list<NoCopy&, int, int, int>(), "");
272 static_assert(!has_emplace<NoCopy&&>(), "");
273 static_assert(!has_emplace<NoCopy&&, int>(), "");
274 static_assert(!has_emplace_init_list<NoCopy&&, int, int, int>(), "");
275
276 }
277 }
278
main()279 int main() {
280 test_emplace_type<small>();
281 test_emplace_type<large>();
282 test_emplace_type<small_throws_on_copy>();
283 test_emplace_type<large_throws_on_copy>();
284 test_emplace_type<throws_on_move>();
285 test_emplace_type_tracked<small_tracked_t>();
286 test_emplace_type_tracked<large_tracked_t>();
287 test_emplace_sfinae_constraints();
288 #ifndef TEST_HAS_NO_EXCEPTIONS
289 test_emplace_throws<SmallThrows>();
290 test_emplace_throws<LargeThrows>();
291 #endif
292 }
293