| // 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 <atomic> | |
| #include <functional> | |
| #include <memory> | |
| #include <type_traits> | |
| #include <utility> | |
| #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 <typename T> | |
| T Dereference(const T* v) { | |
| return *v; | |
| } | |
| template <typename T> | |
| T Copy(const T& v) { | |
| return v; | |
| } | |
| TEST(FunctionRefTest, Function1) { | |
| FunctionRef<int()> ref(&Function); | |
| EXPECT_EQ(1337, ref()); | |
| } | |
| TEST(FunctionRefTest, Function2) { | |
| FunctionRef<int()> ref(Function); | |
| EXPECT_EQ(1337, ref()); | |
| } | |
| TEST(FunctionRefTest, ConstFunction) { | |
| FunctionRef<int() const> ref(Function); | |
| EXPECT_EQ(1337, ref()); | |
| } | |
| TEST(FunctionRefTest, CopyAssignment) { | |
| FunctionRef<int()> a = +[]() -> int { | |
| ADD_FAILURE() << "Unexpectedly called"; | |
| return 0; | |
| }; | |
| FunctionRef<int()> 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<int()> ref(NoExceptFunction); | |
| EXPECT_EQ(1337, ref()); | |
| } | |
| TEST(FunctionRefTest, ForwardsArgs) { | |
| auto l = [](std::unique_ptr<int> i) { return *i; }; | |
| FunctionRef<int(std::unique_ptr<int>)> ref(l); | |
| EXPECT_EQ(42, ref(std::make_unique<int>(42))); | |
| } | |
| TEST(FunctionRef, ReturnMoveOnly) { | |
| auto l = [] { return std::make_unique<int>(29); }; | |
| FunctionRef<std::unique_ptr<int>()> ref(l); | |
| EXPECT_EQ(29, *ref()); | |
| } | |
| TEST(FunctionRef, ManyArgs) { | |
| auto l = [](int a, int b, int c) { return a + b + c; }; | |
| FunctionRef<int(int, int, int)> ref(l); | |
| EXPECT_EQ(6, ref(1, 2, 3)); | |
| } | |
| TEST(FunctionRef, VoidResultFromNonVoidFunctor) { | |
| bool ran = false; | |
| auto l = [&]() -> int { | |
| ran = true; | |
| return 2; | |
| }; | |
| FunctionRef<void()> 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<void(Derived*)> ref1(l1); | |
| ref1(&d); | |
| auto l2 = [&]() -> Derived* { return &d; }; | |
| FunctionRef<Base*()> ref2(l2); | |
| EXPECT_EQ(&d, ref2()); | |
| } | |
| TEST(FunctionRef, VoidResultFromNonVoidFuncton) { | |
| FunctionRef<void()> ref(Function); | |
| ref(); | |
| } | |
| TEST(FunctionRef, MemberPtr) { | |
| struct S { | |
| int i; | |
| }; | |
| S s{1100111}; | |
| auto mem_ptr = &S::i; | |
| FunctionRef<int(const S& s)> 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<int(const S& s)> 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<int(S && s)> 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<int(S && s)> ref(mem_fun_ptr); }, ""); | |
| } | |
| TEST(FunctionRef, NullMemberPtrAssertFails) { | |
| struct S { | |
| int i; | |
| }; | |
| using MemberPtr = int S::*; | |
| MemberPtr mem_ptr = nullptr; | |
| EXPECT_DEBUG_DEATH({ FunctionRef<int(const S& s)> ref(mem_ptr); }, ""); | |
| } | |
| TEST(FunctionRef, NullStdFunctionAssertPasses) { | |
| std::function<void()> function = []() {}; | |
| FunctionRef<void()> ref(function); | |
| } | |
| TEST(FunctionRef, NullStdFunctionAssertFails) { | |
| std::function<void()> function = nullptr; | |
| EXPECT_DEBUG_DEATH({ FunctionRef<void()> ref(function); }, ""); | |
| } | |
| TEST(FunctionRef, NullAnyInvocableAssertPasses) { | |
| AnyInvocable<void() const> invocable = []() {}; | |
| FunctionRef<void()> ref(invocable); | |
| } | |
| TEST(FunctionRef, NullAnyInvocableAssertFails) { | |
| AnyInvocable<void() const> invocable = nullptr; | |
| EXPECT_DEBUG_DEATH({ FunctionRef<void()> 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<void(absl::test_internal::CopyableMovableInstance)> 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<void(const absl::test_internal::CopyableMovableInstance&)> 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<void(absl::test_internal::CopyableMovableInstance)> 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<void(absl::test_internal::CopyableMovableInstance)> 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<Invoker<void, int>, void (*)(VoidPtr, int)>, | |
| "Scalar types should be passed by value"); | |
| static_assert( | |
| std::is_same_v<Invoker<void, Trivial>, void (*)(VoidPtr, Trivial)>, | |
| "Small trivial types should be passed by value"); | |
| static_assert(std::is_same_v<Invoker<void, LargeTrivial>, | |
| void (*)(VoidPtr, LargeTrivial&&)>, | |
| "Large trivial types should be passed by rvalue reference"); | |
| static_assert( | |
| std::is_same_v<Invoker<void, CopyableMovableInstance>, | |
| 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<Invoker<void, int&>, void (*)(VoidPtr, int&)>, | |
| "Reference types should be preserved"); | |
| static_assert(std::is_same_v<Invoker<void, CopyableMovableInstance&>, | |
| void (*)(VoidPtr, CopyableMovableInstance&)>, | |
| "Reference types should be preserved"); | |
| static_assert(std::is_same_v<Invoker<void, CopyableMovableInstance&&>, | |
| 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<void(LargeTrivial&)> ref(test); | |
| ref(obj); | |
| } | |
| { | |
| Trivial obj; | |
| auto test = [&obj](Trivial& input) { ASSERT_EQ(&input, &obj); }; | |
| absl::FunctionRef<void(Trivial&)> ref(test); | |
| ref(obj); | |
| } | |
| } | |
| TEST(FunctionRef, ReferenceToIncompleteType) { | |
| struct IncompleteType; | |
| auto test = [](IncompleteType&) {}; | |
| absl::FunctionRef<void(IncompleteType&)> 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<int()>(s)()); | |
| EXPECT_EQ(1337, FunctionRef<int() const>(s)()); | |
| EXPECT_EQ(1337, FunctionRef<int()>(std::as_const(s))()); | |
| EXPECT_EQ(1337, FunctionRef<int() const>(std::as_const(s))()); | |
| } | |
| TEST(FunctionRefTest, Lambdas) { | |
| // Stateless lambdas implicitly convert to function pointers, so their | |
| // mutability is irrelevant. | |
| EXPECT_TRUE(FunctionRef<bool()>([]() /*const*/ { return true; })()); | |
| EXPECT_TRUE(FunctionRef<bool()>([]() mutable { return true; })()); | |
| EXPECT_TRUE(FunctionRef<bool() const>([]() /*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<bool() const>([]() 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<bool()>([v = true]() /*const*/ { return v; })()); | |
| EXPECT_TRUE(FunctionRef<bool()>([v = true]() mutable { return v; })()); | |
| EXPECT_TRUE( | |
| FunctionRef<bool() const>([v = true]() /*const*/ { return v; })()); | |
| const auto func = [v = true]() mutable { return v; }; | |
| static_assert( | |
| !std::is_convertible_v<decltype(func), FunctionRef<bool() const>>); | |
| } | |
| #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L | |
| static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::Func>, | |
| std::declval<Class&>())), | |
| FunctionRef<int()>>); | |
| static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::CFunc>, | |
| std::declval<Class&>())), | |
| FunctionRef<int() const>>); | |
| static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::Func>, | |
| std::declval<Class*>())), | |
| FunctionRef<int()>>); | |
| static_assert(std::is_same_v<decltype(FunctionRef(nontype<&Class::CFunc>, | |
| std::declval<Class*>())), | |
| FunctionRef<int() const>>); | |
| TEST(FunctionRefTest, NonTypeParameterWithTemporaries) { | |
| static_assert(!std::is_constructible_v<FunctionRef<int()>, | |
| nontype_t<&Class::Func>, Class&&>); | |
| static_assert( | |
| !std::is_constructible_v<FunctionRef<int()>, nontype_t<&Class::Func>, | |
| const Class&&>); | |
| static_assert(!std::is_constructible_v<FunctionRef<int() const>, | |
| nontype_t<&Class::CFunc>, Class&&>); | |
| static_assert( | |
| !std::is_constructible_v<FunctionRef<int() const>, | |
| nontype_t<&Class::CFunc>, const Class&&>); | |
| } | |
| TEST(FunctionRefTest, NonTypeParameterWithDeductionGuides) { | |
| EXPECT_EQ(1337, FunctionRef(nontype<&Function>)()); | |
| EXPECT_EQ(42, FunctionRef(nontype<&Copy<int>>, | |
| std::integral_constant<int, 42>::value)()); | |
| EXPECT_EQ(42, FunctionRef(nontype<&Dereference<int>>, | |
| &std::integral_constant<int, 42>::value)()); | |
| Class c; | |
| EXPECT_EQ(42, FunctionRef<int()>(nontype<&Class::Func>, c)()); | |
| EXPECT_EQ(43, FunctionRef<int() const>(nontype<&Class::CFunc>, c)()); | |
| EXPECT_EQ(42, FunctionRef<int()>(nontype<&Class::Func>, &c)()); | |
| EXPECT_EQ(43, FunctionRef<int() const>(nontype<&Class::CFunc>, &c)()); | |
| } | |
| #endif | |
| TEST(FunctionRefTest, OptionalArguments) { | |
| struct S { | |
| int operator()(int = 0) const { return 1337; } | |
| }; | |
| S s; | |
| EXPECT_EQ(1337, FunctionRef<int()>(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<int()> a = +[]() { return 1; }; | |
| absl::FunctionRef<int() const> b = a; | |
| a = +[]() { return 2; }; | |
| EXPECT_EQ(b(), 2); | |
| } | |
| } // namespace | |
| ABSL_NAMESPACE_END | |
| } // namespace absl |