BufferProvider: simplify OutputSlot implementation structure

The old implementation relied on two layered APIs:
one for the client and one for the implementer of
the Allocation state. This is logically sound, yet
clumsy in terms of design, since the internal API
turns out to be void of actual meaning.

It seems possible to eliminate this confusing structure
by a clear separation of ''implementation realms''
 * the ''mechanics'' of connection state management
 * the actual implementation of the connection

The first can be provided as generic template subclass,
while the latter should be confined entirely into the
implementation of the `Connection` interface.

Doing so requires to keep each part of the implementation
strictly focused onto its purpose — something I obviously
was not able to see at the time when writing this old
implementation, notably because I was completely guided
and driven by the test/dummy implementation without
considering how an actual implementation of
low-level data output would work.
This commit is contained in:
Fischlurch 2026-03-13 22:35:46 +01:00
parent d91ca67a27
commit 0178e11e65
7 changed files with 242 additions and 144 deletions

View file

@ -12,44 +12,46 @@
*/ */
/** @file scoped-collection.hpp /** @file scoped-collection.hpp
** Managing a collection of non-copyable polymorphic objects in compact storage. ** Manage a collection of non-copyable polymorphic objects in compact storage.
** This helper supports the frequently encountered situation where a service ** This helper supports common situation where a service implementation has to
** implementation internally manages a collection of implementation related ** manages a fixed collection of implementation related sub-components, treated
** sub-components with reference semantics. Typically, those objects are ** with reference semantics. Typically, those objects are used polymorphically,
** being used polymorphically, and often they are also added step by step. ** and often even with _type erasure_ and added step by step through a builder.
** The storage holding all those child objects is allocated in one chunk ** The storage to hold all those child objects is allocated in one chunk
** and never adjusted. ** and never adjusted. Individual children are never re-ordered or removed,
** only the collection as a whole is discarded eventually.
** **
** # usage patterns ** # usage patterns
** **
** The common ground for all usage of this container is to hold some elements ** The common ground for all usage of this container is to hold some elements
** with exclusive ownership; when the enclosing container goes out of scope, ** with exclusive ownership; when the enclosing container goes out of scope,
** all the dtors of the embedded objects will be invoked. Frequently this ** all the dtors of the embedded objects will be invoked. Frequently this
** side effect is the reason for using the container: we want to own some ** side effect is one of the reasons for using the container: we want to own
** resource handles to be available exactly as long as the managing object ** some resource handles and be sure they are available exactly as long as
** needs and accesses them. ** the managing scope is alive and able to access them.
** **
** There are two different usage patterns for populating a ScopedCollection ** There are two different usage patterns for populating a ScopedCollection
** - the "stack style" usage creates an empty container (using the one arg ** - the "stack style" usage creates an empty container (using the one arg
** ctor just to specify the maximum size). The storage to hold up to this ** ctor to specify the maximum size only). The storage capacity to hold
** number of objects is (heap) allocated right away, but no objects are ** a number of objects, up to the predefined maximum, is (heap) allocated
** immediately at construction of the container, yet no child objects are
** created. Later on, individual objects are "pushed" into the collection ** created. Later on, individual objects are "pushed" into the collection
** by invoking #emplaceElement() to create a new element of the default ** by invoking #emplaceElement() to create a new element of the default
** type `I`) or #emplace<Type>(args) to create some subtype. This way, ** type `I`) or #emplace<Type>(args) to create some subtype. This way,
** the container is being filled successively. ** the container is gradually filled up.
** - the "RAII style" usage strives to create all of the content objects ** - the "RAII style" usage strives to create all of the content objects
** right away, immediately after the memory allocation. This usage pattern ** right away, immediately after the memory allocation. This usage pattern
** avoids any kind of "lifecycle state". Either the container comes up sane ** avoids any kind of "lifecycle state". Either the container comes up sane
** and fully populated, or the ctor call fails and any already created ** and fully populated, or the ctor call fails and any already created
** objects are discarded. ** objects are discarded.
** @note intentionally there is no operation to discard individual objects, ** @note intentionally there is no operation to discard individual objects,
** all you can do is to #clear() the whole container. ** the only option is to #clear() the whole container.
** @note the container can hold instances of a subclass of the type defined ** @note the container can hold instances of a subclass of the type defined
** by the template parameter `I`. But you need to ensure in this case ** by the template parameter `I`. But you need to ensure in this case
** that the defined buffer size for each element (2nt template parameter) ** that the defined buffer size for each element (2nt template parameter)
** is sufficient to hold any of these subclass instances. This condition ** is sufficient to hold any of these subclass instances. This condition
** is protected by a static assertion (compilation failure). ** is protected by a static assertion (compilation failure).
** @warning when using subclasses, a virtual dtor is mandatory ** @warning when using subclasses, defining a virtual dtor is mandatory!
** @warning deliberately **not threadsafe** ** @warning deliberately **not threadsafe**
** **
** @see ScopedCollection_test ** @see ScopedCollection_test
@ -160,7 +162,7 @@ namespace lib {
* Ctor fails in case of any error during element creation. * Ctor fails in case of any error during element creation.
* @param builder functor to be invoked for each "slot". * @param builder functor to be invoked for each "slot".
* It gets an ElementHolder& as parameter, and should * It gets an ElementHolder& as parameter, and should
* use this to create an object of some I-subclass * use this to create an object of suitable I-subclass
*/ */
template<class CTOR> template<class CTOR>
ScopedCollection (size_t maxElements, CTOR builder) ScopedCollection (size_t maxElements, CTOR builder)

