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

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