OutputSlot: forge a path towards a clean delegation structure
The solution adopted here is the result of extensive reflection. Taken literally, or naively, the reworked architecture would imply to route every call through a delegation-chain that is dispatched in the state-managing "PImpl" (`AllocState<CON>`). However, in keeping with the idea of an opaque functor embedded into `DataSink`, direct and explicitly typed calls can be bound in the associated closure. Doing so will strengthen the role of the interface `Connection` — which defines the boundary to the actual domain of output technology.
This commit is contained in:
parent
473299fb5a
commit
7bae52d1f8
6 changed files with 310 additions and 37 deletions
|
|
@ -75,7 +75,7 @@ namespace mem {
|
|||
mark_locked (ID typeKey, BuffAlloc alloc) override
|
||||
{
|
||||
auto& [storage,size,implMark] = alloc;
|
||||
return metadata_.markLocked (typeKey, storage, implMark);
|
||||
return metadata_.markLocked (typeKey, storage, size, implMark);
|
||||
}
|
||||
|
||||
ID
|
||||
|
|
|
|||
|
|
@ -147,6 +147,12 @@ namespace out {
|
|||
UNIMPLEMENTED ("a lot regarding the Timings is still not clear..."); //////////////////////////TICKET #831
|
||||
}
|
||||
|
||||
OpenedSinks
|
||||
connect (PAlloc& lifecycleManager) override
|
||||
{
|
||||
/////////////////OOO use an iterExplorer-Pipeline to create the functor closure here
|
||||
}
|
||||
|
||||
|
||||
/* == Callback API for BufferProxy == */
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace out {
|
|||
* type of the PImpl, i.e. the Allocation subclass passed in as argument. The OutputSlot,
|
||||
* together with the DataSink handles, will take shared ownership of the connection setup.
|
||||
*/
|
||||
shared_ptr<OutputSlot::Allocation>
|
||||
OutputSlot::PAlloc
|
||||
OutputSlot::connect (unique_ptr<Allocation> allocation)
|
||||
{
|
||||
REQUIRE (allocation);
|
||||
|
|
@ -74,14 +74,15 @@ namespace out {
|
|||
OutputSlot::OpenedSinks
|
||||
OutputSlot::getOpenedSinks()
|
||||
{
|
||||
|
||||
REQUIRE (alloc_);
|
||||
return alloc_->connect (alloc_);
|
||||
}
|
||||
|
||||
|
||||
Timings
|
||||
OutputSlot::timingConstraints()
|
||||
{
|
||||
REQUIRE(alloc_);
|
||||
REQUIRE (alloc_);
|
||||
return alloc_->getTimings();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ namespace out {
|
|||
|
||||
using vault::mem::BuffHandle;
|
||||
using lib::time::FrameCnt;
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
|
||||
|
|
@ -160,23 +159,31 @@ namespace out {
|
|||
|
||||
protected:
|
||||
/** @internal interface for the allocated state */
|
||||
class Allocation;
|
||||
using PAlloc = std::shared_ptr<Allocation>;
|
||||
|
||||
PAlloc alloc_;
|
||||
|
||||
class Allocation
|
||||
{
|
||||
public:
|
||||
virtual ~Allocation(); ///< this is an interface
|
||||
|
||||
virtual void release() =0;
|
||||
virtual Timings getTimings() =0;
|
||||
virtual void release() =0;
|
||||
virtual Timings getTimings() =0;
|
||||
virtual OpenedSinks connect (PAlloc&) =0;
|
||||
};
|
||||
|
||||
/** active connections through this OutputSlot */
|
||||
PAlloc
|
||||
connect (unique_ptr<Allocation>);
|
||||
|
||||
/**
|
||||
* @internal Implementation subclass:
|
||||
* manage active connections through this OutputSlot
|
||||
*/
|
||||
template<class CON>
|
||||
class AllocState;
|
||||
|
||||
shared_ptr<Allocation> alloc_;
|
||||
|
||||
shared_ptr<Allocation>
|
||||
connect (unique_ptr<Allocation>);
|
||||
|
||||
public:
|
||||
/** by default marked as inactive/defunct */
|
||||
|
|
@ -194,5 +201,5 @@ namespace out {
|
|||
};
|
||||
|
||||
|
||||
}} // namespace vault::out
|
||||
}}// namespace vault::out
|
||||
#endif /*VAULT_OUT_OUTPUT_SLOT_H*/
|
||||
|
|
|
|||
|
|
@ -5214,11 +5214,11 @@ Thus there are two serious problem situations
|
|||
&rarr; OutputSlotImpl
|
||||
</pre>
|
||||
</div>
|
||||
<div title="OutputSlotDesign" modifier="Ichthyostega" created="201112190322" modified="202603202151" tags="design decision" changecount="8">
|
||||
<div title="OutputSlotDesign" modifier="Ichthyostega" created="201112190322" modified="202603212136" tags="design decision" changecount="12">
|
||||
<pre>The OutputSlot interface describes a point where generated media data can actually be sent to the external world. It is expected to be implemented by adapters and bridges to existing drivers or external interface libraries, like a viewer widget in the GUI, ALSA or Jack sound output, rendering to file, using an external media format library. The design of this core facility was rather difficult and stretched out over quite some time span -- this page documents the considerations and the decisions taken.
|
||||
|
||||
!intention
|
||||
OutputSlot is a metaphor to unify the organisation of actual (system level) outputs; using this concept allows to separate and abstract the data calculation and the organisation of playback and rendering from the specifics of the actual output sink. Actual output possibilities (video in GUI window, video fullscreen, sound, Jack, rendering to file) can be added and removed dynamically from various components (Vault, Stage), all using the same resolution and mapping mechanisms (&rarr; OutputManagement)
|
||||
OutputSlot is a metaphor to unify the organisation of actual (system level) outputs; using this concept allows to separate and abstract the data calculation and the organisation of playback and rendering from the specifics of the actual output sink. Actual output possibilities (video in GUI window, video full screen, sound, Jack, rendering to file) can be added and removed dynamically from various components (Vault, Stage), all using the same resolution and mapping mechanisms (&rarr; OutputManagement)
|
||||
|
||||
!design possibilities
|
||||
!!properties as a starting point
|
||||
|
|
@ -5237,10 +5237,10 @@ Data is handed over by the client invoking an {{{emit(time,...)}}} function on t
|
|||
;buffer handover model
|
||||
:the client owns the data buffer and cares for allocation and de-allocation. The {{{emit()}}}-call just propagates a pointer to the buffer holding the data ready for output. The output slot implementation in turn has the liability to copy or otherwise use this data within a given time limit.
|
||||
;shared buffer model
|
||||
:here the output mechanism owns the buffer. Within a certain time window prior to the expected time of the {{{emit()}}}-call, the client may obtain this buffer (pointer) to fill in the data. The slot implementation won't touch this buffer until the {{{emit()}}} handover, which in this case just provides the time and signalles the client is done with that buffer. If the data emitting handshake doesn't happen at all, it counts as late and superseded by the next handshake.
|
||||
:here the output mechanism owns the buffer. Within a certain time window prior to the expected time of the {{{emit()}}}-call, the client may obtain this buffer (pointer) to fill in the data. The slot implementation won't touch this buffer until the {{{emit()}}} handover, which in this case just provides the time and signals the client is done with that buffer. If the data emitting handshake doesn't happen at all, it counts as late and superseded by the next handshake.
|
||||
|
||||
!!relation to timing
|
||||
Besides the sink handles, allocation of an output slot defines some timing constraints, to which the client must comply. These [[Timings]] are detailed and explicit, including a grid of deadlines for each frame to deliver, plus a fixed //latency.// Within this context, &raquo;latency&laquo; implies a requirement to be ahead of the nominal time by a certain amount, to compensate for the processing time that is necessary to propagate the media to the physical output pin. The output slot implementation itself is bound by external constraints to deliver data at a fixed framerate and aligned to an externally defined timing grid, and furthermore the data needs to be handed over ahead of these time points by an time amount given by the latency. Depending on the data exchange model, additional timing constraints may be imposed to further limit the time window when the buffer must be provided, transferred and released.
|
||||
Besides the sink handles, allocation of an output slot defines some timing constraints, to which the client must comply. These [[Timings]] are detailed and explicit, including a grid of deadlines for each frame to deliver, plus a fixed //latency.// Within this context, »latency« implies a requirement to be ahead of the nominal time by a certain amount, to compensate for the processing time that is necessary to propagate the media to the physical output pin. The output slot implementation itself is bound by external constraints to deliver data at a fixed frame rate and aligned to an externally defined timing grid, and furthermore the data needs to be handed over ahead of these time points by an time amount given by the latency. Depending on the data exchange model, additional timing constraints may be imposed to further limit the time window when the buffer must be provided, transferred and released.
|
||||
|
||||
!!relation to buffer management
|
||||
{{red{WIP 11/11}}} meanwhile I have worked out the BufferProvider interface in detail, including an explicit buffer handover protocol that is is backed by a tiny state engine to track the BufferMetadata. This mechanism provides an additional transition to {{{BLOCKED}}} state when order or timing constraints are being violated. Yet how to detect and resolve such a floundered state from the engine point of view still remains to be addressed.
|
||||
|
|
@ -5278,7 +5278,7 @@ The planned delivery time of a frame, or (equivalently) the frame-number on a we
|
|||
&rarr; OutputSlotImpl
|
||||
|
||||
-----
|
||||
!!! Delegation and state managment
|
||||
!!! Delegation and state management
|
||||
In 2026, the prototype implementation had to be reworked, due to [[#1395|https://issues.lumiera.org/ticket/1395]].
|
||||
However, the general structure of a BufferProvider was elaborated to quite some degree, and seems plausible and roughly final. Thus it becomes difficult to integrate the very specific requirements imposed by output handling into an implementation framework concerned primarily with memory management.
|
||||
* the output format dictates the buffer layout; whenever an OutputSlot was allocated, there is only a single //buffer type//
|
||||
|
|
@ -5286,17 +5286,23 @@ However, the general structure of a BufferProvider was elaborated to quite some
|
|||
* at that point, the actual connection implementation has to hand-out a buffer pointer
|
||||
* so we need to create metadata and track state transitions for a buffer that is managed elsewhere
|
||||
* furthermore, calls from the client through the BuffHandle, to signal {{{emit}}} and {{{release}}} must be routed to the proper connection.
|
||||
So the problem is that BufferProvider is conceived as a central service facility, while what we need here is a thin abstraction proxy. Fortunately, the {{{BufferProvider}}} implementation scheme offers some wiggle room, insofar a {{{LocalTag}}} can be stored with the metadata. So the task is to provide a suitable implememtation of {{{BufferProvider::BufferStore}}}, such that
|
||||
* the index number of the connection / data feed is embedded into a {{{LocalTag}}}
|
||||
So the problem is that BufferProvider is conceived as a central service facility, while what we need here is a thin abstraction proxy. Fortunately, the {{{BufferProvider}}} implementation scheme offers some wiggle room, insofar a {{{LocalTag}}} can be stored with the metadata. So the task is to provide a suitable implementation of {{{BufferProvider::BufferStore}}}, such that
|
||||
* a suitable access path to the given connection / data feed is embedded into a {{{LocalTag}}} in the metadata
|
||||
* an actual output buffer, provided by the {{{Connection}}} back-end, is registered with the metadata and represented as BuffHandle
|
||||
* calls on that BuffHandle will invoke the {{{BufferStore}}} API and must be delegated to the corresponding {{{Connection}}}.
|
||||
Taken together, this implies that the {{{OutputSlot::AllocState<CON>}}} turns into a delegation hub. It has to maintain the active connections and can thus be used to back a custom made {{{BufferStore}}} implementation, using the information embedded into the {{{LocalTag}}} to select the proper {{{Connection}}} for delegation -- which provides the actual implementation of all buffer management and state handling for the specific output mechanism.
|
||||
|
||||
-----
|
||||
!!! Establish a proper Lifecycle
|
||||
While the original design for OutputSlot seems //elegant, on a theoretical level,// the implementation was constantly plagued with complexities related to the lifecycle. Some relevant aspects could not be settled at all -- which was not noticed until the recent attempts to integrate the OutputSlot into the (likewise reworked) Render Engine implementation. A turning point in all this evolution of design is to remove the //state abstraction// -- in favour of representing the progression of state directly as a sequence of context data frames. The deeper change, which motivated this shift, was to abandon the idea of a single, global, overarching and final scheme of »Rendering«. It is acknowledged rather that the actual rendering for some unspecified »rendering« will be done by an external library -- and each such library establishes its own terminology, processing scheme and conventions, which finally are rooted in some specific ''Domain Onotology''. The Lumiera Render Engine is now understood as a connected graph of //adaptors//, organised around some minimal common denominator, like the fact that data frames are calculated, and that each such frame can be addressed by a media type and a point in time.
|
||||
While the original design for OutputSlot seems //elegant, on a theoretical level,// the implementation was constantly plagued with complexities related to the lifecycle. Some relevant aspects could not be settled at all -- which was not noticed until the recent attempts to integrate the OutputSlot into the (likewise reworked) Render Engine implementation. A turning point in all this evolution of design is to remove the //state abstraction// -- in favour of representing the progression of state directly as a sequence of context data frames. The deeper change, which motivated this shift, was to abandon the idea of a single, global, overarching and final scheme of »Rendering«. It is acknowledged rather that the actual rendering for some unspecified »rendering« will be done by an external library -- and each such library establishes its own terminology, processing scheme and conventions, which finally are rooted in some specific ''Domain Ontology''. The Lumiera Render Engine is now understood as a connected graph of //adaptors//, organised around some minimal common denominator, like the fact that data frames are calculated, and that each such frame can be addressed by a media type and a point in time.
|
||||
|
||||
In line with this shift in focus, the OutputSlot is seen as yet another element of representational state: it is a token to embody an allocated output connection. This implies to unify the notion of the {{{OutputSlot}}} with the {{{Allocation}}}, and turn both into a handle passed to the client process. All aspects of lifecycle can be managed automatically with such ref-counting handles. This has some cost in terms of performance (thread contention when accessing the atomic ref count), but that is deemed acceptable, since output is handled on a rather slow time scale, like producing a data frame every 10 milliseconds. The specific output mechanism remains »allocated« thus as long as some element of the client processing still holds onto any such handle, either the {{{OutputSlot}}} or some {{{DataSink}}}. The latter is reduced into a //named function//, which however also embeds a shared handle to the common allocation state. With this rearrangement in the design, there is now a cohesive domain of connection management, while the actual, technical connection is separated out and packaged behind the {{{Connection}}} interface.
|
||||
|
||||
!!! How actually to arrange the delegation
|
||||
Taken together, this implies that the {{{OutputSlot::AllocState<CON>}}} turns into a delegation hub. It has to maintain the active connections and can thus be used to back a custom made {{{BufferStore}}} implementation, using the information embedded into the {{{LocalTag}}} to select the proper {{{Connection}}} for delegation -- which provides the actual implementation of all buffer management and state handling for the specific output mechanism. Yet this does not imply to route every actual call through the {{{AllocState}}} -- while this is possible, and could be characterised as the naive solution, it would lead to several delegation chains, with a set of delegation methods at each intermediary step. Furthermore, it would require to wire a back-reference to this {{{AllocState}}} through the proxy-{{{BufferProvider}}}.
|
||||
|
||||
Since the entrance point to each buffer usage cycle is the functor in the {{{DataSink}}}, a direct call-path can be established. For one, the C++ standard library offers an [[aliasing-constructor|https://cppreference.com/w/cpp/memory/shared_ptr/shared_ptr.html]]; this is a rather obscure feature, yet allows to setup a subordinate shared-ptr, that participates in the lifecycle management (ref-count) of the main pointer, while pointing at some //alias object//, which typically is a subclass, sub-object or otherwise a part of the automatically managed compound. In the case at hand here, a shared-pointer //to the individual connection// can be established within the λ-capture. Furthermore, the {{{OutputBufferProxy}}} (the proxy-{{{BufferProvider}}}) can be constructed such as to delegate //directly to that {{{Connection}}}.//
|
||||
|
||||
And this raises another intricate question of design: //shall {{{Connection}}} be a ''concept''?//
|
||||
This would be a very elegant, and modern solution, offering much flexibility for the Implementer of said {{{Connection}}}. The {{{OutputBufferProxy}}} could be templated to that {{{Connection}}} type and thus allow the optimiser to inline and reduce the callback functionality. However -- C++ concepts are a rather new and arcane feature, as they rely on very special syntax and semantics that still requires some time in practical use to catch on and prove its viability. A further objection that can be raised is the fact that compliance to a concept leaves no traces within the implementation -- quite contrary to a classical ~OO-style interface, where the implementation is very obviously marked as such. These considerations bring me to the decision to //reject the use of a concept// here, and to rely on a conventional interface for {{{Connection}}}. Notably it can be expected that new kinds of connection will be added frequently, and so the task for a developer not familiar with all fine points of this design should be reasonably straight forward: „You have to implement the {{{Connection}}} interface“
|
||||
</pre>
|
||||
</div>
|
||||
<div title="OutputSlotImpl" modifier="Ichthyostega" created="201107102343" modified="201109232235" tags="spec operational">
|
||||
|
|
|
|||
|
|
@ -114711,7 +114711,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1771445380969" FOLDED="true" ID="ID_1703778866" MODIFIED="1771523204578" TEXT="Type-Refinement fehlt">
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1771445380969" FOLDED="true" ID="ID_1703778866" MODIFIED="1774125003754" TEXT="Type-Refinement fehlt">
|
||||
<linktarget COLOR="#b43f57" DESTINATION="ID_1703778866" ENDARROW="Default" ENDINCLINATION="-1037;-26;" ID="Arrow_ID_1563102453" SOURCE="ID_1813249595" STARTARROW="None" STARTINCLINATION="-107;797;"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#b10652" CREATED="1771465736392" ID="ID_983442728" MODIFIED="1771465865302" TEXT="Vorsicht: bekanntes Problem mit der TypeHandler-Identität">
|
||||
|
|
@ -114956,6 +114956,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1771512789583" ID="ID_1567622701" MODIFIED="1771522443460" TEXT="Ticket machen und auf später vertagen">
|
||||
<arrowlink COLOR="#6e0e30" DESTINATION="ID_916357319" ENDARROW="Default" ENDINCLINATION="3;-26;" ID="Arrow_ID_339622533" STARTARROW="None" STARTINCLINATION="-201;-14;"/>
|
||||
<linktarget COLOR="#b4715d" DESTINATION="ID_1567622701" ENDARROW="Default" ENDINCLINATION="-57;1294;" ID="Arrow_ID_646507974" SOURCE="ID_497118718" STARTARROW="None" STARTINCLINATION="910;51;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#db0728" CREATED="1771513582347" ID="ID_94121635" MODIFIED="1771513715826" TEXT="(ausschlaggebend)">
|
||||
|
|
@ -118997,8 +118998,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f9f3e3" COLOR="#a50125" CREATED="1773959558830" ID="ID_1973724646" MODIFIED="1773963271195" TEXT="Achtung: ursprüngliches Konzept »Job« löst sich auf">
|
||||
<linktarget COLOR="#fd2e1b" DESTINATION="ID_1973724646" ENDARROW="Default" ENDINCLINATION="-1379;72;" ID="Arrow_ID_862194975" SOURCE="ID_1593586171" STARTARROW="None" STARTINCLINATION="1316;57;"/>
|
||||
<linktarget COLOR="#fe6c6c" DESTINATION="ID_1973724646" ENDARROW="Default" ENDINCLINATION="-1379;72;" ID="Arrow_ID_663742943" SOURCE="ID_589497720" STARTARROW="None" STARTINCLINATION="-974;63;"/>
|
||||
<linktarget COLOR="#fd2e1b" DESTINATION="ID_1973724646" ENDARROW="Default" ENDINCLINATION="-1379;72;" ID="Arrow_ID_862194975" SOURCE="ID_1593586171" STARTARROW="None" STARTINCLINATION="1316;57;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1773959604840" ID="ID_1430634387" MODIFIED="1773959706305" TEXT="notiere diese Beobachtung im Rückblick 2026 (nach einiger Verwirrung)">
|
||||
|
|
@ -138294,7 +138295,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node COLOR="#435e98" CREATED="1773888286270" ID="ID_1279395018" MODIFIED="1773888766729" TEXT="Fazit">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1773888290871" ID="ID_1640123820" MODIFIED="1773888299240" TEXT="DataSink wird unique"/>
|
||||
<node COLOR="#5b280f" CREATED="1773888290871" ID="ID_1640123820" MODIFIED="1774117142876" TEXT="DataSink wird unique">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node BACKGROUND_COLOR="#e5daab" COLOR="#470f69" CREATED="1774117157026" ID="ID_1466239" MODIFIED="1774117235993" TEXT="anders: DataSink wird ein Funktor">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1773888299988" ID="ID_1909698021" MODIFIED="1773888311487" TEXT="DataSink verweist auf den PImpl (AllocState)">
|
||||
<node CREATED="1773888330075" ID="ID_1924701415" MODIFIED="1773888346410" TEXT="hier wird ein neues Interface benötigt"/>
|
||||
<node CREATED="1773888364124" ID="ID_1625145338" MODIFIED="1773888376862" TEXT="oder eine vergleichbare implementation-level-Indirektion"/>
|
||||
|
|
@ -138363,9 +138369,47 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1773935626212" ID="ID_638151363" MODIFIED="1773935640598" TEXT="also neue Lösung für den Lebenszyklus finden"/>
|
||||
<node CREATED="1773935626212" ID="ID_638151363" MODIFIED="1774117448707" TEXT="also neue Lösung für den Lebenszyklus finden">
|
||||
<arrowlink COLOR="#e2ecc3" DESTINATION="ID_36151402" ENDARROW="Default" ENDINCLINATION="-14;-78;" ID="Arrow_ID_496758201" STARTARROW="None" STARTINCLINATION="-142;9;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774120269051" ID="ID_1414284795" MODIFIED="1774120274196" TEXT="Einwände / Abwägung">
|
||||
<node CREATED="1774058024248" ID="ID_82008745" LINK="#ID_1047888380" MODIFIED="1774120647806" TEXT="muß daran denken daß die DataSink auch sowas wie eine Stream-ID bieten sollte">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das ist eine absehbare, zukünftige Anforderung — für den Frame-Cache; letztlich geht es darum, sparsam mit der Storage für Job-Parameter umzugehen, da wir sehr viele Jobs unter hohem Druck durch das System schicken. Das bedeutet, alle Paramter, die <i>nicht beweglich sind (sich pro Frame ändern),</i> müssen möglichst zusammengefaßt repräsentiert werden. Die DataSink muß dem entsprechend auch alles weitere repräsentieren, was sich hinter eine bestehende Output-Connection an Metadaten hängen läßt, und was für den Cache-Key relevant wird
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774120256991" ID="ID_1157546506" MODIFIED="1774120265316" TEXT="Performance-Überlegungen">
|
||||
<node CREATED="1774119984274" ID="ID_581830154" LINK="#ID_871196012" MODIFIED="1774120034249" TEXT="Achtung: shared-ptr im λ-capture ⟹ stets Heap"/>
|
||||
<node BACKGROUND_COLOR="#eab2d0" COLOR="#d10120" CREATED="1774121031654" ID="ID_600545894" MODIFIED="1774121434219" TEXT="das ärgert mich — aber es WIRD KEINE ROLLE SPIELEN">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Diese Funktionalität hier, die Ausgabe von Frames, liegt zweifellost bereits weit in der Zone, in der <b>Premature Optimisation</b> ein echtes Problem ist: Selbst wenn etwas alle 5 Millisekunden einmal passiert, sind +100µs <i>praktisch nicht feststellbar</i>; die absolute Schmerzgrenze für Optimierungen in einer solchen Lage wäre, wenn man dadurch eine ganze Millisekunde herausholen könnte, und <i>zudem die Operation unter Druck und permanent abläuft! </i>
|
||||
</p>
|
||||
<p>
|
||||
<br/>Schon erstaunlich, daß es so schwer ist, dieser Einsicht gemäß zu handeln...
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#302180" CREATED="1774121556663" HGAP="30" ID="ID_1178991105" MODIFIED="1774121595961" TEXT="(und wenn doch ⟹ durch Invoker-Technik ersetzen, analog zu std::function)" VSHIFT="8">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774121472020" ID="ID_922156630" MODIFIED="1774121875612" TEXT="ja dann ... kann man da gleich noch mehr oben drauf packen">
|
||||
<arrowlink COLOR="#d2fd54" DESTINATION="ID_602198707" ENDARROW="Default" ENDINCLINATION="555;-30;" ID="Arrow_ID_1933104143" STARTARROW="None" STARTINCLINATION="546;25;"/>
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774058024248" ID="ID_82008745" MODIFIED="1774058054776" TEXT="aber: daran denken daß die DataSink auch sowas wie eine Stream-ID bieten sollte"/>
|
||||
</node>
|
||||
<node CREATED="1774041166497" ID="ID_1405169811" MODIFIED="1774041789004" TEXT="Design nochmal überdenken">
|
||||
<linktarget COLOR="#96171e" DESTINATION="ID_1405169811" ENDARROW="Default" ENDINCLINATION="32;82;" ID="Arrow_ID_1850815871" SOURCE="ID_1695581190" STARTARROW="None" STARTINCLINATION="-700;32;"/>
|
||||
|
|
@ -138412,11 +138456,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1774041702802" ID="ID_1059075539" MODIFIED="1774041716165" TEXT="sogar die Allocation ist nur transient"/>
|
||||
<node CREATED="1774041720512" ID="ID_699098233" MODIFIED="1774041746264" TEXT="und mit dem shared-ptr kommt noch ein weiteres front-end-Handle ins Spiel"/>
|
||||
</node>
|
||||
<node CREATED="1774041802165" ID="ID_400821992" MODIFIED="1774041817127" TEXT="OutputSlot und Allocation zu einem neuen front-end-Handle verschmelzen">
|
||||
<node COLOR="#338800" CREATED="1774041802165" ID="ID_400821992" MODIFIED="1774116667493" TEXT="OutputSlot und Allocation zu einem neuen front-end-Handle verschmelzen">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1774041822205" ID="ID_527875329" MODIFIED="1774041843283" TEXT="künftig bekommt man also den OutputSlot sofort im »allozierten« Zustand"/>
|
||||
<node CREATED="1774041847407" ID="ID_883089965" MODIFIED="1774041871047" TEXT="was ich mal (theoretisch) für den OutputSlot vorgesehen hatte ⟶ in den OutputManager"/>
|
||||
<node CREATED="1774041924787" ID="ID_1979509297" MODIFIED="1774041966755" TEXT="OutputSlot wird damit kopierbar und verliert die VTable"/>
|
||||
<node CREATED="1774041982834" ID="ID_1851190390" MODIFIED="1774042051311" TEXT="der Konstruktor nimmt nun direkt einen unique_ptr<Allocation>"/>
|
||||
<node CREATED="1774041982834" ID="ID_1851190390" MODIFIED="1774116941295" TEXT="der Konstruktor nimmt nun direkt einen unique_ptr<Allocation>">
|
||||
<arrowlink COLOR="#939dbe" DESTINATION="ID_209194829" ENDARROW="Default" ENDINCLINATION="327;14;" ID="Arrow_ID_1829394358" STARTARROW="None" STARTINCLINATION="263;0;"/>
|
||||
</node>
|
||||
<node CREATED="1774042055979" ID="ID_1678190677" MODIFIED="1774042077220" TEXT="...und pflanzt den in einen shared-ptr als pImpl"/>
|
||||
<node CREATED="1774042095382" ID="ID_409572046" MODIFIED="1774042116105" TEXT="getOpenedSinks() hat darauf nun direkt Zugriff"/>
|
||||
<node CREATED="1774042144135" ID="ID_398645730" MODIFIED="1774042163080" TEXT="und delegiert an eine builder/verdrahtungs-Funktion auf dem PImpl"/>
|
||||
|
|
@ -138425,10 +138472,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1773954149241" ID="ID_203883845" MODIFIED="1773954234498" TEXT="Allocation / Lebenszyklus in den Griff bekommen">
|
||||
<arrowlink COLOR="#d0020f" DESTINATION="ID_671153651" ENDARROW="Default" ENDINCLINATION="-3;-427;" ID="Arrow_ID_1331623727" STARTARROW="Default" STARTINCLINATION="-756;0;"/>
|
||||
<node CREATED="1773971803964" ID="ID_987627732" MODIFIED="1773971813190" TEXT="gemeinamen shared-ptr einführen">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773973038119" ID="ID_322920487" MODIFIED="1773973052086" TEXT="Problem: diesen erzeugen und verdrahten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773973038119" ID="ID_322920487" MODIFIED="1774116830612" TEXT="Problem: diesen erzeugen und verdrahten">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1773973059692" ID="ID_1788170271" MODIFIED="1773973087364" TEXT="muß eine Deleter-Funktion einbinden"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1773973088177" ID="ID_534312365" MODIFIED="1773973144984" TEXT="muß aber diesen Pointer auch im AllocState selber zugänglich machen">
|
||||
<node BACKGROUND_COLOR="#e5cca9" COLOR="#a50167" CREATED="1773973088177" ID="ID_534312365" MODIFIED="1774116812214" TEXT="muß aber diesen Pointer auch im AllocState selber zugänglich machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -138439,18 +138486,210 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1773973156752" ID="ID_1805849643" MODIFIED="1773973178296" TEXT="und zudem muß die OutputSlot-Impl den tatsächlichen AllocState konstruieren können"/>
|
||||
<node CREATED="1774041751196" ID="ID_1946395022" MODIFIED="1774041772893" TEXT="nun könnte man eine Factory bauen, und ein leere Handle überall hin durchschieben"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#27013a" CREATED="1773973156752" ID="ID_1805849643" MODIFIED="1774116754813" TEXT="und zudem muß die OutputSlot-Impl den tatsächlichen AllocState konstruieren können">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1774041751196" ID="ID_1946395022" MODIFIED="1774116705999" TEXT="nun könnte man eine Factory bauen, und ein leere Handle überall hin durchschieben">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node CREATED="1774041103709" ID="ID_1695581190" MODIFIED="1774041789004" TEXT="das ist alles so kompliziert ⟹ etwas mit dem Design stimmt nicht">
|
||||
<arrowlink COLOR="#96171e" DESTINATION="ID_1405169811" ENDARROW="Default" ENDINCLINATION="32;82;" ID="Arrow_ID_1850815871" STARTARROW="None" STARTINCLINATION="-700;32;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774116838284" ID="ID_878332497" MODIFIED="1774116859054" TEXT="mit veränderter Architektur wird das einfach....">
|
||||
<node CREATED="1774116894254" ID="ID_209194829" MODIFIED="1774116928285" TEXT="Basis-Verdrahtung kann jetzt im OutputSlot-Konstruktor passieren">
|
||||
<linktarget COLOR="#939dbe" DESTINATION="ID_209194829" ENDARROW="Default" ENDINCLINATION="327;14;" ID="Arrow_ID_1829394358" SOURCE="ID_1851190390" STARTARROW="None" STARTINCLINATION="263;0;"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1773971813999" ID="ID_36151402" MODIFIED="1774117434690" TEXT="dieser wird per λ-closure im DataSink-Funktor verborgen">
|
||||
<linktarget COLOR="#e2ecc3" DESTINATION="ID_36151402" ENDARROW="Default" ENDINCLINATION="-14;-78;" ID="Arrow_ID_496758201" SOURCE="ID_638151363" STARTARROW="None" STARTINCLINATION="-142;9;"/>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1773971849966" ID="ID_1738000581" MODIFIED="1774117476736" TEXT="der »pImpl« in OutputSlot wird ein daran angekoppelter weak-ptr">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node COLOR="#435e98" CREATED="1774117484906" HGAP="40" ID="ID_1135177401" MODIFIED="1774117513992" TEXT="besser durch verändertes Design gelöst" VSHIFT="5">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1773971813999" ID="ID_36151402" MODIFIED="1773971845114" TEXT="dieser wird per λ-closure im DataSink-Funktor verborgen"/>
|
||||
<node CREATED="1773971849966" ID="ID_1738000581" MODIFIED="1773971868607" TEXT="der »pImpl« in OutputSlot wird ein daran angekoppelter weak-ptr"/>
|
||||
<node CREATED="1773971873811" ID="ID_264465688" MODIFIED="1773971898075" TEXT="auf das vorzeitige Schließen einzelner Connections wird verzichtet"/>
|
||||
<node CREATED="1773971902700" ID="ID_967293485" MODIFIED="1773971931718" TEXT="aber es muß einen globalen (virtuellen) release-Hook im OutputSlot geben"/>
|
||||
</node>
|
||||
<node CREATED="1774117870539" ID="ID_160673186" MODIFIED="1774117879102" TEXT="Callbacks für das Buffer-Handling einfädeln">
|
||||
<node CREATED="1774117886873" ID="ID_1363452049" MODIFIED="1774117892476" TEXT="der Funktor in DataSink">
|
||||
<node CREATED="1774117905798" ID="ID_3491981" MODIFIED="1774119797698" TEXT="verwendet einen Slave-shared-ptr">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das ist ein wenig bekanntes (aber bisweilen nützliches) Feature der Standardlib: man kann einen Alias-Pointer an den gleichen shared-State ankoppeln; wohin dieser Alias zeigt, ist komplett beliebig (muß aber während der ganzen Lebensdauer existieren, denn dieser Zielort wird nicht eigens gemanaged).
|
||||
</p>
|
||||
<p>
|
||||
Hier könnten wir dieses Feature nutzen, um direkt auf die jeweilige Connection zu zeigen, oder (alternativ) auf den OutputBufferProxy den konkret getypten AllocState (Subklasse)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774121832836" ID="ID_602198707" MODIFIED="1774122336107" TEXT="bekommt außerdem softort auch einen Buffer Descriptor mit">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
in dem stecken zwei Informationen:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
ein Pointer auf den OutputBufferProxy (Buffer-Provider)
|
||||
</li>
|
||||
<li>
|
||||
eine vorbereitete Typ-Info, die die Buffer-Size, aber auch das LocalTag enthält, über das die jeweils zuständige Connection angesteuert wird
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#d2fd54" DESTINATION="ID_602198707" ENDARROW="Default" ENDINCLINATION="555;-30;" ID="Arrow_ID_1933104143" SOURCE="ID_922156630" STARTARROW="None" STARTINCLINATION="546;25;"/>
|
||||
<node CREATED="1774121902242" HGAP="28" ID="ID_643404701" MODIFIED="1774122005097" TEXT="in dem ist per »LocalTag« die Connection-Impl codiert" VSHIFT="5"/>
|
||||
</node>
|
||||
<node CREATED="1774122219137" ID="ID_656953886" MODIFIED="1774122240553" TEXT="⟹ alle weiteren Protokollschritte erfolgen direkt von dort"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1774122365597" ID="ID_292817548" MODIFIED="1774122379717" TEXT="Abwägung: wohin delegieren die Proxy-Callbacks?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1774122388349" ID="ID_1459974960" MODIFIED="1774122391728" TEXT="möglich wäre...">
|
||||
<node CREATED="1774122410671" ID="ID_1178347692" MODIFIED="1774124507440" TEXT="an eine Connection (Interface)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das wäre dann auch der tatsächliche Empfänger, der letztlich die Entscheidungen trifft — <b>das wäre sauberes Design</b>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="full-1"/>
|
||||
</node>
|
||||
<node CREATED="1774122425805" ID="ID_1560232882" MODIFIED="1774124510817" TEXT="an einen konkreten Connection-Subtyp">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das wäre <i>kohäsives Design</i> — würde aber eine zusätzliche Indirektion durch die Connection-VTable einsparen ⟹ damit wird das Connection-Interface praktisch wertlos; sinnvollerweise müßte man es durch ein <b>Concept</b> ersetzen
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="full-2"/>
|
||||
</node>
|
||||
<node CREATED="1774122436380" ID="ID_1025931134" MODIFIED="1774124514258" TEXT="an den AlocState + Connection-Index">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das wäre die naheliegende (und dämliche) Lösung — insofern spricht <i>für eine solche Lösung</i> daß sie nicht viel »Grips« verlangt; man stiefelt sich von Delegation zu Delegation. Das ist leicht zu schreiben, und einigermaßen gut lesbar, wenn die Delegationen gut benannt sind. Insofern <b>setzt diese Lösung den Baseline-Standard</b> 
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="full-3"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774123575010" ID="ID_824191013" MODIFIED="1774123578213" TEXT="Abwägung">
|
||||
<node CREATED="1774123579183" ID="ID_1737320485" MODIFIED="1774123596424" TEXT="och schon wieder so eine schwere Abwägung">
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
</node>
|
||||
<node CREATED="1774123608295" ID="ID_1563409432" MODIFIED="1774123673981" TEXT="Lesbarkeit und Verstänglichkeit gewichte ich hier sehr hoch">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
weil es sich um eine sehr zentrale Struktur handelt, welche erwartungsgemäß auch viel in Zukunft erweitert und angepaßt werden muß
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774123676575" ID="ID_280613834" MODIFIED="1774123762058" TEXT="direkte Delegation an Connection (oder Subtyp) vereinfacht die OutputBufferProxy">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Es fällt dadurch nämlich eine weitere, generische Indirektion weg, die dann auch nicht mehr trickreich durch drei Konstruktoren durchgefädelt werden muß
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774123768156" ID="ID_1416841395" MODIFIED="1774123808063">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Konkrete Connection + Concept wäre <i><font color="#b93ca1">saugeil</font></i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<node CREATED="1774123818580" ID="ID_1494790648" MODIFIED="1774123821927" TEXT="modern"/>
|
||||
<node CREATED="1774123823192" ID="ID_1829897869" MODIFIED="1774124113447" TEXT="Code wird komplett geinlined">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
zumindest in der BufferStore-Implementierung; ein cleverer Optimiser kann u.U. sogar die <i>monomorphic optimisation</i> machen? (fraglich, denn der Aufrufer hat ja nur ein BuffHandler. Wenngleich auch <i>kontextuelll klar ist,</i> daß dieses BuffHandle von einer ganz bestimmten Implementierung stammen muß; fragt sich, wie lange es noch dauert, bis Optimiser sowas auch „sehen“ order gar beweisen können, und ob sich dafür der Aufwand lohnt)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774124115813" ID="ID_83197251" MODIFIED="1774124123303" TEXT="maximale Freiheit für den Implementator"/>
|
||||
</node>
|
||||
<node CREATED="1774124125679" ID="ID_1280679186" MODIFIED="1774124476752">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ich bin skeptisch: <i>für wen</i> ist das »lesbar«?
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Concepts sind ein relativ komplexes Gebilde, und sie haben eine spezielle Notierung, die in der Form nur in C++ gegeben ist. Nur ein Bruchteil der C++ - Entwickler wir mit Konzepten vertraut werden (auf lange Zeit). Zudem hinterläßt ein Konzept <i>in der Implementierung keine Spuren. </i>Man könnte sich da zwar etwas einfallen lassen, aber das wäre dann noch mehr ein Spezial-Konstrukt. Das ist etwas, was sich erst noch herausbilden muß (auch die Tool-Unterstützung ist ein Aspekt).
|
||||
</p>
|
||||
<p>
|
||||
Demgegenüber ist ein klassisches OO-Interface ein seit 30 Jahren universell bekanntes und weithin unterstütztes Schema, das in den allermeisten Sprachen in irgend einer Form eingesetzt wird (selbst wenn die Sprachen sonst nicht OO sind). Wenn ich einem durchschnittlichen Entwickler heute sage: „Du mußt das Interface Connection implementieren“, dann setzt der sich einfach hin und klopft das runter.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774124482636" ID="ID_99417390" MODIFIED="1774124502539" TEXT="Beschluß: Direk-Aufruf auf das Connection-Interface">
|
||||
<icon BUILTIN="forward"/>
|
||||
<icon BUILTIN="full-1"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774124656373" ID="ID_1252354115" MODIFIED="1774127022008" TEXT="also binden in die Funktor-Closure">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1774124694439" ID="ID_775305943" MODIFIED="1774124714000" TEXT="ein shared-ptr mit Alias auf die jeweilige Connection"/>
|
||||
<node CREATED="1774124730203" ID="ID_257841074" MODIFIED="1774124780343" TEXT="ein vertig verdrahteter Buffer-Descriptor (⟶ Connection)">
|
||||
<node COLOR="#5b280f" CREATED="1774126323430" ID="ID_497118718" MODIFIED="1774126743220" TEXT="doch wieder Buffer-Descriptor-Refinement?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ja ich weiß, irgenwie <i>will ich diese Idee</i> — und kann dann immer kein gutes Argument dafür herbeizaubern. So auch in dem Fall; es ist nämlich hier trotzdem so, daß wir ein ganzes Tupel von Argumenten für jede einzelne Connection aufsammeln müssen. Ein Type-Refinement würde beduten, zwei dieser Argumente zusammen in einem generischen Buffer-Descriptor „zu verstecken“ (nämlich den Link auf den OutputBufferProxy, sowie die Buffer-Size). Deshalb bleiben trotzdem weitere Argumente übrig, und auch für die Verständlichkeit ist es abträglich, wenn die Abhängigkeit auf den Proxy-BufferProvider verborgen wird
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#b4715d" DESTINATION="ID_1567622701" ENDARROW="Default" ENDINCLINATION="-57;1294;" ID="Arrow_ID_646507974" STARTARROW="None" STARTINCLINATION="910;51;"/>
|
||||
<icon BUILTIN="help"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node COLOR="#b40945" CREATED="1774126746364" HGAP="38" ID="ID_1849597195" MODIFIED="1774126761166" TEXT="NJET" VSHIFT="11">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774126316622" ID="ID_1460072236" MODIFIED="1774126322206" TEXT="Argumente">
|
||||
<node CREATED="1774126777267" ID="ID_1310012432" MODIFIED="1774126788414" TEXT="den shared-ptr als »lifecycle-manager«"/>
|
||||
<node CREATED="1774126796040" ID="ID_1259439489" MODIFIED="1774126831327" TEXT="die jeweils relevante Connection (⟶ als Pointer/Referenz)"/>
|
||||
<node CREATED="1774126856640" ID="ID_1792742469" MODIFIED="1774126864387" TEXT="von dieser Connection die Buffer-Size"/>
|
||||
<node CREATED="1774126881885" ID="ID_899991315" MODIFIED="1774126887766" TEXT="der Proxy-BufferProvider"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -166204,6 +166443,20 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
<font NAME="Monospaced" SIZE="12"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1774119984274" ID="ID_710870030" LINK="#ID_871196012" MODIFIED="1774120713133" TEXT="λ-capture Heap-overflow">
|
||||
<node CREATED="1774120723265" ID="ID_300417056" MODIFIED="1774120732777" TEXT="passiert automatisch und ist »implementation-defined«"/>
|
||||
<node CREATED="1774120733654" ID="ID_794869813" MODIFIED="1774120983814" TEXT="der Schwellwert liegt bei der LibStdC++ relativ niedrig">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Im Zusammenhang mit der »Test-Chain-Load« (wo ich mich wieder einmal wunderbar im Design verlaufen hatte) habe ich ein »trojanisches Lambda« bauen müssen wollen. Dieser Programmiertrick funktioniert nur, wenn die Storage für das Capture noch »inline« liegt. Empirisch habe ich gefunden, daß ein char[16] oder ein unique-ptr noch inline liegt, aber ein shared-ptr einen Heap-Overflow bewirkt.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1774120823962" ID="ID_762343468" MODIFIED="1774120842355" TEXT="wenn man darüber liegt ⟹ schleppt ein Heap-Delegate mit"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1482365430484" ID="ID_1414724077" MODIFIED="1557498707240" TEXT="chrono">
|
||||
|
|
|
|||
Loading…
Reference in a new issue