// 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 "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/memory/memory.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace { void RunFun(FunctionRef f) { f(); } TEST(FunctionRefTest, Lambda) { bool ran = false; RunFun([&] { ran = true; }); EXPECT_TRUE(ran); } int Function() { return 1337; } TEST(FunctionRefTest, Function1) { FunctionRef ref(&Function); EXPECT_EQ(1337, ref()); } TEST(FunctionRefTest, Function2) { FunctionRef ref(Function); EXPECT_EQ(1337, ref()); } 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(absl::make_unique(42))); } TEST(FunctionRef, ReturnMoveOnly) { auto l = [] { return absl::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); }, ""); } #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, void (*)(VoidPtr, int)>::value, "Scalar types should be passed by value"); static_assert( std::is_same, void (*)(VoidPtr, Trivial)>::value, "Small trivial types should be passed by value"); static_assert(std::is_same, void (*)(VoidPtr, LargeTrivial &&)>::value, "Large trivial types should be passed by rvalue reference"); static_assert( std::is_same, void (*)(VoidPtr, CopyableMovableInstance &&)>::value, "Types with copy/move ctor should be passed by rvalue reference"); // References are passed as references. static_assert( std::is_same, void (*)(VoidPtr, int&)>::value, "Reference types should be preserved"); static_assert( std::is_same, void (*)(VoidPtr, CopyableMovableInstance&)>::value, "Reference types should be preserved"); static_assert( std::is_same, void (*)(VoidPtr, CopyableMovableInstance &&)>::value, "Reference types should be preserved"); // Make sure the address of an object received by reference is the same as the // addess 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); } } } // namespace ABSL_NAMESPACE_END } // namespace absl