|
@@ -0,0 +1,150 @@
|
|
|
+#include "function_ref.h"
|
|
|
+
|
|
|
+#include <library/cpp/testing/unittest/registar.h>
|
|
|
+
|
|
|
+Y_UNIT_TEST_SUITE(TestFunctionRef) {
|
|
|
+ template <typename Signature>
|
|
|
+ struct TTestFunction;
|
|
|
+
|
|
|
+ template <typename Ret, typename... Args, bool IsNoexcept>
|
|
|
+ struct TTestFunction<Ret(Args...) noexcept(IsNoexcept)> {
|
|
|
+ Ret operator()(Args...) const noexcept(IsNoexcept) {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ Y_UNIT_TEST(NonDefaultConstructible) {
|
|
|
+ static_assert(!std::is_default_constructible_v<TFunctionRef<void()>>);
|
|
|
+ static_assert(!std::is_default_constructible_v<TFunctionRef<void() noexcept>>);
|
|
|
+ static_assert(!std::is_default_constructible_v<TFunctionRef<int(double, void********* megaptr, TTestFunction<void(int)>)>>);
|
|
|
+ }
|
|
|
+
|
|
|
+ int F1(bool x) {
|
|
|
+ if (x)
|
|
|
+ throw 19;
|
|
|
+ return 42;
|
|
|
+ }
|
|
|
+
|
|
|
+ int F2(bool x) noexcept {
|
|
|
+ return 42 + x;
|
|
|
+ }
|
|
|
+
|
|
|
+ static const TTestFunction<int(bool)> C1;
|
|
|
+ static const TTestFunction<int(bool) noexcept> C2;
|
|
|
+
|
|
|
+ Y_UNIT_TEST(Noexcept) {
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(F1)>);
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(F2)>);
|
|
|
+ static_assert(!std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(F1)>);
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(F2)>);
|
|
|
+
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(C1)>);
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool)>, decltype(C2)>);
|
|
|
+ static_assert(!std::is_constructible_v<TFunctionRef<int(bool) noexcept>, decltype(C1)>);
|
|
|
+ static_assert(std::is_constructible_v<TFunctionRef<int(bool) noexcept>, 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<int, decltype(ref1), bool>);
|
|
|
+ static_assert(std::is_nothrow_invocable_r_v<int, decltype(ref2), bool>);
|
|
|
+ static_assert(std::is_same_v<decltype(ref1)::TSignature, int(bool)>);
|
|
|
+ static_assert(std::is_same_v<decltype(ref2)::TSignature, int(bool) noexcept>);
|
|
|
+ }
|
|
|
+
|
|
|
+ void WithCallback(TFunctionRef<double(double, int) noexcept>);
|
|
|
+
|
|
|
+ void Iterate(int from, int to, TFunctionRef<void(int)> callback) {
|
|
|
+ while (from < to) {
|
|
|
+ callback(from++);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void IterateNoexcept(int from, int to, TFunctionRef<void(int) noexcept> 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<void(int)> ref = [](int x) { return x; };
|
|
|
+ ref = [](double x) { return x; };
|
|
|
+ ref = [](char x) { return x; };
|
|
|
+
|
|
|
+ TFunctionRef<int()> ref1 = [] { return 0.5; };
|
|
|
+ ref1 = [] { return 'a'; };
|
|
|
+ ref1 = [] { return 124u; };
|
|
|
+
|
|
|
+ TFunctionRef<TStringBuf()> ref2{Greet};
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(StatelessLambdaLifetime) {
|
|
|
+ TFunctionRef<int(int, int)> ref{[](int a, int b) { return a + b; }};
|
|
|
+ UNIT_ASSERT_EQUAL(ref(5, 5), 10);
|
|
|
+ }
|
|
|
+
|
|
|
+ Y_UNIT_TEST(ForwardArguments) {
|
|
|
+ char x = 'x';
|
|
|
+ TFunctionRef<void(std::unique_ptr<int>, char&)> ref = [](std::unique_ptr<int> ptr, char& ch) {
|
|
|
+ UNIT_ASSERT_EQUAL(*ptr, 5);
|
|
|
+ ch = 'a';
|
|
|
+ };
|
|
|
+ ref(std::make_unique<int>(5), x);
|
|
|
+ UNIT_ASSERT_EQUAL(x, 'a');
|
|
|
+ }
|
|
|
+}
|