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