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