15a83710eSEric Fiselier //===----------------------------------------------------------------------===//
25a83710eSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65a83710eSEric Fiselier //
75a83710eSEric Fiselier //===----------------------------------------------------------------------===//
85a83710eSEric Fiselier 
931cbe0f2SLouis Dionne // UNSUPPORTED: c++03
10bd23d4daSEric Fiselier // REQUIRES: c++11 || c++14
114c46801fSEric Fiselier 
125a83710eSEric Fiselier // <functional>
135a83710eSEric Fiselier 
145a83710eSEric Fiselier // class function<R(ArgTypes...)>
155a83710eSEric Fiselier 
165a83710eSEric Fiselier // template<class A> function(allocator_arg_t, const A&, function&&);
176ecac730SMarshall Clow //
186ecac730SMarshall Clow // This signature was removed in C++17
195a83710eSEric Fiselier 
205a83710eSEric Fiselier #include <functional>
214c46801fSEric Fiselier #include <memory>
225a83710eSEric Fiselier #include <cassert>
235a83710eSEric Fiselier 
244c46801fSEric Fiselier #include "test_macros.h"
256d370568SEric Fiselier #include "min_allocator.h"
26cc89063bSNico Weber #include "count_new.h"
275a83710eSEric Fiselier 
285a83710eSEric Fiselier class A
295a83710eSEric Fiselier {
305a83710eSEric Fiselier     int data_[10];
315a83710eSEric Fiselier public:
325a83710eSEric Fiselier     static int count;
335a83710eSEric Fiselier 
A()345a83710eSEric Fiselier     A()
355a83710eSEric Fiselier     {
365a83710eSEric Fiselier         ++count;
375a83710eSEric Fiselier         for (int i = 0; i < 10; ++i)
385a83710eSEric Fiselier             data_[i] = i;
395a83710eSEric Fiselier     }
405a83710eSEric Fiselier 
A(const A &)415a83710eSEric Fiselier     A(const A&) {++count;}
425a83710eSEric Fiselier 
~A()435a83710eSEric Fiselier     ~A() {--count;}
445a83710eSEric Fiselier 
operator ()(int i) const455a83710eSEric Fiselier     int operator()(int i) const
465a83710eSEric Fiselier     {
475a83710eSEric Fiselier         for (int j = 0; j < 10; ++j)
485a83710eSEric Fiselier             i += data_[j];
495a83710eSEric Fiselier         return i;
505a83710eSEric Fiselier     }
515a83710eSEric Fiselier };
525a83710eSEric Fiselier 
535a83710eSEric Fiselier int A::count = 0;
545a83710eSEric Fiselier 
g(int)554c46801fSEric Fiselier int g(int) { return 0; }
564c46801fSEric Fiselier 
main(int,char **)572df59c50SJF Bastien int main(int, char**)
585a83710eSEric Fiselier {
590b43db52SDan Albert   globalMemCounter.reset();
602cbc654dSEric Fiselier   assert(globalMemCounter.checkOutstandingNewEq(0));
615a83710eSEric Fiselier   {
625a83710eSEric Fiselier     std::function<int(int)> f = A();
635a83710eSEric Fiselier     assert(A::count == 1);
642cbc654dSEric Fiselier     assert(globalMemCounter.checkOutstandingNewEq(1));
65*bb09ef95SLouis Dionne     RTTI_ASSERT(f.target<A>());
66*bb09ef95SLouis Dionne     RTTI_ASSERT(f.target<int (*)(int)>() == 0);
670b43db52SDan Albert     std::function<int(int)> f2(std::allocator_arg, bare_allocator<A>(),
680b43db52SDan Albert                                std::move(f));
695a83710eSEric Fiselier     assert(A::count == 1);
702cbc654dSEric Fiselier     assert(globalMemCounter.checkOutstandingNewEq(1));
71*bb09ef95SLouis Dionne     RTTI_ASSERT(f2.target<A>());
72*bb09ef95SLouis Dionne     RTTI_ASSERT(f2.target<int (*)(int)>() == 0);
73*bb09ef95SLouis Dionne     RTTI_ASSERT(f.target<A>() == 0);
74*bb09ef95SLouis Dionne     RTTI_ASSERT(f.target<int (*)(int)>() == 0);
755a83710eSEric Fiselier   }
764c46801fSEric Fiselier     assert(globalMemCounter.checkOutstandingNewEq(0));
774c46801fSEric Fiselier     {
784c46801fSEric Fiselier         // Test that moving a function constructed from a reference wrapper
794c46801fSEric Fiselier         // is done without allocating.
804c46801fSEric Fiselier         DisableAllocationGuard g;
814c46801fSEric Fiselier         using Ref = std::reference_wrapper<A>;
824c46801fSEric Fiselier         A a;
834c46801fSEric Fiselier         Ref aref(a);
844c46801fSEric Fiselier         std::function<int(int)> f(aref);
854c46801fSEric Fiselier         assert(A::count == 1);
86*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<A>() == nullptr);
87*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<Ref>());
885b1e5b43SMichael Park         std::function<int(int)> f2(std::allocator_arg, std::allocator<int>{},
894c46801fSEric Fiselier                                    std::move(f));
904c46801fSEric Fiselier         assert(A::count == 1);
91*bb09ef95SLouis Dionne         RTTI_ASSERT(f2.target<A>() == nullptr);
92*bb09ef95SLouis Dionne         RTTI_ASSERT(f2.target<Ref>());
93*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<Ref>()); // f is unchanged because the target is small
944c46801fSEric Fiselier     }
954c46801fSEric Fiselier     {
964c46801fSEric Fiselier         // Test that moving a function constructed from a function pointer
974c46801fSEric Fiselier         // is done without allocating
984c46801fSEric Fiselier         DisableAllocationGuard guard;
994c46801fSEric Fiselier         using Ptr = int(*)(int);
1004c46801fSEric Fiselier         Ptr p = g;
1014c46801fSEric Fiselier         std::function<int(int)> f(p);
102*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<A>() == nullptr);
103*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<Ptr>());
1045b1e5b43SMichael Park         std::function<int(int)> f2(std::allocator_arg, std::allocator<int>(),
1054c46801fSEric Fiselier                                    std::move(f));
106*bb09ef95SLouis Dionne         RTTI_ASSERT(f2.target<A>() == nullptr);
107*bb09ef95SLouis Dionne         RTTI_ASSERT(f2.target<Ptr>());
108*bb09ef95SLouis Dionne         RTTI_ASSERT(f.target<Ptr>()); // f is unchanged because the target is small
1094c46801fSEric Fiselier     }
1102df59c50SJF Bastien 
1112df59c50SJF Bastien   return 0;
1125a83710eSEric Fiselier }
113