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// FIXME: In MSVC mode, even "std::function<int(int)> f(aref);" causes
10// allocations.
11// XFAIL: target=x86_64-pc-windows-msvc && stdlib=libc++ && libcpp-abi-version=1
12
13// UNSUPPORTED: c++03
14
15// <functional>
16
17// class function<R(ArgTypes...)>
18
19// function(const function& f);
20// function(function&& f); // noexcept in C++20
21
22#include <functional>
23#include <memory>
24#include <cstdlib>
25#include <cassert>
26#include <utility>
27
28#include "test_macros.h"
29#include "count_new.h"
30
31class A
32{
33 int data_[10];
34public:
35 static int count;
36
37 A()
38 {
39 ++count;
40 for (int i = 0; i < 10; ++i)
41 data_[i] = i;
42 }
43
44 A(const A&) {++count;}
45
46 ~A() {--count;}
47
48 int operator()(int i) const
49 {
50 for (int j = 0; j < 10; ++j)
51 i += data_[j];
52 return i;
53 }
54};
55
56int A::count = 0;
57
58int g(int) {return 0;}
59
60int main(int, char**)
61{
62 globalMemCounter.reset();
63 assert(globalMemCounter.checkOutstandingNewEq(0));
64 {
65 std::function<int(int)> f = A();
66 assert(A::count == 1);
67 assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1));
68 RTTI_ASSERT(f.target<A>());
69 RTTI_ASSERT(f.target<int(*)(int)>() == 0);
70 std::function<int(int)> f2 = f;
71 assert(A::count == 2);
72 assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2));
73 RTTI_ASSERT(f2.target<A>());
74 RTTI_ASSERT(f2.target<int(*)(int)>() == 0);
75 }
76 assert(A::count == 0);
77 assert(globalMemCounter.checkOutstandingNewEq(0));
78 {
79 std::function<int(int)> f = g;
80 assert(globalMemCounter.checkOutstandingNewEq(0));
81 RTTI_ASSERT(f.target<int(*)(int)>());
82 RTTI_ASSERT(f.target<A>() == 0);
83 std::function<int(int)> f2 = f;
84 assert(globalMemCounter.checkOutstandingNewEq(0));
85 RTTI_ASSERT(f2.target<int(*)(int)>());
86 RTTI_ASSERT(f2.target<A>() == 0);
87 }
88 assert(globalMemCounter.checkOutstandingNewEq(0));
89 {
90 std::function<int(int)> f;
91 assert(globalMemCounter.checkOutstandingNewEq(0));
92 RTTI_ASSERT(f.target<int(*)(int)>() == 0);
93 RTTI_ASSERT(f.target<A>() == 0);
94 std::function<int(int)> f2 = f;
95 assert(globalMemCounter.checkOutstandingNewEq(0));
96 RTTI_ASSERT(f2.target<int(*)(int)>() == 0);
97 RTTI_ASSERT(f2.target<A>() == 0);
98 }
99 {
100 std::function<int(int)> f;
101 assert(globalMemCounter.checkOutstandingNewEq(0));
102 RTTI_ASSERT(f.target<int(*)(int)>() == 0);
103 RTTI_ASSERT(f.target<A>() == 0);
104 assert(!f);
105 std::function<long(int)> g = f;
106 assert(globalMemCounter.checkOutstandingNewEq(0));
107 RTTI_ASSERT(g.target<long(*)(int)>() == 0);
108 RTTI_ASSERT(g.target<A>() == 0);
109 assert(!g);
110 }
111#if TEST_STD_VER >= 11
112 assert(globalMemCounter.checkOutstandingNewEq(0));
113 { // Test rvalue references
114 std::function<int(int)> f = A();
115 assert(A::count == 1);
116 assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1));
117 RTTI_ASSERT(f.target<A>());
118 RTTI_ASSERT(f.target<int(*)(int)>() == 0);
119 LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
120#if TEST_STD_VER > 17
121 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
122#endif
123 std::function<int(int)> f2 = std::move(f);
124 assert(A::count == 1);
125 assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(1));
126 RTTI_ASSERT(f2.target<A>());
127 RTTI_ASSERT(f2.target<int(*)(int)>() == 0);
128 RTTI_ASSERT(f.target<A>() == 0);
129 RTTI_ASSERT(f.target<int(*)(int)>() == 0);
130 }
131 assert(globalMemCounter.checkOutstandingNewEq(0));
132 {
133 // Test that moving a function constructed from a reference wrapper
134 // is done without allocating.
135 DisableAllocationGuard g;
136 using Ref = std::reference_wrapper<A>;
137 A a;
138 Ref aref(a);
139 std::function<int(int)> f(aref);
140 assert(A::count == 1);
141 RTTI_ASSERT(f.target<A>() == nullptr);
142 RTTI_ASSERT(f.target<Ref>());
143 LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
144#if TEST_STD_VER > 17
145 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
146#endif
147 std::function<int(int)> f2(std::move(f));
148 assert(A::count == 1);
149 RTTI_ASSERT(f2.target<A>() == nullptr);
150 RTTI_ASSERT(f2.target<Ref>());
151#if defined(_LIBCPP_VERSION)
152 RTTI_ASSERT(f.target<Ref>()); // f is unchanged because the target is small
153#endif
154 }
155 {
156 // Test that moving a function constructed from a function pointer
157 // is done without allocating
158 DisableAllocationGuard guard;
159 using Ptr = int(*)(int);
160 Ptr p = g;
161 std::function<int(int)> f(p);
162 RTTI_ASSERT(f.target<A>() == nullptr);
163 RTTI_ASSERT(f.target<Ptr>());
164 LIBCPP_ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
165#if TEST_STD_VER > 17
166 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));
167#endif
168 std::function<int(int)> f2(std::move(f));
169 RTTI_ASSERT(f2.target<A>() == nullptr);
170 RTTI_ASSERT(f2.target<Ptr>());
171#if defined(_LIBCPP_VERSION)
172 RTTI_ASSERT(f.target<Ptr>()); // f is unchanged because the target is small
173#endif
174 }
175#endif // TEST_STD_VER >= 11
176
177 return 0;
178}
179

source code of libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/copy_move.pass.cpp