// Copyright 2019 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/functional/function_ref.h" #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/functional/any_invocable.h" #include "absl/memory/memory.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { struct Class { int Func() { return 42; } int CFunc() const { return 43; } }; int Function() { return 1337; } template T Dereference(const T* v) { return *v; } template T Copy(const T& v) { return v; } TEST(FunctionRefTest, Function1) { FunctionRef ref(&Function); EXPECT_EQ(1337, ref()); } TEST(FunctionRefTest, Function2) { FunctionRef ref(Function); EXPECT_EQ(1337, ref()); } TEST(FunctionRefTest, ConstFunction) { FunctionRef ref(Function); EXPECT_EQ(1337, ref()); } TEST(FunctionRefTest, CopyAssignment) { FunctionRef a = +[]() -> int { ADD_FAILURE() << "Unexpectedly called"; return 0; }; FunctionRef b = +[] { return 1337; }; a = b; EXPECT_EQ(1337, a()); } int NoExceptFunction() noexcept { return 1337; } // TODO(jdennett): Add a test for noexcept member functions. TEST(FunctionRefTest, NoExceptFunction) { FunctionRef ref(NoExceptFunction); EXPECT_EQ(1337, ref()); } TEST(FunctionRefTest, ForwardsArgs) { auto l = [](std::unique_ptr i) { return *i; }; FunctionRef)> ref(l); EXPECT_EQ(42, ref(std::make_unique(42))); } TEST(FunctionRef, ReturnMoveOnly) { auto l = [] { return std::make_unique(29); }; FunctionRef()> ref(l); EXPECT_EQ(29, *ref()); } TEST(FunctionRef, ManyArgs) { auto l = [](int a, int b, int c) { return a + b + c; }; FunctionRef ref(l); EXPECT_EQ(6, ref(1, 2, 3)); } TEST(FunctionRef, VoidResultFromNonVoidFunctor) { bool ran = false; auto l = [&]() -> int { ran = true; return 2; }; FunctionRef ref(l); ref(); EXPECT_TRUE(ran); } TEST(FunctionRef, CastFromDerived) { struct Base {}; struct Derived : public Base {}; Derived d; auto l1 = [&](Base* b) { EXPECT_EQ(&d, b); }; FunctionRef ref1(l1); ref1(&d); auto l2 = [&]() -> Derived* { return &d; }; FunctionRef ref2(l2); EXPECT_EQ(&d, ref2()); } TEST(FunctionRef, VoidResultFromNonVoidFuncton) { FunctionRef ref(Function); ref(); } TEST(FunctionRef, MemberPtr) { struct S { int i; }; S s{1100111}; auto mem_ptr = &S::i; FunctionRef ref(mem_ptr); EXPECT_EQ(1100111, ref(s)); } TEST(FunctionRef, MemberFun) { struct S { int i; int get_i() const { return i; } }; S s{22}; auto mem_fun_ptr = &S::get_i; FunctionRef ref(mem_fun_ptr); EXPECT_EQ(22, ref(s)); } TEST(FunctionRef, MemberFunRefqualified) { struct S { int i; int get_i() && { return i; } }; auto mem_fun_ptr = &S::get_i; S s{22}; FunctionRef ref(mem_fun_ptr); EXPECT_EQ(22, ref(std::move(s))); } #if !defined(_WIN32) && defined(GTEST_HAS_DEATH_TEST) TEST(FunctionRef, MemberFunRefqualifiedNull) { struct S { int i; int get_i() && { return i; } }; auto mem_fun_ptr = &S::get_i; mem_fun_ptr = nullptr; EXPECT_DEBUG_DEATH({ FunctionRef ref(mem_fun_ptr); }, ""); } TEST(FunctionRef, NullMemberPtrAssertFails) { struct S { int i; }; using MemberPtr = int S::*; MemberPtr mem_ptr = nullptr; EXPECT_DEBUG_DEATH({ FunctionRef ref(mem_ptr); }, ""); } TEST(FunctionRef, NullStdFunctionAssertPasses) { std::function function = []() {}; FunctionRef ref(function); } TEST(FunctionRef, NullStdFunctionAssertFails) { std::function function = nullptr; EXPECT_DEBUG_DEATH({ FunctionRef ref(function); }, ""); } TEST(FunctionRef, NullAnyInvocableAssertPasses) { AnyInvocable invocable = []() {}; FunctionRef ref(invocable); } TEST(FunctionRef, NullAnyInvocableAssertFails) { AnyInvocable invocable = nullptr; EXPECT_DEBUG_DEATH({ FunctionRef ref(invocable); }, ""); } #endif // GTEST_HAS_DEATH_TEST TEST(FunctionRef, CopiesAndMovesPerPassByValue) { absl::test_internal::InstanceTracker tracker; absl::test_internal::CopyableMovableInstance instance(0); auto l = [](absl::test_internal::CopyableMovableInstance) {}; FunctionRef ref(l); ref(instance); EXPECT_EQ(tracker.copies(), 1); EXPECT_EQ(tracker.moves(), 1); } TEST(FunctionRef, CopiesAndMovesPerPassByRef) { absl::test_internal::InstanceTracker tracker; absl::test_internal::CopyableMovableInstance instance(0); auto l = [](const absl::test_internal::CopyableMovableInstance&) {}; FunctionRef ref(l); ref(instance); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 0); } TEST(FunctionRef, CopiesAndMovesPerPassByValueCallByMove) { absl::test_internal::InstanceTracker tracker; absl::test_internal::CopyableMovableInstance instance(0); auto l = [](absl::test_internal::CopyableMovableInstance) {}; FunctionRef ref(l); ref(std::move(instance)); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 2); } TEST(FunctionRef, CopiesAndMovesPerPassByValueToRef) { absl::test_internal::InstanceTracker tracker; absl::test_internal::CopyableMovableInstance instance(0); auto l = [](const absl::test_internal::CopyableMovableInstance&) {}; FunctionRef ref(l); ref(std::move(instance)); EXPECT_EQ(tracker.copies(), 0); EXPECT_EQ(tracker.moves(), 1); } TEST(FunctionRef, PassByValueTypes) { using absl::functional_internal::Invoker; using absl::functional_internal::VoidPtr; using absl::test_internal::CopyableMovableInstance; struct Trivial { void* p[2]; }; struct LargeTrivial { void* p[3]; }; static_assert(std::is_same_v, void (*)(VoidPtr, int)>, "Scalar types should be passed by value"); static_assert( std::is_same_v, void (*)(VoidPtr, Trivial)>, "Small trivial types should be passed by value"); static_assert(std::is_same_v, void (*)(VoidPtr, LargeTrivial&&)>, "Large trivial types should be passed by rvalue reference"); static_assert( std::is_same_v, void (*)(VoidPtr, CopyableMovableInstance&&)>, "Types with copy/move ctor should be passed by rvalue reference"); // References are passed as references. static_assert(std::is_same_v, void (*)(VoidPtr, int&)>, "Reference types should be preserved"); static_assert(std::is_same_v, void (*)(VoidPtr, CopyableMovableInstance&)>, "Reference types should be preserved"); static_assert(std::is_same_v, void (*)(VoidPtr, CopyableMovableInstance&&)>, "Reference types should be preserved"); // Make sure the address of an object received by reference is the same as the // address of the object passed by the caller. { LargeTrivial obj; auto test = [&obj](LargeTrivial& input) { ASSERT_EQ(&input, &obj); }; absl::FunctionRef ref(test); ref(obj); } { Trivial obj; auto test = [&obj](Trivial& input) { ASSERT_EQ(&input, &obj); }; absl::FunctionRef ref(test); ref(obj); } } TEST(FunctionRef, ReferenceToIncompleteType) { struct IncompleteType; auto test = [](IncompleteType&) {}; absl::FunctionRef ref(test); struct IncompleteType {}; IncompleteType obj; ref(obj); } TEST(FunctionRefTest, CorrectConstQualifiers) { struct S { int operator()() { return 42; } int operator()() const { return 1337; } }; S s; EXPECT_EQ(42, FunctionRef(s)()); EXPECT_EQ(1337, FunctionRef(s)()); EXPECT_EQ(1337, FunctionRef(std::as_const(s))()); EXPECT_EQ(1337, FunctionRef(std::as_const(s))()); } TEST(FunctionRefTest, Lambdas) { // Stateless lambdas implicitly convert to function pointers, so their // mutability is irrelevant. EXPECT_TRUE(FunctionRef([]() /*const*/ { return true; })()); EXPECT_TRUE(FunctionRef([]() mutable { return true; })()); EXPECT_TRUE(FunctionRef([]() /*const*/ { return true; })()); #if defined(__clang__) || (ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L && \ defined(_MSC_VER) && !defined(__EDG__)) // MSVC has problems compiling the following code pre-C++20: // const auto f = []() mutable {}; // f(); // EDG's MSVC-compatible mode (which Visual C++ uses for Intellisense) // exhibits the bug in C++20 as well. So we don't support them. EXPECT_TRUE(FunctionRef([]() mutable { return true; })()); #endif // Stateful lambdas are not implicitly convertible to function pointers, so // a const stateful lambda is not mutably callable. EXPECT_TRUE(FunctionRef([v = true]() /*const*/ { return v; })()); EXPECT_TRUE(FunctionRef([v = true]() mutable { return v; })()); EXPECT_TRUE( FunctionRef([v = true]() /*const*/ { return v; })()); const auto func = [v = true]() mutable { return v; }; static_assert( !std::is_convertible_v>); } #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L static_assert(std::is_same_v, std::declval())), FunctionRef>); static_assert(std::is_same_v, std::declval())), FunctionRef>); static_assert(std::is_same_v, std::declval())), FunctionRef>); static_assert(std::is_same_v, std::declval())), FunctionRef>); TEST(FunctionRefTest, NonTypeParameterWithTemporaries) { static_assert(!std::is_constructible_v, nontype_t<&Class::Func>, Class&&>); static_assert( !std::is_constructible_v, nontype_t<&Class::Func>, const Class&&>); static_assert(!std::is_constructible_v, nontype_t<&Class::CFunc>, Class&&>); static_assert( !std::is_constructible_v, nontype_t<&Class::CFunc>, const Class&&>); } TEST(FunctionRefTest, NonTypeParameterWithDeductionGuides) { EXPECT_EQ(1337, FunctionRef(nontype<&Function>)()); EXPECT_EQ(42, FunctionRef(nontype<&Copy>, std::integral_constant::value)()); EXPECT_EQ(42, FunctionRef(nontype<&Dereference>, &std::integral_constant::value)()); Class c; EXPECT_EQ(42, FunctionRef(nontype<&Class::Func>, c)()); EXPECT_EQ(43, FunctionRef(nontype<&Class::CFunc>, c)()); EXPECT_EQ(42, FunctionRef(nontype<&Class::Func>, &c)()); EXPECT_EQ(43, FunctionRef(nontype<&Class::CFunc>, &c)()); } #endif TEST(FunctionRefTest, OptionalArguments) { struct S { int operator()(int = 0) const { return 1337; } }; S s; EXPECT_EQ(1337, FunctionRef(s)()); } TEST(FunctionRefTest, NonConstToConstConversion) { // The const-qualified version might inherit from the non-const version. // We want to make sure that this doesn't introduce a bug when an instance of // the base (non-const) class is forwarded through the derived (const) class. // This has the potential to trigger the copy constructor, thus incorrectly // producing a copy rather than another indirection. absl::FunctionRef a = +[]() { return 1; }; absl::FunctionRef b = a; a = +[]() { return 2; }; EXPECT_EQ(b(), 2); } } // namespace ABSL_NAMESPACE_END } // namespace absl