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