diff options
author | Sven Gothel <[email protected]> | 2022-10-07 04:23:47 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-10-07 04:23:47 +0200 |
commit | 247bf7968135fbd859ae6ac24d20ef7c221a4bbe (patch) | |
tree | fabe78200a3f3e29c0af06626765f0aebc5d730e /test/test_functional_perf.hpp | |
parent | 5299f1aecf3cc4462750f41ee4eee1d055cc956e (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.hpp | 265 |
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"); |