Chain-Load: invent the heart of the trap-mechanism
...the intention is to plant a »trojan lambda« into the target functor, to set off initialisation (and possibly relocation) on demand.
This commit is contained in:
parent
1892d1beb5
commit
3c713a4739
3 changed files with 159 additions and 9 deletions
|
|
@ -81,16 +81,76 @@
|
|||
//#include "lib/util.hpp"
|
||||
|
||||
//#include <functional>
|
||||
//#include <utility>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace lib {
|
||||
// namespace err = lumiera::error;
|
||||
|
||||
// using lib::meta::_Fun;
|
||||
using lib::meta::_Fun;
|
||||
using lib::meta::has_Sig;
|
||||
// using std::function;
|
||||
// using std::forward;
|
||||
// using std::move;
|
||||
using std::forward;
|
||||
using std::move;
|
||||
|
||||
using RawAddr = void const*;
|
||||
|
||||
|
||||
/**
|
||||
* »Trojan Function« builder.
|
||||
* Generates a Lambda to invoke a delegate for the actual computation.
|
||||
* On invocation, the current storage location of the λ is determined.
|
||||
*/
|
||||
template<class SIG>
|
||||
class TrojanFun
|
||||
{
|
||||
template<class DEL>
|
||||
using Manager = std::shared_ptr<DEL>;
|
||||
|
||||
template<class DEL, typename RET, typename... ARGS>
|
||||
static auto
|
||||
buildTrapActivator (Manager<DEL>&& managedDelegate, _Fun<RET(ARGS...)>)
|
||||
{
|
||||
return [chain = move(managedDelegate)]
|
||||
(ARGS ...args) -> RET
|
||||
{
|
||||
auto currLocation = &chain;
|
||||
auto& functor = (*chain) (currLocation);
|
||||
//
|
||||
return functor (forward<ARGS> (args)...);
|
||||
};
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* Invocation: build a Lambda to activate the »Trap«
|
||||
* and then to forward the invocation to the actual
|
||||
* function, which should have been initialised
|
||||
* by the delegate invoked.
|
||||
* @param delegate a functor object pass invocation;
|
||||
* the delegate must return a reference to the
|
||||
* actual function implementation to invoke.
|
||||
* Must be heap-allocated.
|
||||
* @return a lightweight lambda usable as trigger.
|
||||
* @note takes ownership of the delegate
|
||||
*/
|
||||
template<class DEL>
|
||||
static auto
|
||||
generateTrap (DEL* delegate)
|
||||
{
|
||||
static_assert (_Fun<DEL>(), "Delegate must be function-like");
|
||||
using Ret = typename _Fun<DEL>::Ret;
|
||||
static_assert (_Fun<Ret>(), "Result from invoking delegate must also be function-like");
|
||||
static_assert (has_Sig<Ret, SIG>(), "Result from delegate must expose target signature");
|
||||
|
||||
REQUIRE (delegate);
|
||||
|
||||
return buildTrapActivator (Manager<DEL>{delegate}, _Fun<SIG>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ namespace lib {
|
|||
namespace test{
|
||||
|
||||
// using util::_Fmt;
|
||||
using lib::meta::isFunMember;
|
||||
// using lib::meta::_FunRet;
|
||||
// using err::LUMIERA_ERROR_LIFECYCLE;
|
||||
|
||||
|
|
@ -71,6 +72,7 @@ namespace test{
|
|||
{
|
||||
simpleUse();
|
||||
|
||||
verify_trojanLambda();
|
||||
verify_inlineFunctorStorage();
|
||||
// verify_numerics();
|
||||
// verify_adaptMapping();
|
||||
|
|
@ -88,6 +90,74 @@ namespace test{
|
|||
|
||||
|
||||
|
||||
/** @test verify construction of the »trap« front-end eventually to trigger initialisation
|
||||
* - this test does not involve any std::function, rather a heap-allocated copy of a λ
|
||||
* # the _target function_ finally to be invoked performs a verifiable computation
|
||||
* # the _delegate_ receives an memory location and returns a reference to the target
|
||||
* # the generated _»trojan λ«_ captures its own address, invokes the delegate,
|
||||
* retrieves a reference to a target functor, and invokes these with actual arguments.
|
||||
* @remark the purpose of this convoluted scheme is for the _delegate to perform initialisation,_
|
||||
* taking into account the current memory location „sniffed“ by the trojan.
|
||||
*/
|
||||
void
|
||||
verify_trojanLambda()
|
||||
{
|
||||
size_t beacon;
|
||||
auto fun = [&](uint challenge){ return beacon+challenge; };
|
||||
|
||||
using Sig = size_t(uint);
|
||||
CHECK (isFunMember<Sig> (&fun));
|
||||
|
||||
beacon = rand();
|
||||
uint c = beacon % 42;
|
||||
// verify we can invoke the target function
|
||||
CHECK (beacon+c == fun(c));
|
||||
|
||||
// verify we can also invoke the target function through a reference
|
||||
using FunType = decltype(fun);
|
||||
FunType& funRef = fun;
|
||||
CHECK (beacon+c == funRef(c));
|
||||
|
||||
// construct delegate function exposing the expected behaviour;
|
||||
// additionally this function captures the passed-in address.
|
||||
RawAddr location{nullptr};
|
||||
auto delegate = [&](RawAddr adr) -> FunType&
|
||||
{
|
||||
location = adr;
|
||||
return fun;
|
||||
};
|
||||
using Delegate = decltype(delegate);
|
||||
Delegate *delP = new Delegate(delegate);
|
||||
|
||||
// verify the heap-allocated copy of the delegate behaves as expected
|
||||
location = nullptr;
|
||||
CHECK (beacon+c == (*delP)(this)(c));
|
||||
CHECK (location == this);
|
||||
|
||||
// now (finally) build the »trap function«,
|
||||
// taking ownership of the heap-allocated delegate copy
|
||||
auto trojanLambda = TrojanFun<Sig>::generateTrap (delP);
|
||||
CHECK (sizeof(trojanLambda) == 2*sizeof(size_t));
|
||||
|
||||
// on invocation...
|
||||
// - it captures its current location
|
||||
// - passes this to the delegate
|
||||
// - invokes the target function returned from the delegate
|
||||
CHECK (beacon+c == trojanLambda(c));
|
||||
CHECK (location == &trojanLambda);
|
||||
|
||||
// repeat that with a copy, and changed beacon value
|
||||
auto trojanClone = trojanLambda;
|
||||
beacon = rand();
|
||||
c = beacon % 55;
|
||||
CHECK (beacon+c == trojanClone(c));
|
||||
CHECK (location == &trojanClone);
|
||||
CHECK (beacon+c == trojanLambda(c));
|
||||
CHECK (location == &trojanLambda);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test verify that std::function indeed stores a simple functor inline
|
||||
*/
|
||||
void
|
||||
|
|
|
|||
|
|
@ -97265,8 +97265,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
die Trap-Door muß irgendwo auf den Initialiser zugreifen, und dieser muß wiederum die vorläufige Funktion speichern. Alle diese Allokationen müssen direkt am Trap selber »aufgehängt« werden; wenn wir also den Trap verwerfen (durch Neuzuweisung), sägen wir den Ast ab, auf dem wir sitzen. Kann man machen, wenn man Flügel hat, oder sowieso schon auf dem Sprung ist
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1700778952199" ID="ID_1113376718" MODIFIED="1700778979121" TEXT="sollte aber grade noch gehen, wenn nur noch der Tail-Call der Funktion folgt"/>
|
||||
</node>
|
||||
|
|
@ -97277,11 +97276,32 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779211570" ID="ID_181212829" MODIFIED="1700779288743" TEXT="sauber als Hilfskomponente aufsetzen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1700779233186" ID="ID_155856101" MODIFIED="1700779259708" TEXT="Begründung: wird schon wieder Komplex und hat ein paar vergrabene Hunde..."/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779263072" ID="ID_1457586572" MODIFIED="1700779291901" TEXT="lib/lazy-init.hpp">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700779263072" ID="ID_1457586572" MODIFIED="1700792011790" TEXT="lib/lazy-init.hpp">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700779275391" ID="ID_1990626821" MODIFIED="1700779291901" TEXT="LazyInit_test.cpp">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700779275391" ID="ID_1990626821" MODIFIED="1700792011791" TEXT="LazyInit_test.cpp">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700786308827" ID="ID_627670298" MODIFIED="1700792001666" TEXT="der Trojanische-Funktor">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1700786329960" ID="ID_579721558" MODIFIED="1700786340287" TEXT="bettet einen shared_ptr ein">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1700786341382" ID="ID_1622424867" MODIFIED="1700792030724" TEXT="delegiert über diesen um Funktor(Referenz) zu bekommen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1700786363539" ID="ID_1467357967" MODIFIED="1700792032414" TEXT="ruft über diese Referenz den tatsächlichen Funktor">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700786402490" ID="ID_846455233" MODIFIED="1700786418812" TEXT="Trick-Mechanismus zur this-Ermittlung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1700786427859" ID="ID_569731992" MODIFIED="1700786445020" TEXT="muß zu Beginn »proben«"/>
|
||||
<node CREATED="1700786446976" ID="ID_646471757" MODIFIED="1700786472569" TEXT="Zusatz-Problem: das λ sieht nur seine capture">
|
||||
<node CREATED="1700786476589" ID="ID_1376774629" MODIFIED="1700786490117" TEXT="⟶ also mehrstufig vorgehen"/>
|
||||
<node CREATED="1700786494226" ID="ID_990128277" MODIFIED="1700786508492" TEXT="generisch das Verhältnis zur std::function ermitteln"/>
|
||||
<node CREATED="1700786514967" ID="ID_1504854205" MODIFIED="1700786531452" TEXT="ebenso das Verhältnis von der std::function zu *this"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue