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