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