#include "function_ref.h" #include Y_UNIT_TEST_SUITE(TestFunctionRef) { template struct TTestFunction; template struct TTestFunction { Ret operator()(Args...) const noexcept(IsNoexcept) { return {}; } }; Y_UNIT_TEST(NonDefaultConstructible) { static_assert(!std::is_default_constructible_v>); static_assert(!std::is_default_constructible_v>); static_assert(!std::is_default_constructible_v)>>); } int F1(bool x) { if (x) throw 19; return 42; } int F2(bool x) noexcept { return 42 + x; } static const TTestFunction C1; static const TTestFunction C2; Y_UNIT_TEST(Noexcept) { static_assert(std::is_constructible_v, decltype(F1)>); static_assert(std::is_constructible_v, decltype(F2)>); static_assert(!std::is_constructible_v, decltype(F1)>); static_assert(std::is_constructible_v, decltype(F2)>); static_assert(std::is_constructible_v, decltype(C1)>); static_assert(std::is_constructible_v, decltype(C2)>); static_assert(!std::is_constructible_v, decltype(C1)>); static_assert(std::is_constructible_v, decltype(C2)>); } Y_UNIT_TEST(Deduction) { TFunctionRef ref1(F1); TFunctionRef ref2(F2); TFunctionRef ref3(C1); TFunctionRef ref4(C2); static_assert(!std::is_nothrow_invocable_r_v); static_assert(std::is_nothrow_invocable_r_v); static_assert(std::is_same_v); static_assert(std::is_same_v); } void WithCallback(TFunctionRef); void Iterate(int from, int to, TFunctionRef callback) { while (from < to) { callback(from++); } } void IterateNoexcept(int from, int to, TFunctionRef callback) { while (from < to) { callback(from++); } } Y_UNIT_TEST(AsArgument) { int sum = 0; Iterate(0, 10, [&](int x) { sum += x; }); UNIT_ASSERT_EQUAL(sum, 45); Iterate(0, 10, [&](int x) noexcept { sum += x; }); UNIT_ASSERT_EQUAL(sum, 90); IterateNoexcept(0, 10, [&](int x) noexcept { sum += x; }); UNIT_ASSERT_EQUAL(sum, 135); auto summer = [&](int x) { sum += x; }; Iterate(0, 10, summer); Iterate(0, 10, summer); Iterate(0, 10, summer); UNIT_ASSERT_EQUAL(sum, 270); TFunctionRef ref = summer; Iterate(0, 10, ref); UNIT_ASSERT_EQUAL(sum, 315); } int GlobalSum = 0; void AddToGlobalSum(int x) { GlobalSum += x; } Y_UNIT_TEST(FunctionPointer) { GlobalSum = 0; Iterate(0, 10, AddToGlobalSum); UNIT_ASSERT_EQUAL(GlobalSum, 45); TFunctionRef ref1 = AddToGlobalSum; Iterate(0, 10, ref1); UNIT_ASSERT_EQUAL(GlobalSum, 90); TFunctionRef ref2{AddToGlobalSum}; Iterate(0, 10, ref2); UNIT_ASSERT_EQUAL(GlobalSum, 135); } Y_UNIT_TEST(Reassign) { TFunctionRef kek = [](double) { return 42; }; kek = [](double) { return 19; }; kek = [](int) { return 22.8; }; } const char* Greet() { return "Hello, world!"; } Y_UNIT_TEST(ImplicitCasts) { TFunctionRef ref = [](int x) { return x; }; ref = [](double x) { return x; }; ref = [](char x) { return x; }; TFunctionRef ref1 = [] { return 0.5; }; ref1 = [] { return 'a'; }; ref1 = [] { return 124u; }; TFunctionRef ref2{Greet}; } Y_UNIT_TEST(StatelessLambdaLifetime) { TFunctionRef ref{[](int a, int b) { return a + b; }}; UNIT_ASSERT_EQUAL(ref(5, 5), 10); } Y_UNIT_TEST(ForwardArguments) { char x = 'x'; TFunctionRef, char&)> ref = [](std::unique_ptr ptr, char& ch) { UNIT_ASSERT_EQUAL(*ptr, 5); ch = 'a'; }; ref(std::make_unique(5), x); UNIT_ASSERT_EQUAL(x, 'a'); } }