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