#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';
}
}
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);
}
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)());
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()>>);
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()>&&>);
}
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) {
const auto lambda = [](int32_t x) { return x; };
const auto capturing_lambda = [&](int32_t x) { return lambda(x); };
int32_t (*const function_ptr)(int32_t) = +lambda;
struct Functor {
int32_t operator()(int32_t x) const { return x; }
};
const Functor functor;
struct Obj {
int32_t Method(int32_t x) const { return x; }
};
int32_t (Obj::*const method)(int32_t) const = &Obj::Method;
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)>);
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)>);
static_assert(!std::constructible_from<FunctionRef<int32_t(int32_t)>,
decltype(&functor)>);
}
TEST(FunctionRef, ConstructionFromAbslFunctionRef) {
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)>>);
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&&>);
}
}