aboutsummaryrefslogtreecommitdiffstats
path: root/test/test_functional_perf.hpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2022-10-07 04:23:47 +0200
committerSven Gothel <[email protected]>2022-10-07 04:23:47 +0200
commit247bf7968135fbd859ae6ac24d20ef7c221a4bbe (patch)
treefabe78200a3f3e29c0af06626765f0aebc5d730e /test/test_functional_perf.hpp
parent5299f1aecf3cc4462750f41ee4eee1d055cc956e (diff)
Revised jau::function: Revise back to vanilla Runtime Polymorphic `target_t<R(A...)>`
Drop target_t::delegate - implementation insufficient regarding C++ UB and not yet enought to show performance benefit - will be revised in upcoming commit for a pure Static Polymorphic delegate_t - maintain simplified code for target_t<R(A...)> and its specializations Use and expose jau::type_info and target size - originally used for lambda only, it might benefit users to query the type_info - same for target size lambda_target simplified via jau::type_info - encapsulated all RTTI/CTTI type_info, especially macros and equal operator Misc - Move target_t::size to function - function<R(A...)>::toString() Show prototype signature with demangled names (if available) and size. API: - function<R(A...)>: Remove cap[val|ref]'s dataIsIdentity param, handle as dataIsIdentity==true (always) - This simplifies the API and the data chunk shall always refer to its identity - Add function<R(A...)> for member of type C0 and this base-pointer of type C1 derived-of or same-as C0 - This allows passing a instance reference for this base-pointer, derived from the actually used member-function - Tested in test_function01's test01_memberfunc_this() +++ test_function01 - test01_memberfunc_this() covers different this base-pointer and member-function relationships - Use `constexpr jau::type_info::limited_lambda_id` instead of macro - Added test09_lambda_ctti() regarding RTTI/CTTI type name limitations test_function0_perf - Add test00_usage(), showing memory footprint ...
Diffstat (limited to 'test/test_functional_perf.hpp')
-rw-r--r--test/test_functional_perf.hpp265
1 files changed, 239 insertions, 26 deletions
diff --git a/test/test_functional_perf.hpp b/test/test_functional_perf.hpp
index eed367a..e007dc7 100644
--- a/test/test_functional_perf.hpp
+++ b/test/test_functional_perf.hpp
@@ -34,25 +34,135 @@
// Test examples.
class TestFunction01 {
- private:
+ public:
+ const int loops = 1000000;
- typedef int(*native_func_t)(int);
- typedef std::function<int(int)> std_func_t;
- typedef jau::function<int(int)> jau_func_t;
+ /**
+ * Unit test covering most variants of jau::function<R(A...)
+ */
+ void test00_usage() {
+ {
+ // Test capturing lambdas
+ volatile int i = 100;
+
+ {
+ jau::function<int(int)> fa0 = [&](int a) -> int {
+ return i + a;
+ };
+ fprintf(stderr, "lambda.ref: %s\n", fa0.toString().c_str());
+ REQUIRE( jau::func::target_type::lambda == fa0.type() );
+ }
+
+ {
+ jau::function<int(int)> fa0 = [i](int a) -> int {
+ return i + a;
+ };
+ fprintf(stderr, "lambda.copy: %s\n", fa0.toString().c_str());
+ REQUIRE( jau::func::target_type::lambda == fa0.type() );
+ }
+
+ {
+ // and this non-capturing lambda is also detected as lambda
+ jau::function<int(int)> fl3_1 = [](int a) -> int {
+ return a + 100;
+ } ;
+ fprintf(stderr, "lambda.plain %s\n", fl3_1.toString().c_str());
+ REQUIRE( jau::func::target_type::lambda == fl3_1.type() );
+ }
+ }
+ {
+ // free, result void and no params
+ typedef void(*cfunc)();
+ jau::function<void()> fl_0 = (cfunc) ( []() -> void {
+ // nop
+ } );
+ fprintf(stderr, "freeA.0 %s\n", fl_0.toString().c_str());
+ REQUIRE( jau::func::target_type::free == fl_0.type() );
+ }
+ {
+ // member, result non-void
+ jau::function<int(int)> f2a_0(this, &TestFunction01::func02a_member);
+ fprintf(stderr, "member: %s\n", f2a_0.toString().c_str());
+ REQUIRE( jau::func::target_type::member == f2a_0.type() );
+ }
+ {
+ // member, result void
+ jau::function<void(int&, int)> f2a_0(this, &TestFunction01::func12a_member);
+ fprintf(stderr, "member: %s\n", f2a_0.toString().c_str());
+ REQUIRE( jau::func::target_type::member == f2a_0.type() );
+ }
+ {
+ // Lambda alike w/ explicit capture by value, result non-void
+ int offset100 = 100;
- int func02a_member(int i) {
- int res = i+100;
- return res;;
- }
- static int Func03a_static(int i) {
- int res = i+100;
- return res;
- }
+ typedef int(*cfunc)(int&, int); // to force non-capturing lambda into a free function template type deduction
- public:
- const int loops = 1000000;
+ jau::function<int(int)> f5_o100_1 = jau::bind_capval(offset100,
+ (cfunc) ( [](int& capture, int i)->int {
+ int res = i+10000+capture;
+ return res;
+ } ) );
+ fprintf(stderr, "capval.small: %s\n", f5_o100_1.toString().c_str());
+ }
+ {
+ // Lambda alike w/ explicit capture by value, result non-void
+ struct blob {
+ int offset100 = 100;
+ uint64_t lala0 = 0;
+ uint64_t lala1 = 1;
+ uint64_t lala2 = 2;
+ uint64_t lala3 = 3;
+
+ bool operator==(const blob& rhs) const noexcept {
+ return offset100 == rhs.offset100 &&
+ lala0 == rhs.lala0 &&
+ lala1 == rhs.lala1 &&
+ lala2 == rhs.lala2 &&
+ lala3 == rhs.lala3;
+ }
+ bool operator!=(const blob& rhs) const noexcept
+ { return !( *this == rhs ); }
+
+ };
+ blob b0;
+
+ typedef int(*cfunc)(blob&, int); // to force non-capturing lambda into a free function template type deduction
+
+ jau::function<int(int)> f5_o100_1 = jau::bind_capval(b0,
+ (cfunc) ( [](blob& capture, int i)->int {
+ int res = i+10000+capture.offset100;
+ return res;
+ } ) );
+ fprintf(stderr, "capval.big: %s\n", f5_o100_1.toString().c_str());
+ }
+ {
+ // Lambda alike w/ explicit capture by reference, result non-void
+ int offset100 = 100;
- void test00_perf() {
+ typedef int(*cfunc)(int*, int); // to force non-capturing lambda into a free function template type deduction
+
+ jau::function<int(int)> f7_o100_1 = jau::bind_capref<int, int, int>(&offset100,
+ (cfunc) ( [](int* capture, int i)->int {
+ int res = i+10000+(*capture);
+ return res;;
+ } ) );
+ fprintf(stderr, "capref: %s\n", f7_o100_1.toString().c_str());
+ REQUIRE( jau::func::target_type::capref == f7_o100_1.type() );
+ }
+ {
+ // std::function lambda
+ std::function<int(int i)> func4a_stdlambda = [](int i)->int {
+ int res = i+100;
+ return res;;
+ };
+ jau::function<int(int)> f = jau::bind_std(100, func4a_stdlambda);
+ fprintf(stderr, "std.lambda: %s\n", f.toString().c_str());
+ fprintf(stderr, " (net std.lambda): sizeof %zu\n", sizeof(func4a_stdlambda));
+ REQUIRE( jau::func::target_type::std == f.type() );
+ }
+ }
+
+ void test10_perf() {
INFO("Test 00_usage: START");
// free raw func
@@ -79,10 +189,9 @@ class TestFunction01 {
};
}
-#if 1
// free std::function
{
- std_func_t f = TestFunction01::Func03a_static;
+ std::function<int(int)> f = TestFunction01::Func03a_static;
BENCHMARK("free_stdfunc") {
volatile int r=0;
@@ -92,7 +201,6 @@ class TestFunction01 {
return r;
};
}
-#endif
// free, jau::function
{
@@ -155,7 +263,46 @@ class TestFunction01 {
};
jau::function<int(int)> f = jau::bind_capval(offset100, func5a_capture);
- BENCHMARK("capval_lambda_jaufunc") {
+ BENCHMARK("capval_small_jaufunc") {
+ volatile int r=0;
+ for(int i=0; i<loops; ++i) {
+ r += f(i);
+ }
+ return r;
+ };
+ }
+
+ {
+ // Lambda alike w/ explicit capture by value, result non-void
+ struct blob {
+ int offset100 = 100;
+ uint64_t lala0 = 0;
+ uint64_t lala1 = 1;
+ uint64_t lala2 = 2;
+ uint64_t lala3 = 3;
+
+ bool operator==(const blob& rhs) const noexcept {
+ return offset100 == rhs.offset100 &&
+ lala0 == rhs.lala0 &&
+ lala1 == rhs.lala1 &&
+ lala2 == rhs.lala2 &&
+ lala3 == rhs.lala3;
+ }
+ bool operator!=(const blob& rhs) const noexcept
+ { return !( *this == rhs ); }
+
+ };
+ blob b0;
+
+ typedef int(*cfunc)(blob&, int); // to force non-capturing lambda into a free function template type deduction
+
+ jau::function<int(int)> f = jau::bind_capval(b0,
+ (cfunc) ( [](blob& capture, int i)->int {
+ int res = i+10000+capture.offset100;
+ return res;
+ } ) );
+
+ BENCHMARK("capval_big_jaufunc") {
volatile int r=0;
for(int i=0; i<loops; ++i) {
r += f(i);
@@ -175,7 +322,7 @@ class TestFunction01 {
};
jau::function<int(int)> f = jau::bind_capref(&offset100, func7a_capture);
- BENCHMARK("capref_lambda_jaufunc") {
+ BENCHMARK("capref_jaufunc") {
volatile int r=0;
for(int i=0; i<loops; ++i) {
r += f(i);
@@ -184,15 +331,14 @@ class TestFunction01 {
};
}
- // std::function lambda, jau::function
+ // std::function lambda
{
- std::function<int(int i)> l = [](int i)->int {
+ std::function<int(int i)> f = [](int i)->int {
int res = i+100;
return res;;
};
- jau::function<int(int)> f = jau::bind_std(100, l);
- BENCHMARK("std_function_lambda_jaufunc") {
+ BENCHMARK("lambda_std_function") {
volatile int r=0;
for(int i=0; i<loops; ++i) {
r += f(i);
@@ -210,7 +356,7 @@ class TestFunction01 {
return captured + a;
};
- BENCHMARK("clambda_jaufunc") {
+ BENCHMARK("lambda_jaufunc") {
volatile int r=0;
for(int i=0; i<loops; ++i) {
r += f(i);
@@ -224,6 +370,73 @@ class TestFunction01 {
INFO("Test 00_usage: END");
}
+
+ private:
+
+ typedef int(*native_func_t)(int);
+ typedef std::function<int(int)> std_func_t;
+ typedef jau::function<int(int)> jau_func_t;
+
+ // template<typename R, typename... A>
+ typedef int(*MyCFunc0)(int);
+
+ typedef jau::function<int(int)> MyClassFunction0;
+ typedef jau::function<void(int&, int)> MyClassFunction1;
+ typedef jau::function<void()> MyClassFunction2;
+
+ int func02a_member(int i) {
+ int res = i+100;
+ return res;;
+ }
+ int func02b_member(int i) noexcept {
+ int res = i+1000;
+ return res;
+ }
+ static int Func03a_static(int i) {
+ int res = i+100;
+ return res;
+ }
+ static int Func03b_static(int i) noexcept {
+ int res = i+1000;
+ return res;
+ }
+
+ void func12a_member(int& r, const int i) {
+ r = i+100;
+ }
+ void func12b_member(int& r, const int i) noexcept {
+ r = i+1000;
+ }
+ static void Func13a_static(int& r, const int i) {
+ r = i+100;
+ }
+ static void Func13b_static(int& r, const int i) noexcept {
+ r = i+1000;
+ }
+
+ void func20a_member() {
+ // nop
+ }
+ static void Func20a_static() {
+ // nop
+ }
+
+ static jau::function<int(int)> lambda_01() {
+ static int i = 100;
+ jau::function<int(int)> f = [&](int a) -> int {
+ return i + a;
+ };
+ return f;
+ }
+ static jau::function<int(int)> lambda_02() {
+ int i = 100;
+ jau::function<int(int)> f = [i](int a) -> int {
+ return i + a;
+ };
+ return f;
+ }
+
};
-METHOD_AS_TEST_CASE( TestFunction01::test00_perf, "00_perf");
+METHOD_AS_TEST_CASE( TestFunction01::test00_usage, "00_usage");
+METHOD_AS_TEST_CASE( TestFunction01::test10_perf, "10_perf");