From 98078b9bb6b223b6b23ac842b6759e3d609d33ed Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 24 Nov 2023 04:15:15 +0100 Subject: [PATCH] Chain-Load: investigate std::function inline-storage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...which is crucial for the solution pursued at the moment; std::function is known to apply a small-object optimisation, yet unfortunately there are no guarantees by the C++ standard (it is only mandated that std::function handles a bare function pointer without overhead) Other people have investigated that behaviour already, indicating that at least one additional »slot« of data can be handled with embedded storage in all known implementations (while libstdc++ seemingly imposes the strongest limitations) https://stackoverflow.com/a/77202545/444796 This experiment in the unit-test shows that for my setup (libstdc++ and GCC-8) only a lambda capturing a single pointer is handled entirely embedded into the std::function; already a lambda capturing a shared-ptr leads to overflow into heap --- tests/library/lazy-init-test.cpp | 47 ++++++++++++++++++++++-- wiki/thinkPad.ichthyo.mm | 62 +++++++++++++++++++++++++++++--- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/tests/library/lazy-init-test.cpp b/tests/library/lazy-init-test.cpp index 638a290e1..34d63f261 100644 --- a/tests/library/lazy-init-test.cpp +++ b/tests/library/lazy-init-test.cpp @@ -30,7 +30,9 @@ #include "lib/lazy-init.hpp" //#include "lib/format-string.hpp" //#include "lib/test/test-helper.hpp" +#include "lib/test/testdummy.hpp" #include "lib/test/diagnostic-output.hpp" /////////////////////TODO TODOH +#include "lib/util.hpp" //#include @@ -40,6 +42,7 @@ namespace lib { namespace test{ // using util::_Fmt; + using util::isSameObject; using lib::meta::isFunMember; // using lib::meta::_FunRet; // using err::LUMIERA_ERROR_LIFECYCLE; @@ -73,7 +76,7 @@ namespace test{ simpleUse(); verify_trojanLambda(); - verify_inlineFunctorStorage(); + verify_inlineStorage(); // verify_numerics(); // verify_adaptMapping(); // verify_dynamicChange(); @@ -161,8 +164,48 @@ namespace test{ /** @test verify that std::function indeed stores a simple functor inline */ void - verify_inlineFunctorStorage() + verify_inlineStorage() { + Dummy::checksum() = 0; + using DummyManager = std::shared_ptr; + + DummyManager dummy{new Dummy}; + long currSum = Dummy::checksum(); + CHECK (currSum > 0); + CHECK (currSum == dummy->getVal()); + CHECK (1 == dummy.use_count()); + { + // --- nested Scope --- + auto lambda = [dummy]{ return &dummy; }; + CHECK (2 == dummy.use_count()); + CHECK (currSum == Dummy::checksum()); + + RawAddr location = lambda(); + CHECK (location == &lambda); + + std::function funWrap{lambda}; + CHECK (funWrap); + CHECK (not isSameObject (funWrap, lambda)); + CHECK (3 == dummy.use_count()); + CHECK (currSum == Dummy::checksum()); + +SHOW_EXPR(location) + location = funWrap(); +SHOW_EXPR(location) +SHOW_EXPR(RawAddr(&funWrap)) +SHOW_EXPR(RawAddr(dummy.get())) + + std::function fuckWrap{[location]{ return &location; }}; + CHECK (fuckWrap); +SHOW_EXPR(RawAddr(&location)) +SHOW_EXPR(RawAddr(fuckWrap())) +SHOW_EXPR(RawAddr(&fuckWrap)) + } + CHECK (1 == dummy.use_count()); + CHECK (currSum == Dummy::checksum()); + dummy.reset(); + CHECK (0 == dummy.use_count()); + CHECK (0 == Dummy::checksum()); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 6608614df..f212e3a5a 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -97285,8 +97285,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + @@ -97297,12 +97298,65 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + + + + + + + + + + + + + + + +

+ Ergebnis: funktioniert nur mit 1 »Slot« +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +