Invocation: improve notation by using a wrapper

...so the solution is to build up the working data as `lib::SeveralBuilder`;
however, a more concise notation can be achieved with a suitably configured
wrapping subclass; together with the cross-builder trick, this allows
to write the allocation configuration in a clearly libelled way,
while the field definition and the builder constructor hides the
complexities of picking up the extension point and passing on the
wiring to the allocator instance.
This commit is contained in:
Fischlurch 2024-07-08 01:19:06 +02:00
parent d291853174
commit d3344e7dd3
2 changed files with 127 additions and 67 deletions

View file

@ -61,6 +61,21 @@
** build walk will traverse the connectivity graph depth-first, and then start invoking the
** Level-2 builder operations bottom-up to generate and wire up the corresponding Render Nodes.
**
** ## Using custom allocators
**
** Since the low-level-Model is a massive data structure comprising thousands of nodes, each with
** specialised parametrisation for some media handling library, and a lot of cross-linking pointers,
** it is important to care for efficient usage of memory with good locality. Furthermore, the higher
** levels of the build process will generate additional temporary data structures, which is gradually
** refined until the actual render node network can be emitted. Each builder level can thus be
** outfitted with a custom allocator typically an instance of lib::AllocationCluster. Notably
** the higher levels can be attached to a separate AllocationCluster instance, which will be
** discarded when the build process is complete, while Level-2 (and below) uses the allocator
** for the actual target data structure, which will be retained and until a complete segment
** of the timeline is superseded and has been re-built.
** @remark syntactically, the custom allocator specification is given after opening a top-level
** builder, by means of the builder function `.withAllocator<ALO> (args...)`
**
** @todo WIP-WIP-WIP 7/2024 Node-Invocation is reworked from ground up -- some parts can not be
** spelled out completely yet, since we have to build this tightly interlocked system of
** code moving bottom up, and then filling in further details later working top-down.
@ -90,8 +105,8 @@ namespace engine {
using std::move;
using std::forward;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Rebuild the Node Invocation
namespace { // policy configuration
namespace { // policy configuration for allocator
template<template<typename> class ALO =std::void_t, typename...INIT>
struct AlloPolicySelector
@ -120,13 +135,37 @@ namespace engine {
template<class I, class E=I>
using BuilderType = lib::SeveralBuilder<I,E>;
};
template<class POL, class I, class E=I>
using DataBuilder = typename POL::template BuilderType<I,E>;
//
}//(End) internal policy configuration
/**
* Convenience builder to collect working data.
* Implemented through a suitable configuration of lib::SeveralBuilder,
* such as to embed and connect to the configured custom allocator, which
* serves the goal to package all generated node configuration data together
* into a compact memory block, which can be discarded in bulk, once a given
* segment of the low-level-Model has been superseded.
* @tparam POL policy configuration pick the desired allocator
* @tparam I interface type for lib::Several<I>
* @remark in essence, this wrapper class creates the following setup
* \code
* makeSeveral<I>()
* .withAllocator<ALO> (args...);
* \endcode
*/
template<class POL, class I, class E=I>
class DataBuilder
: public POL::template BuilderType<I,E>
{
public:
template<typename...INIT>
DataBuilder (INIT&& ...alloInit)
: POL::template BuilderType<I,E>{forward<INIT> (alloInit)...}
{ }
};
template<class POL>
class PortBuilder;
@ -134,24 +173,20 @@ namespace engine {
class NodeBuilder
: util::MoveOnly
{
template<class I, class E=I, typename...INIT>
static auto
setupBuilder (INIT&& ...alloInit)
{
return POL::template setupBuilder<I,E> (forward<INIT> (alloInit)...);
}
using PortData = DataBuilder<POL, Port>;
using LeadRefs = DataBuilder<POL, ProcNodeRef>;
PortData ports_;
std::vector<ProcNodeRef> leads_{};
LeadRefs leads_;
public:
template<typename...INIT>
NodeBuilder (INIT&& ...alloInit)
: ports_{setupBuilder<Port> (forward<INIT> (alloInit)...)}
: ports_{forward<INIT> (alloInit)...}
, leads_{forward<INIT> (alloInit)...}
{ }
NodeBuilder
addLead (ProcNode const& lead)
{
@ -168,25 +203,39 @@ namespace engine {
}
/** cross-builder function to specify usage of a dedicated *node allocator* */
/**
* cross-builder function to specify usage of a dedicated *node allocator*
* @tparam ALO (optional) spec for the allocator to use
* @tparam INIT (optional) initialisation arguments for the allocator
* @remarks this is a front-end to the extension point for allocator specification
* exposed through lib::SeveralBuilder::withAllocator(). The actual meaning
* of the given parameters and the choice of the actual allocator happens
* through resolution of partial template specialisations of the extension
* point lib::allo::SetupSeveral. Some notable examples
* - withAllocator<ALO>() attaches to a _monostate_ allocator type.
* - `withAllocator<ALO> (ALO<X> allo)` uses a C++ standard allocator
* instance `allo`, dedicated to produce objects of type `X`
* - `withAllocator (AllocationCluster&)` attaches to a specific
* AllocationCluster; this is the most relevant usage pattern
*/
template<template<typename> class ALO =std::void_t, typename...INIT>
auto
withAllocator (INIT&& ...alloInit)
{
return NodeBuilder<AlloPolicySelector<ALO,INIT...>>{forward<INIT>(alloInit)...};
using AllocatorPolicy = AlloPolicySelector<ALO,INIT...>;
return NodeBuilder<AllocatorPolicy>{forward<INIT>(alloInit)...};
}
/****************************************************//**
* Terminal: complete the Connectivity defined thus far.
/************************************************************//**
* Terminal: complete the ProcNode Connectivity defined thus far.
*/
Connectivity
build()
{
/////////////////////////////////////////////////////////////////////OOO actually use the collected data to build
return Connectivity{ports_.build()
,lib::makeSeveral<ProcNodeRef>().build()
,NodeID{}};
,leads_.build()
,NodeID{}}; //////////////////////////////////////OOO what's the purpose of the NodeID??
}
};
@ -232,13 +281,19 @@ namespace engine {
/**
* Entrance point for building actual Render Node Connectivity (Level-2)
* @note when using a custom allocator, the first follow-up builder function
* to apply should be `withAllocator<ALO>(args...)`, prior to adding
* any further specifications and data elements.
*/
inline auto
prepareNode()
{
return NodeBuilder<UseHeapAlloc>{};
}
class ProcBuilder
: util::MoveOnly

View file

@ -290,9 +290,7 @@
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1493753178082" ID="ID_152757560" MODIFIED="1576282358163" TEXT="grunds&#xe4;tzliche Architektur gekl&#xe4;rt">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...h&#228;ngt am UI-Bus,
@ -322,9 +320,7 @@
<node CREATED="1501776305305" ID="ID_1193603370" MODIFIED="1557498707216" TEXT="Abstraktion des GUI"/>
<node CREATED="1501776319543" ID="ID_641656399" MODIFIED="1557498707216">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Sicht <i>&quot;von unten&quot;</i>
@ -359,9 +355,7 @@
<node CREATED="1533915480649" ID="ID_846895155" MODIFIED="1533915485628" TEXT="aber klingt nicht so sch&#xf6;n"/>
<node CREATED="1533915486336" ID="ID_627537189" MODIFIED="1576282358162" TEXT="und ist doppeldeutig">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...es k&#246;nnte auch den Feedback des Users meinen
@ -1422,9 +1416,7 @@
<node CREATED="1501850716049" ID="ID_104637334" MODIFIED="1538263469665" TEXT="emit() ist void(void)"/>
<node CREATED="1501850734414" ID="ID_994424125" MODIFIED="1538263469665">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
und arbeitet <i>asynchron</i>
@ -2644,9 +2636,7 @@
</node>
<node CREATED="1533768930822" ID="ID_1792377980" MODIFIED="1538263469670">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
besserer Name: <b>NotificationHub</b>
@ -3955,9 +3945,7 @@
</node>
<node COLOR="#338800" CREATED="1538836931857" ID="ID_438461567" MODIFIED="1538839523006" TEXT="#1174 kann auch geschlossen werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
#1174 UI self diagnostics window
@ -6322,9 +6310,7 @@
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
z.B. in den Block mit den &quot;default-Regeln&quot;
@ -87409,7 +87395,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#774459" DESTINATION="ID_611643324" ENDARROW="Default" ENDINCLINATION="-1147;68;" ID="Arrow_ID_1972337488" SOURCE="ID_1044694589" STARTARROW="None" STARTINCLINATION="804;73;"/>
<icon BUILTIN="yes"/>
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1720318492552" ID="ID_139926760" MODIFIED="1720318500106" TEXT="Probleme / Zweifel">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1720318492552" ID="ID_139926760" MODIFIED="1720408749240" TEXT="Probleme / Zweifel">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1720318501983" ID="ID_1668344828" MODIFIED="1720318529687" TEXT="zwei verschiedene Allocatoren in einem Builder sind verwirrend und gef&#xe4;hrlich"/>
<node CREATED="1720318530879" ID="ID_519349426" MODIFIED="1720318546580" TEXT="gut w&#xe4;re, wenn auf einem Level nur ein Allocator relevant ist"/>
@ -87468,15 +87454,15 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1720316245567" ID="ID_1819027234" MODIFIED="1720316332817" TEXT="cross-Builder-Trick f&#xfc;r Allokator einbauen">
<node COLOR="#338800" CREATED="1720316245567" ID="ID_1819027234" MODIFIED="1720408748235" TEXT="cross-Builder-Trick f&#xfc;r Allokator einbauen">
<linktarget COLOR="#721c55" DESTINATION="ID_1819027234" ENDARROW="Default" ENDINCLINATION="-426;-32;" ID="Arrow_ID_1938401610" SOURCE="ID_1147972165" STARTARROW="None" STARTINCLINATION="-70;384;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1720316338810" ID="ID_1548536358" MODIFIED="1720316355932" TEXT="hatte das erstmals f&#xfc;r den SeveralBuilder so gemacht"/>
<node CREATED="1720316421216" ID="ID_18485878" MODIFIED="1720316434730" TEXT="Vorteil: man bekommt einen dedizierten Scope f&#xfc;r das Type-Rebinding"/>
<node CREATED="1720316436796" ID="ID_554170067" MODIFIED="1720316451392" TEXT="Nachteil: geht nur per move und bei noch leerem Builder"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1720318733128" ID="ID_594929215" MODIFIED="1720366228647" TEXT="zus&#xe4;tzliche Schwierigkeit: Typ f&#xfc;r den Allocator">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#5e01a5" CREATED="1720318733128" ID="ID_594929215" MODIFIED="1720408741388" TEXT="zus&#xe4;tzliche Schwierigkeit: Typ f&#xfc;r den Allocator">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1720318754853" ID="ID_1165422564" MODIFIED="1720366097449" TEXT="geht jeweils auch in den Zieldatentyp mit ein"/>
<node CREATED="1720318787977" ID="ID_145712004" MODIFIED="1720366097449" TEXT="macht Klassendefinition kniffelig">
<node CREATED="1720318802329" ID="ID_430923777" MODIFIED="1720366097449" TEXT="mu&#xdf; per decltype() abgreifen"/>
@ -87501,9 +87487,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1720366289949" ID="ID_931662353" MODIFIED="1720366310582" TEXT="......und f&#xfc;r den Builder ist er in einer Policy-Selection eingepackt"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1720366069900" ID="ID_1936253657" MODIFIED="1720366213409" TEXT="mu&#xdf; SeveralBuilder-Typ konstruieren">
<node COLOR="#338800" CREATED="1720366069900" ID="ID_1936253657" MODIFIED="1720408719924" TEXT="mu&#xdf; SeveralBuilder-Typ konstruieren">
<linktarget COLOR="#fd4b66" DESTINATION="ID_1936253657" ENDARROW="Default" ENDINCLINATION="12;-46;" ID="Arrow_ID_520894148" SOURCE="ID_1206749989" STARTARROW="None" STARTINCLINATION="-71;4;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1720366322665" ID="ID_661828635" MODIFIED="1720366536903" TEXT="Wunsch">
<icon BUILTIN="yes"/>
<node CREATED="1720366327360" ID="ID_290275852" MODIFIED="1720366379365" TEXT="eigentlicher NodeBuilder tr&#xe4;gt nur noch einen POL-Template-Parameter"/>
@ -87546,9 +87532,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1720403044320" ID="ID_1061158702" MODIFIED="1720403070344" TEXT="die Policy im Builder selber als einfachen Typ-Parameter definieren"/>
<node CREATED="1720403071195" ID="ID_1277562489" MODIFIED="1720403164722">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>nicht</b>&#160;als template-template-Parameter...
@ -87557,9 +87541,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...denn sonst wird man die <font face="Monospaced" color="#872701">ALO, INIT...</font>&#160;- Parameter nicht los, sondern sie werden Teil des Builder-Typs (wir wollen aber, da&#223; sie nur implizit in den Builder-Typ eingehen)
@ -87572,9 +87554,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1720403252562" ID="ID_1281523727" MODIFIED="1720403262877" TEXT="die Policy definiert ein neues / eigenes Interface"/>
<node CREATED="1720403263561" ID="ID_675181635" MODIFIED="1720403289773">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<i>auf das</i>&#160;mu&#223; sich der Builder abst&#252;tzen, nicht auf den lib::SeveralBuilder oder dessen Policy
@ -87585,9 +87565,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1720403312751" ID="ID_1172888563" MODIFIED="1720403357154" TEXT="und: den default (&#x2259; Heap alloc) einfach als andere Policy daneben stellen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...nicht versuchen, die beiden zu verbinden oder irgendwie durch default-Parameter ausdr&#252;cken
@ -87598,9 +87576,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1720403358153" ID="ID_437340586" MODIFIED="1720403446512">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
tja... und jedes nested template braucht ein Pr&#228;fix &quot;<font face="Monospaced" color="#3607cb">template &lt;fun&gt;</font>&quot; in der Syntax
@ -87610,6 +87586,35 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#c8c0b6" CREATED="1720407274166" ID="ID_1545233818" MODIFIED="1720408757702">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
...und dann kann man es noch <i>rund machen...</i>
</p>
</body>
</html></richcontent>
<node CREATED="1720407992104" ID="ID_1821809277" MODIFIED="1720408006024" TEXT="die cross-Builder-Methode klar formulieren und kommentieren"/>
<node CREATED="1720408014534" ID="ID_556525925" MODIFIED="1720408031325" TEXT="eine Adapter-Subklasse &#xfc;ber den lib::SeveralBuilder setzen">
<node COLOR="#910209" CREATED="1720408104983" ID="ID_708933867" MODIFIED="1720408134237" TEXT="DataBuilder&lt;POL, I, E&gt;">
<font NAME="Monospaced" SIZE="12"/>
</node>
<node CREATED="1720408032960" ID="ID_1215104063" MODIFIED="1720408042582" TEXT="damit kann man die Felder direkt anschreiben"/>
<node CREATED="1720408043275" ID="ID_1038375286" MODIFIED="1720408148412" TEXT="und auch die Konstruktor-Notation auf das Minimum k&#xfc;rzen"/>
<node CREATED="1720408056019" ID="ID_99009807" MODIFIED="1720408083613" TEXT="und die grauenhafte template-Syntax dort wegpacken"/>
<node CREATED="1720408152536" ID="ID_42582244" MODIFIED="1720408211384" TEXT="Vorsicht: darf nicht im anonymen Namespace stehen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
weil dieser Typ in die tats&#228;chliche Linkage der Objektfelder eingeht
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
</node>
</node>