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