View file

@ -342,7 +342,7 @@ namespace out {
* remains in memory until shutdown of the current executable * remains in memory until shutdown of the current executable
*/ */
class DiagnosticOutputSlot class DiagnosticOutputSlot
: public OutputSlotImplBase : public OutputSlot
{ {
static const uint MAX_CHANNELS = 5; ///////////////////////////////OOO Build heap-based implementation with arbitrary number of feeds!! static const uint MAX_CHANNELS = 5; ///////////////////////////////OOO Build heap-based implementation with arbitrary number of feeds!!
@ -363,30 +363,27 @@ namespace out {
* thus allowing to verify the handling of individual buffers * thus allowing to verify the handling of individual buffers
*/ */
class SimulatedOutputSequences class SimulatedOutputSequences
: public AllocStateHub<TrackingInMemoryBlockSequence> : public AllocState<TrackingInMemoryBlockSequence>
{ {
typedef AllocStateHub<TrackingInMemoryBlockSequence> _Base; using _Base = AllocState<TrackingInMemoryBlockSequence>;
void
buildConnection(ConnectionStorage storage)
{
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
storage.create<TrackingInMemoryBlockSequence>();
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
public: public:
SimulatedOutputSequences (uint numChannels) SimulatedOutputSequences (uint numChannels)
: _Base(numChannels) : _Base{ numChannels
{ ,[](ConnectionStorage& storage)
init(); {
} UNIMPLEMENTED ("new Tracking implementation for DiagnosticOutputSlot");
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
storage.create<TrackingInMemoryBlockSequence>();
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}}
{ }
}; };
/** hook into the OutputSlot frontend */ /** hook into the OutputSlot frontend */
unique_ptr<AllocState> unique_ptr<Allocation>
buildState() buildState()
{ {
return make_unique<SimulatedOutputSequences> ( return make_unique<SimulatedOutputSequences> (
@ -402,7 +399,8 @@ namespace out {
{ {
REQUIRE (!isFree(), "diagnostic OutputSlot not (yet) connected"); REQUIRE (!isFree(), "diagnostic OutputSlot not (yet) connected");
REQUIRE (channel <= getOutputChannelCount()); REQUIRE (channel <= getOutputChannelCount());
return static_cast<TrackingInMemoryBlockSequence&> (state_->access (channel)); // return static_cast<TrackingInMemoryBlockSequence&> (state_->access (channel));
UNIMPLEMENTED ("the old tracking API is abandoned, the new one not yet implemented");
} }

View file

@ -33,19 +33,20 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/nocopy.hpp" #include "lib/nocopy.hpp"
#include "vault/out/output-slot.hpp" #include "vault/out/output-slot.hpp"
#include "vault/mem/buffhandle.hpp"
#include "lib/scoped-collection.hpp" #include "lib/scoped-collection.hpp"
#include "lib/iter-adapter-stl.hpp" #include "lib/iter-adapter-stl.hpp"
#include "lib/iter-source.hpp" #include "lib/iter-source.hpp"
#include "lib/handle.hpp" #include "lib/handle.hpp"
//#include "lib/time/timevalue.hpp" #include "lib/time/timevalue.hpp"
//#include "steam/engine/buffer-provider.hpp" //#include "steam/engine/buffer-provider.hpp"
//#include "steam/play/timings.hpp" //#include "steam/play/timings.hpp"
//#include "lib/sync.hpp" //#include "lib/sync.hpp"
#include "vault/mem/buffer-provider.hpp"
//#include <string> //#include <string>
#include <functional> #include <functional>
#include <vector> #include <utility>
//#include <vector>
//#include <memory> //#include <memory>
@ -53,8 +54,8 @@ namespace vault {
namespace out { namespace out {
using vault::mem::BuffHandle; using vault::mem::BuffHandle;
//using vault::mem::BufferProvider; using vault::mem::BufferProvider;
//using lib::time::Time; using lib::time::TimeValue; /////////////////OOO Rly?
//using std::string; //using std::string;
using lib::iter_stl::eachElm; using lib::iter_stl::eachElm;
@ -102,61 +103,29 @@ namespace out {
/**
* Extension point for Implementation.
* The AllocState is where the concrete output
* handling implementation is expected to reside.
* OutputSlot is a frontend and accesses
* AllocState in the way of a PImpl.
*/
class OutputSlot::AllocState
: public OutputSlot::Allocation
, util::NonCopyable
{
public:
virtual ~AllocState() { }
virtual Connection& access (uint) const =0;
};
/* ===== Building blocks for OutputSlot implementation ===== */ /* ===== Building blocks for OutputSlot implementation ===== */
/** Base for OutputSlot standard implementation */
class OutputSlotImplBase
: public OutputSlot
{
protected:
template<class CON>
class AllocStateHub;
};
/** /**
* Maintaining a list of active connections. * Implementation of active Allocation state: maintaining
* Base class for the typical implementation approach. * a list of active connections. An instance is created whenever
* Using this class is \em not mandatory. But obviously, * a client _locks_ (and thereby »allocates«) the OutputSlot. The
* we'd get to manage a selection of Connection objects * actual implementation of OutputSlot::buildState() will employ a
* representing the "active points" in several media channels * custom Connection, where all the actual state handling and data
* connected through this OutputSlot. These Connection subclasses * transport is implemented. Such a Connection subclass is also what
* are what is referenced by the DataSink smart-ptrs handed out * is referenced by the DataSink smart-hendle, that is handed out
* to the client code. As AllocState implements the Allocation * to the client code and allows to mark the state transitions.
* API, it has the liability to create these DataSink smart-ptrs, * Theses smart-handles are ref counting and thus the individual
* which means to wire them appropriately and also provide an * Connection object is kept alive as long as at least one DataSink
* deleter function (here #shutdownConnection) to be invoked * handle is retained. The deleter function #shutdownConnection is
* when the last copy of the smart-handle goes out of scope. * is invoked for each abandoned connection; once all connections
* * are defunct, the AllocState itself can be deconfigured.
* The typical standard/base implementation provided here
* manages a collection of active Connection subclass objects.
*/ */
template<class CON> template<class CON>
class OutputSlotImplBase::AllocStateHub class OutputSlot::AllocState
: public OutputSlot::AllocState : public OutputSlot::Allocation
{ {
typedef lib::ScopedCollection<CON> Connections; using Connections = lib::ScopedCollection<CON>;
typedef OutputSlot::OpenedSinks OpenedSinks; using OpenedSinks = OutputSlot::OpenedSinks;
Connections connections_; Connections connections_;
@ -191,32 +160,22 @@ namespace out {
protected: /* == API for OutputSlot-Impl == */ protected: /* == API for OutputSlot-Impl == */
void
init() ///< derived classes need to invoke this to build the actual connections
{
//////////////////////////TICKET #878 really build all at once? or on demand?
connections_.populate_by (&AllocStateHub::buildConnection, this);
}
using ConnectionStorage = Connections::ElementHolder&; using ConnectionStorage = Connections::ElementHolder;
/** factory function to build the actual /**
* connection handling objects per channel */ * The actual implementation of OutputSlot::buildState() needs to build
virtual void buildConnection(ConnectionStorage) =0; * an AllocState<CON> instance, and has to provide a _population functor_
* to setup the actual \a CON (Connection implementation) instances.
* @see ScopedCollection_test::building_RAII_Style()
AllocStateHub(uint numChannels) */
: connections_(numChannels) template<class CTOR>
{ } AllocState(uint numChannels, CTOR&& populator)
: connections_(numChannels, std::forward<CTOR>(populator))
public:
virtual
~AllocStateHub()
{ } { }
private: /* === Implementation details === */
private: // Implementation details
static DataSink static DataSink
connectOutputSink (CON& connection) connectOutputSink (CON& connection)

View file

@ -59,11 +59,11 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/handle.hpp" #include "lib/handle.hpp"
#include "lib/time/timevalue.hpp" #include "vault/mem/buffhandle.hpp"
#include "vault/mem/buffer-provider.hpp"
#include "vault/out/timings.hpp" #include "vault/out/timings.hpp"
#include "lib/iter-source.hpp" #include "lib/iter-source.hpp"
#include "lib/nocopy.hpp" #include "lib/nocopy.hpp"
#include "lib/util.hpp"
#include <memory> #include <memory>
@ -72,11 +72,7 @@ namespace vault {
namespace out { namespace out {
using vault::mem::BuffHandle; using vault::mem::BuffHandle;
using vault::mem::BufferProvider;
using lib::time::FrameCnt; using lib::time::FrameCnt;
using lib::time::TimeValue;
using lib::time::Time;
using std::unique_ptr; using std::unique_ptr;
@ -93,28 +89,15 @@ namespace out {
* channels to some kind of external sink (video in GUI window, video full screen, * channels to some kind of external sink (video in GUI window, video full screen,
* sound, Jack, rendering to file). Clients are expected to retrieve a suitably * sound, Jack, rendering to file). Clients are expected to retrieve a suitably
* preconfigured implementation from some OutputManager instance. An OutputSlot * preconfigured implementation from some OutputManager instance. An OutputSlot
* needs to be \em claimed for output by invoking #allocate, which returns a * needs to be _claimed_ for output by invoking #allocate, which returns a
* representation of the connection state. This operation is exclusive. * representation of the connection state. This operation is exclusive.
* The actual \link DataSink output sinks \endlink can be retrieved * The actual [output sinks](\ref DataSink) can be retrieved
* through the Allocation object returned from there. * through the Allocation object returned from there.
*/ */
class OutputSlot class OutputSlot
: util::NonCopyable : util::NonCopyable
{ {
protected:
/** active connections through this OutputSlot */
class AllocState;
unique_ptr<AllocState> state_;
/** build the \em connected state,
* based on the existing configuration
* within this concrete OutputSlot */
virtual unique_ptr<AllocState> buildState() =0;
public: public:
virtual ~OutputSlot(); virtual ~OutputSlot();
@ -128,13 +111,9 @@ namespace out {
virtual Timings getTimingConstraints() =0; virtual Timings getTimingConstraints() =0;
protected: ~Allocation(); ///< this is an interface
~Allocation(); ///< never to be managed by clients directly
}; };
/** established output channel */
class Connection;
/** can this OutputSlot be allocated? */ /** can this OutputSlot be allocated? */
bool isFree() const; bool isFree() const;
@ -145,6 +124,22 @@ namespace out {
/** disconnect from this OutputSlot /** disconnect from this OutputSlot
* @warning may block until DataSinks are gone */ * @warning may block until DataSinks are gone */
void disconnect(); void disconnect();
/** established output feed */
class Connection;
protected:
/** active connections through this OutputSlot */
template<class CON>
class AllocState;
unique_ptr<Allocation> state_;
/** build the _connected state,_
* based on the existing configuration
* within this concrete OutputSlot */
virtual unique_ptr<Allocation> buildState() =0;
}; };
@ -168,16 +163,11 @@ namespace out {
{ {
return not (sink1 and sink2) return not (sink1 and sink2)
or (sink1 and sink2 or (sink1 and sink2
and & sink1.impl() == & sink2.impl()); and util::isSameObject (sink1.impl(), sink2.impl()));
}
friend bool operator!= (DataSink const& sink1, DataSink const& sink2)
{
return not (sink1 == sink2);
} }
}; };
}} // namespace vault::out }} // namespace vault::out
#endif /*VAULT_OUT_OUTPUT_SLOT_H*/ #endif /*VAULT_OUT_OUTPUT_SLOT_H*/

View file

@ -188,7 +188,7 @@ namespace test{
// Verify correct behaviour of iteration end // Verify correct behaviour of iteration end
CHECK (! (coll.end())); CHECK (not bool(coll.end()));
CHECK (isnil (coll.end())); CHECK (isnil (coll.end()));
VERIFY_ERROR (ITER_EXHAUST, *coll.end() ); VERIFY_ERROR (ITER_EXHAUST, *coll.end() );
@ -303,7 +303,7 @@ namespace test{
CollD coll (6, Populator(rr, trigger)); CollD coll (6, Populator(rr, trigger));
CHECK (!isnil (coll)); CHECK (not isnil (coll));
CHECK (6 == coll.size()); CHECK (6 == coll.size());
CHECK (0 != Dummy::checksum()); CHECK (0 != Dummy::checksum());
@ -314,7 +314,7 @@ namespace test{
CHECK (coll[4].calc(0) == 4 + rr); CHECK (coll[4].calc(0) == 4 + rr);
CHECK (coll[5].calc(0) == 5 + rr + trigger); CHECK (coll[5].calc(0) == 5 + rr + trigger);
// what does this check prove? // what does this check prove?
// - the container was indeed populated with DubDummy objects // - the container was indeed populated with SubDummy objects
// since the overridden version of Dummy::acc() did run and // since the overridden version of Dummy::acc() did run and
// reveal the trigger value // reveal the trigger value
// - the population was indeed done with the anonymous Populator // - the population was indeed done with the anonymous Populator

View file

@ -38,6 +38,7 @@
#include "lib/error.hpp" #include "lib/error.hpp"
#include "lib/nocopy.hpp" #include "lib/nocopy.hpp"
#include "lib/symbol.hpp"
#include "stage/ctrl/bus-term.hpp" #include "stage/ctrl/bus-term.hpp"
#include "stage/model/tangible.hpp" #include "stage/model/tangible.hpp"
#include "stage/ctrl/state-manager.hpp" #include "stage/ctrl/state-manager.hpp"
@ -49,6 +50,8 @@
#include <string> #include <string>
using lib::Symbol;
namespace stage { namespace stage {
namespace test{ namespace test{

View file

@ -137463,6 +137463,131 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node> </node>
</node> </node>
</node> </node>
<node CREATED="1773354410472" ID="ID_1743624174" MODIFIED="1773354422590" TEXT="bestehende Implementierung &#xfc;berpr&#xfc;fen">
<node CREATED="1773366196992" ID="ID_1171528228" MODIFIED="1773366221964" TEXT="die dreistufige Vererbung ist zweifelhaft">
<node CREATED="1773366223189" ID="ID_1366861589" MODIFIED="1773366246027" TEXT="Kennzeichen: mir fallen keine drei schl&#xfc;ssigen Klassennamen ein">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#491552" CREATED="1773366247597" ID="ID_475172789" MODIFIED="1773366269948" TEXT="wie kam dieses Konstrukt zustande?">
<icon BUILTIN="info"/>
<node CREATED="1773366279150" ID="ID_735259479" MODIFIED="1773366302144" TEXT="der PImpl ist bereits auf dem Interface OutputSlot vorhanden"/>
<node CREATED="1773366338424" ID="ID_1596448185" MODIFIED="1773366367494" TEXT="damit mu&#xdf; auch die Impl-Base f&#xfc;r den PImpl dort zumindest deklariert sein"/>
<node CREATED="1773366368466" ID="ID_352563837" MODIFIED="1773366385108" TEXT="der Client sieht aber eine Referenz auf diesen PImpl (class Allocation)"/>
<node CREATED="1773366388230" ID="ID_988189170" MODIFIED="1773366406189" TEXT="damit sind zwei abgestufte Interfaces schon mal zwingend"/>
<node CREATED="1773366407398" ID="ID_441511007" MODIFIED="1773366422499" TEXT="hinzu kommt: der konkrete PImpl soll auf den Connection-Typ getemplated sein"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1773367153256" ID="ID_632963645" MODIFIED="1773367160887" TEXT="Kritik">
<icon BUILTIN="yes"/>
<node CREATED="1773367162551" ID="ID_1839486394" MODIFIED="1773367536301" TEXT="keine Trennung der Zonen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Interessant ist daran, da&#223; ich das damals &#252;berahupt nicht gesehen habe; mein Level war also, da&#223; ich zwar ziemlich direkt ein solches Protokoll in OO-Interfaces &#252;bersetzen konnte, aber das Denken in Zonen / Dom&#228;nen und Perspektiven der Implementierung war mir noch fremd, ich konnte dies grade so ansatzweise erahnen, aber hab mich in der konkreten Implementierung nur von Haken zu &#214;se durchgehangelt...
</p>
</body>
</html></richcontent>
<node CREATED="1773367173125" ID="ID_1353951708" MODIFIED="1773367178714" TEXT="Implementierung des Protokolls"/>
<node CREATED="1773367179429" ID="ID_1923303384" MODIFIED="1773367191679" TEXT="Implementierung der konkreten Connection"/>
<node CREATED="1773367220239" ID="ID_185299510" MODIFIED="1773367232602" TEXT="Implementierung des Buffer-Managements">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1773367257106" ID="ID_998290443" MODIFIED="1773367263978" TEXT="man kann sich hier nicht festlegen">
<icon BUILTIN="messagebox_warning"/>
</node>
<node COLOR="#524398" CREATED="1773367275715" ID="ID_1202996101" MODIFIED="1773367399070" TEXT="kann zentral oder dezentral sein">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...damit meine ich
</p>
<ul>
<li>
entweder die ganze Allokation (und damit die Verwendung des OutputSlot) ist praktisch einheitlich; es werden zwar N Buffer zugewiesen, aber der Transfer-Mechanismus l&#228;uft f&#252;r alle gemeinsam
</li>
<li>
oder die Allokation ist lediglich eine logische Klammer, und die eigentliche Implementierung ist N-fach aufgedoppelt, f&#252;r jeden einzelnen Feed
</li>
</ul>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node CREATED="1773367564585" ID="ID_200538523" MODIFIED="1773367577454" TEXT="die Implementierungs-Interfaces sind &#xbb;d&#xfc;nn&#xab;">
<node CREATED="1773367579127" ID="ID_87042655" MODIFIED="1773367935032" TEXT="das PImpl-Interface selber hat nur eine (nicht verwendete) Methode">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
<font color="#4a1a65" face="Bitstream Vera Sans Mono" size="9pt"><b>virtual</b></font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt">&#160;</font><font color="#635e96" face="Bitstream Vera Sans Mono" size="9pt"><b>Connection</b></font><font color="#65533c" face="Bitstream Vera Sans Mono" size="9pt">&amp;</font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt">&#160;</font><font color="#632d2d" face="Bitstream Vera Sans Mono" size="9pt"><b>access</b></font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt">&#160; </font><font color="#11123a" face="Bitstream Vera Sans Mono" size="9pt">(</font><font color="#8c505c" face="Bitstream Vera Sans Mono" size="9pt"><b>uint</b></font><font color="#11123a" face="Bitstream Vera Sans Mono" size="9pt">)</font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt">&#160;</font><font color="#4a1a65" face="Bitstream Vera Sans Mono" size="9pt"><b>const</b></font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt">&#160;</font>
</p>
<p>
</p>
<p>
...nat&#252;rlich wird die verwendet, aber irgendwo aus der konkreten Implementierung (DiagnosticOutputSlot) heraus. Das ist ein <i>telltale sign</i>&#160;&#8212; nat&#252;rlich sollte eine solche Interface-Methode verwendet werden, aber die Verwendung einer Methode sollte direkt vom Interface aus offensichtlich sein, ohne in die Implementierung schauen zu m&#252;ssen. Das ist hier nicht der Fall; warum sollte ein konkreter OutputSlot von oben herab auf einzelnen Connections zugreifen m&#252;ssen? Konkret habe ich das verwendet, um das ganze Diagnose-API darauf aufzubauen. Jaja, sowas nennt man &#187;hexagonales Design&#171; &#8212; Diagnose-State und Verifikationen sollte man niemals verwenden, um daran die Architektur auszurichten.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773367958645" ID="ID_1486878938" MODIFIED="1773369159508" TEXT="OutputSlotImplBase hat &#xfc;berhaupt keine API-Funktion, sondern dient nur als Typing-Scope">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
und daf&#252;r wird aber die VTable &#187;durchgef&#228;delt&#171; ... erst eine davon abgeleitete konkrete Implementierung bietet dann die Factory-Methode, die den Typ tats&#228;chlich festlegt
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
</node>
<node CREATED="1773369169156" ID="ID_214225108" MODIFIED="1773369180790" TEXT="Verbesserungsversuch....">
<node CREATED="1773369183338" ID="ID_1251387186" MODIFIED="1773369195156" TEXT="der PImpl k&#xf6;nnte direkt eine Allocation halten"/>
<node CREATED="1773369240283" ID="ID_1908925521" MODIFIED="1773369252845" TEXT="dann w&#xe4;re bereits AllocState getemplated">
<node CREATED="1773369255863" ID="ID_650591769" MODIFIED="1773369272046" TEXT="und h&#xe4;tte nur die Aufgabe, die einzelnen Connections zu managen"/>
<node CREATED="1773452438012" ID="ID_1278277039" MODIFIED="1773452447061" TEXT="das kann dann aber keine abstrakte Klasse mehr sein"/>
<node CREATED="1773452448298" ID="ID_1336231928" MODIFIED="1773452466651" TEXT="&#x27f9; umstellen auf den &#xbb;RAII style&#xab; von ScopedCollection">
<node CREATED="1773452476717" ID="ID_147983584" MODIFIED="1773452494223" TEXT="das alte Design war ungeschickt..."/>
<node CREATED="1773452495003" ID="ID_546834834" MODIFIED="1773452504462" TEXT="und au&#xdf;erdem auch unn&#xf6;tigerweise stateful"/>
<node CREATED="1773452514440" ID="ID_287465602" MODIFIED="1773452676005" TEXT="gab&apos;s damals schon den &#xbb;Populator&#xab; ?">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
....oder war das mit der <font face="Monospaced" color="#754848">ScopedCollection</font>&#160;ein sp&#228;terer retro-fit?
</p>
<p>
Jedenfalls halte ich das aus heutiger Sicht immer noch f&#252;r eine gute L&#246;sung; man k&#246;nnte h&#246;chtstens die ScopedCollection noch etwas ausbauen (Policy f&#252;r die Storage? UninitialisedStorage f&#252;r die Impl verwenden?)
</p>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#dedca9" CREATED="1773454700253" ID="ID_380862630" MODIFIED="1773454743253">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
eins ist klar:<i>&#160;Lambdas sind sch&#246;n</i>
</p>
</body>
</html></richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
</node>
</node>
<node CREATED="1773423115479" ID="ID_1275456830" MODIFIED="1773423123305" TEXT="Probleme / H&#xfc;rden">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1773423124811" ID="ID_1029911055" MODIFIED="1773423172313" TEXT="die Deallokation soll automatisch sein!">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1773423131415" ID="ID_1566753229" MODIFIED="1773423147739" TEXT="wer mu&#xdf; wen konkret getypt sehen?">
<icon BUILTIN="help"/>
</node>
</node>
</node>
</node>
</node> </node>
</node> </node>
<node CREATED="1771532464268" ID="ID_1570776013" MODIFIED="1771532466986" TEXT="Aufbau"/> <node CREATED="1771532464268" ID="ID_1570776013" MODIFIED="1771532466986" TEXT="Aufbau"/>
@ -168295,7 +168420,7 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
</node> </node>
<node CREATED="1742429811135" ID="ID_586841788" MODIFIED="1742429828889" TEXT="debuild : ein front-End f&#xfc;r dpkg-buildpackage + f&#xfc;r Quellpakete"/> <node CREATED="1742429811135" ID="ID_586841788" MODIFIED="1742429828889" TEXT="debuild : ein front-End f&#xfc;r dpkg-buildpackage + f&#xfc;r Quellpakete"/>
</node> </node>
<node CREATED="1743342264364" FOLDED="true" ID="ID_1682484515" MODIFIED="1743342606290" TEXT="Reprepro"> <node CREATED="1743342264364" FOLDED="true" ID="ID_1682484515" MODIFIED="1773285915809" TEXT="Reprepro">
<icon BUILTIN="idea"/> <icon BUILTIN="idea"/>
<node CREATED="1743342269411" ID="ID_435457412" MODIFIED="1743342277894" TEXT="leichtgewichtiges Setup f&#xfc;r ein DEB-Depot"/> <node CREATED="1743342269411" ID="ID_435457412" MODIFIED="1743342277894" TEXT="leichtgewichtiges Setup f&#xfc;r ein DEB-Depot"/>
<node CREATED="1743342285825" FOLDED="true" ID="ID_888901502" MODIFIED="1743342445654" TEXT="verwende dies f&#xfc;r Lumiera seit vielen Jahren"> <node CREATED="1743342285825" FOLDED="true" ID="ID_888901502" MODIFIED="1743342445654" TEXT="verwende dies f&#xfc;r Lumiera seit vielen Jahren">
@ -168345,6 +168470,21 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
<icon BUILTIN="yes"/> <icon BUILTIN="yes"/>
</node> </node>
</node> </node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1773285927456" ID="ID_314179538" LINK="https://www.debian.org/doc/debian-policy/upgrading-checklist.html#version-4-7-3" MODIFIED="1773286526973" TEXT="Priority &apos;optoinal&apos; ist Default seit Debian-Standard 4.7.3">
<linktarget COLOR="#b70c25" DESTINATION="ID_314179538" ENDARROW="Default" ENDINCLINATION="-11;644;" ID="Arrow_ID_449203010" SOURCE="ID_1697601750" STARTARROW="None" STARTINCLINATION="1051;70;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1773285988207" ID="ID_825405448" MODIFIED="1773286017503" TEXT="Reprepro braucht aber (noch?) diese Angabe">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
m&#246;glicherweise weil ich eine Version aus Debian/stable verwende?
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1773286019099" ID="ID_633768255" MODIFIED="1773286031902" TEXT="kurzfristiger workaround: -P optional"/>
</node>
</node> </node>
</node> </node>
</node> </node>
@ -205197,6 +205337,12 @@ env.Command('out.bin', 'in.bin', my_action)</code></pre>
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="flag-yellow"/>
</node> </node>
</node> </node>
<node CREATED="1773286426445" ID="ID_1823743836" MODIFIED="1773286429881" TEXT="Infrastruktur">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1773286431590" ID="ID_1697601750" MODIFIED="1773286526973" TEXT="Reprepro-Config: Override-File f&#xfc;r Priority?">
<arrowlink COLOR="#b70c25" DESTINATION="ID_314179538" ENDARROW="Default" ENDINCLINATION="-11;644;" ID="Arrow_ID_449203010" STARTARROW="None" STARTINCLINATION="1051;70;"/>
<icon BUILTIN="help"/>
</node>
</node>
</node> </node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1689610305547" ID="ID_1569437785" MODIFIED="1689610311743" TEXT="QA-testing"> <node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1689610305547" ID="ID_1569437785" MODIFIED="1689610311743" TEXT="QA-testing">
<icon BUILTIN="hourglass"/> <icon BUILTIN="hourglass"/>