|  | // Copyright 2022 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/functional/function_ref.h" | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <concepts> | 
|  | #include <optional> | 
|  |  | 
|  | #include "base/compiler_specific.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/abseil-cpp/absl/functional/function_ref.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | char Func(float) { | 
|  | return 'a'; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST(FunctionRef, Lambda) { | 
|  | auto add = [](int a, int b) { return a + b; }; | 
|  |  | 
|  | { | 
|  | const FunctionRef<int(int, int)> ref = add; | 
|  | EXPECT_EQ(19, ref(17, 2)); | 
|  | } | 
|  |  | 
|  | { | 
|  | const auto add_const = add; | 
|  | const FunctionRef<int(int, int)> ref = add_const; | 
|  | EXPECT_EQ(19, ref(17, 2)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, CapturingLambda) { | 
|  | int x = 3; | 
|  | const auto lambda = [&x] { return x; }; | 
|  | FunctionRef<int()> ref = lambda; | 
|  | EXPECT_EQ(3, ref()); | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, FunctionPtr) { | 
|  | [](FunctionRef<char(float)> ref) { EXPECT_EQ('a', ref(1.0)); }(&Func); | 
|  | const FunctionRef<char(float)> ref = +[](float) { return 'a'; }; | 
|  | EXPECT_EQ('a', ref(1.0f)); | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, Functor) { | 
|  | struct S { | 
|  | int operator()(int x) const { return x; } | 
|  | }; | 
|  | const S s; | 
|  | const FunctionRef<int(int)> ref = s; | 
|  | EXPECT_EQ(17, ref(17)); | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, Method) { | 
|  | struct S { | 
|  | int Method() const { return value; } | 
|  |  | 
|  | const int value; | 
|  | }; | 
|  | const S s(25); | 
|  | [&s](FunctionRef<int(const S*)> ref) { EXPECT_EQ(25, ref(&s)); }(&S::Method); | 
|  | } | 
|  |  | 
|  | // If we construct from another `FunctionRef`, that should work fine, even if | 
|  | // the input is destroyed before we call the output. In other words, we should | 
|  | // reference the underlying callable, not the `FunctionRef`. | 
|  | // | 
|  | // We construct in a `noinline` function to maximize the chance that ASAN | 
|  | // notices the use-after-free if we get this wrong. | 
|  | NOINLINE void ConstructFromLValue(std::optional<FunctionRef<int()>>& ref) { | 
|  | const auto return_17 = [] { return 17; }; | 
|  | FunctionRef<int()> other = return_17; | 
|  | ref.emplace(other); | 
|  | } | 
|  | NOINLINE void ConstructFromConstLValue(std::optional<FunctionRef<int()>>& ref) { | 
|  | const auto return_17 = [] { return 17; }; | 
|  | const FunctionRef<int()> other = return_17; | 
|  | ref.emplace(other); | 
|  | } | 
|  | NOINLINE void ConstructFromRValue(std::optional<FunctionRef<int()>>& ref) { | 
|  | const auto return_17 = [] { return 17; }; | 
|  | using Ref = FunctionRef<int()>; | 
|  | ref.emplace(Ref(return_17)); | 
|  | } | 
|  | NOINLINE void ConstructFromConstRValue(std::optional<FunctionRef<int()>>& ref) { | 
|  | const auto return_17 = [] { return 17; }; | 
|  | using Ref = const FunctionRef<int()>; | 
|  | ref.emplace(Ref(return_17)); | 
|  | } | 
|  | TEST(FunctionRef, ConstructionFromOtherFunctionRefObjects) { | 
|  | using Ref = FunctionRef<int()>; | 
|  | std::optional<Ref> ref; | 
|  |  | 
|  | ConstructFromLValue(ref); | 
|  | EXPECT_EQ(17, (*ref)()); | 
|  |  | 
|  | ConstructFromConstLValue(ref); | 
|  | EXPECT_EQ(17, (*ref)()); | 
|  |  | 
|  | ConstructFromRValue(ref); | 
|  | EXPECT_EQ(17, (*ref)()); | 
|  |  | 
|  | ConstructFromConstRValue(ref); | 
|  | EXPECT_EQ(17, (*ref)()); | 
|  |  | 
|  | // It shouldn't be possible to construct from `FunctionRef` objects with | 
|  | // differing signatures, even if they are compatible with `int()`. | 
|  | static_assert(!std::constructible_from<Ref, FunctionRef<void()>>); | 
|  | static_assert(!std::constructible_from<Ref, FunctionRef<int(int)>>); | 
|  | static_assert(!std::constructible_from<Ref, FunctionRef<int64_t()>>); | 
|  |  | 
|  | // Check again with various qualifiers. | 
|  | static_assert(!std::constructible_from<Ref, const FunctionRef<void()>>); | 
|  | static_assert(!std::constructible_from<Ref, FunctionRef<void()>&>); | 
|  | static_assert(!std::constructible_from<Ref, FunctionRef<void()>&&>); | 
|  | static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&>); | 
|  | static_assert(!std::constructible_from<Ref, const FunctionRef<void()>&&>); | 
|  | } | 
|  |  | 
|  | // `FunctionRef` allows functors with convertible return types to be adapted. | 
|  | TEST(FunctionRef, ConvertibleReturnTypes) { | 
|  | { | 
|  | const auto lambda = [] { return true; }; | 
|  | const FunctionRef<int()> ref = lambda; | 
|  | EXPECT_EQ(1, ref()); | 
|  | } | 
|  |  | 
|  | { | 
|  | class Base {}; | 
|  | class Derived : public Base {}; | 
|  |  | 
|  | const auto lambda = []() -> Derived* { return nullptr; }; | 
|  | const FunctionRef<const Base*()> ref = lambda; | 
|  | EXPECT_EQ(nullptr, ref()); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, ConstructionFromInexactMatches) { | 
|  | // Lambda. | 
|  | const auto lambda = [](int32_t x) { return x; }; | 
|  |  | 
|  | // Capturing lambda. | 
|  | const auto capturing_lambda = [&](int32_t x) { return lambda(x); }; | 
|  |  | 
|  | // Function pointer. | 
|  | int32_t (*const function_ptr)(int32_t) = +lambda; | 
|  |  | 
|  | // Functor. | 
|  | struct Functor { | 
|  | int32_t operator()(int32_t x) const { return x; } | 
|  | }; | 
|  | const Functor functor; | 
|  |  | 
|  | // Method. | 
|  | struct Obj { | 
|  | int32_t Method(int32_t x) const { return x; } | 
|  | }; | 
|  | int32_t (Obj::*const method)(int32_t) const = &Obj::Method; | 
|  |  | 
|  | // Each of the objects above should work for a `FunctionRef` with a | 
|  | // convertible return type. In this case, they all return `int32_t`, which | 
|  | // should be seamlessly convertible to `int64_t` below. | 
|  | static_assert( | 
|  | std::constructible_from<FunctionRef<int64_t(int32_t)>, decltype(lambda)>); | 
|  | static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, | 
|  | decltype(capturing_lambda)>); | 
|  | static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, | 
|  | decltype(function_ptr)>); | 
|  | static_assert(std::constructible_from<FunctionRef<int64_t(int32_t)>, | 
|  | decltype(functor)>); | 
|  | static_assert( | 
|  | std::constructible_from<FunctionRef<int64_t(const Obj*, int32_t)>, | 
|  | decltype(method)>); | 
|  |  | 
|  | // It shouldn't be possible to construct a `FunctionRef` from any of the | 
|  | // objects above if we discard the return value. | 
|  | static_assert( | 
|  | !std::constructible_from<FunctionRef<void(int32_t)>, decltype(lambda)>); | 
|  | static_assert(!std::constructible_from<FunctionRef<void(int32_t)>, | 
|  | decltype(capturing_lambda)>); | 
|  | static_assert(!std::constructible_from<FunctionRef<void(int32_t)>, | 
|  | decltype(function_ptr)>); | 
|  | static_assert( | 
|  | !std::constructible_from<FunctionRef<void(int32_t)>, decltype(functor)>); | 
|  | static_assert(!std::constructible_from<FunctionRef<void(const Obj*, int32_t)>, | 
|  | decltype(method)>); | 
|  |  | 
|  | // It shouldn't be possible to construct a `FunctionRef` from a pointer to a | 
|  | // functor, even with a compatible signature. | 
|  | static_assert(!std::constructible_from<FunctionRef<int32_t(int32_t)>, | 
|  | decltype(&functor)>); | 
|  | } | 
|  |  | 
|  | TEST(FunctionRef, ConstructionFromAbslFunctionRef) { | 
|  | // It shouldn't be possible to construct a `FunctionRef` from an | 
|  | // `absl::FunctionRef`, whether the signatures are compatible or not. | 
|  | using Ref = FunctionRef<int(int)>; | 
|  | static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void()>>); | 
|  | static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<void(int)>>); | 
|  | static_assert(!std::is_constructible_v<Ref, absl::FunctionRef<int(int)>>); | 
|  |  | 
|  | // Check again with various qualifiers. | 
|  | using AbslRef = absl::FunctionRef<int(int)>; | 
|  | static_assert(!std::is_constructible_v<Ref, const AbslRef>); | 
|  | static_assert(!std::is_constructible_v<Ref, AbslRef&>); | 
|  | static_assert(!std::is_constructible_v<Ref, AbslRef&&>); | 
|  | static_assert(!std::is_constructible_v<Ref, const AbslRef&>); | 
|  | static_assert(!std::is_constructible_v<Ref, const AbslRef&&>); | 
|  | } | 
|  |  | 
|  | }  // namespace base |