175 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++0310 11// <functional>12 13// class function<R(ArgTypes...)>14 15// function(const function& f);16// function(function&& f); // noexcept in C++2017 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 A28{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) const45 {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 >= 11108 assert(globalMemCounter.checkOutstandingNewEq(0));109 { // Test rvalue references110 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 > 17117 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));118#endif119 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 wrapper130 // 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 > 17141 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));142#endif143 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 small149#endif150 }151 {152 // Test that moving a function constructed from a function pointer153 // is done without allocating154 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 > 17162 ASSERT_NOEXCEPT(std::function<int(int)>(std::move(f)));163#endif164 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 small169#endif170 }171#endif // TEST_STD_VER >= 11172 173 return 0;174}175