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:
parent
d91ca67a27
commit
0178e11e65
7 changed files with 242 additions and 144 deletions
|
|
@ -12,44 +12,46 @@
|
|||
*/
|
||||
|
||||
/** @file scoped-collection.hpp
|
||||
** Managing a collection of non-copyable polymorphic objects in compact storage.
|
||||
** This helper supports the frequently encountered situation where a service
|
||||
** implementation internally manages a collection of implementation related
|
||||
** sub-components with reference semantics. Typically, those objects are
|
||||
** being used polymorphically, and often they are also added step by step.
|
||||
** The storage holding all those child objects is allocated in one chunk
|
||||
** and never adjusted.
|
||||
** Manage a collection of non-copyable polymorphic objects in compact storage.
|
||||
** This helper supports common situation where a service implementation has to
|
||||
** manages a fixed collection of implementation related sub-components, treated
|
||||
** with reference semantics. Typically, those objects are used polymorphically,
|
||||
** and often even with _type erasure_ and added step by step through a builder.
|
||||
** The storage to hold all those child objects is allocated in one chunk
|
||||
** and never adjusted. Individual children are never re-ordered or removed,
|
||||
** only the collection as a whole is discarded eventually.
|
||||
**
|
||||
** # usage patterns
|
||||
**
|
||||
** 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,
|
||||
** 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
|
||||
** resource handles to be available exactly as long as the managing object
|
||||
** needs and accesses them.
|
||||
** side effect is one of the reasons for using the container: we want to own
|
||||
** some resource handles and be sure they are available exactly as long as
|
||||
** the managing scope is alive and able to access them.
|
||||
**
|
||||
** There are two different usage patterns for populating a ScopedCollection
|
||||
** - 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
|
||||
** number of objects is (heap) allocated right away, but no objects are
|
||||
** ctor to specify the maximum size only). The storage capacity to hold
|
||||
** 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
|
||||
** by invoking #emplaceElement() to create a new element of the default
|
||||
** 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
|
||||
** right away, immediately after the memory allocation. This usage pattern
|
||||
** avoids any kind of "lifecycle state". Either the container comes up sane
|
||||
** and fully populated, or the ctor call fails and any already created
|
||||
** objects are discarded.
|
||||
** @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
|
||||
** by the template parameter `I`. But you need to ensure in this case
|
||||
** that the defined buffer size for each element (2nt template parameter)
|
||||
** is sufficient to hold any of these subclass instances. This condition
|
||||
** 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**
|
||||
**
|
||||
** @see ScopedCollection_test
|
||||
|
|
@ -160,7 +162,7 @@ namespace lib {
|
|||
* Ctor fails in case of any error during element creation.
|
||||
* @param builder functor to be invoked for each "slot".
|
||||
* 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>
|
||||
ScopedCollection (size_t maxElements, CTOR builder)
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ namespace out {
|
|||
* remains in memory until shutdown of the current executable
|
||||
*/
|
||||
class DiagnosticOutputSlot
|
||||
: public OutputSlotImplBase
|
||||
: public OutputSlot
|
||||
{
|
||||
|
||||
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
|
||||
*/
|
||||
class SimulatedOutputSequences
|
||||
: public AllocStateHub<TrackingInMemoryBlockSequence>
|
||||
: public AllocState<TrackingInMemoryBlockSequence>
|
||||
{
|
||||
typedef AllocStateHub<TrackingInMemoryBlockSequence> _Base;
|
||||
|
||||
void
|
||||
buildConnection(ConnectionStorage storage)
|
||||
{
|
||||
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
|
||||
storage.create<TrackingInMemoryBlockSequence>();
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
|
||||
}
|
||||
using _Base = AllocState<TrackingInMemoryBlockSequence>;
|
||||
|
||||
public:
|
||||
SimulatedOutputSequences (uint numChannels)
|
||||
: _Base(numChannels)
|
||||
{
|
||||
init();
|
||||
}
|
||||
: _Base{ numChannels
|
||||
,[](ConnectionStorage& storage)
|
||||
{
|
||||
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 */
|
||||
unique_ptr<AllocState>
|
||||
unique_ptr<Allocation>
|
||||
buildState()
|
||||
{
|
||||
return make_unique<SimulatedOutputSequences> (
|
||||
|
|
@ -402,7 +399,8 @@ namespace out {
|
|||
{
|
||||
REQUIRE (!isFree(), "diagnostic OutputSlot not (yet) connected");
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -33,19 +33,20 @@
|
|||
#include "lib/error.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "vault/out/output-slot.hpp"
|
||||
#include "vault/mem/buffhandle.hpp"
|
||||
#include "lib/scoped-collection.hpp"
|
||||
#include "lib/iter-adapter-stl.hpp"
|
||||
#include "lib/iter-source.hpp"
|
||||
#include "lib/handle.hpp"
|
||||
//#include "lib/time/timevalue.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
//#include "steam/engine/buffer-provider.hpp"
|
||||
//#include "steam/play/timings.hpp"
|
||||
//#include "lib/sync.hpp"
|
||||
#include "vault/mem/buffer-provider.hpp"
|
||||
|
||||
//#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
//#include <vector>
|
||||
//#include <memory>
|
||||
|
||||
|
||||
|
|
@ -53,8 +54,8 @@ namespace vault {
|
|||
namespace out {
|
||||
|
||||
using vault::mem::BuffHandle;
|
||||
//using vault::mem::BufferProvider;
|
||||
//using lib::time::Time;
|
||||
using vault::mem::BufferProvider;
|
||||
using lib::time::TimeValue; /////////////////OOO Rly?
|
||||
//using std::string;
|
||||
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 ===== */
|
||||
|
||||
/** Base for OutputSlot standard implementation */
|
||||
class OutputSlotImplBase
|
||||
: public OutputSlot
|
||||
{
|
||||
protected:
|
||||
template<class CON>
|
||||
class AllocStateHub;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Maintaining a list of active connections.
|
||||
* Base class for the typical implementation approach.
|
||||
* Using this class is \em not mandatory. But obviously,
|
||||
* we'd get to manage a selection of Connection objects
|
||||
* representing the "active points" in several media channels
|
||||
* connected through this OutputSlot. These Connection subclasses
|
||||
* are what is referenced by the DataSink smart-ptrs handed out
|
||||
* to the client code. As AllocState implements the Allocation
|
||||
* API, it has the liability to create these DataSink smart-ptrs,
|
||||
* which means to wire them appropriately and also provide an
|
||||
* deleter function (here #shutdownConnection) to be invoked
|
||||
* when the last copy of the smart-handle goes out of scope.
|
||||
*
|
||||
* The typical standard/base implementation provided here
|
||||
* manages a collection of active Connection subclass objects.
|
||||
* Implementation of active Allocation state: maintaining
|
||||
* a list of active connections. An instance is created whenever
|
||||
* a client _locks_ (and thereby »allocates«) the OutputSlot. The
|
||||
* actual implementation of OutputSlot::buildState() will employ a
|
||||
* custom Connection, where all the actual state handling and data
|
||||
* transport is implemented. Such a Connection subclass is also what
|
||||
* is referenced by the DataSink smart-hendle, that is handed out
|
||||
* to the client code and allows to mark the state transitions.
|
||||
* Theses smart-handles are ref counting and thus the individual
|
||||
* Connection object is kept alive as long as at least one DataSink
|
||||
* handle is retained. The deleter function #shutdownConnection is
|
||||
* is invoked for each abandoned connection; once all connections
|
||||
* are defunct, the AllocState itself can be deconfigured.
|
||||
*/
|
||||
template<class CON>
|
||||
class OutputSlotImplBase::AllocStateHub
|
||||
: public OutputSlot::AllocState
|
||||
class OutputSlot::AllocState
|
||||
: public OutputSlot::Allocation
|
||||
{
|
||||
typedef lib::ScopedCollection<CON> Connections;
|
||||
typedef OutputSlot::OpenedSinks OpenedSinks;
|
||||
using Connections = lib::ScopedCollection<CON>;
|
||||
using OpenedSinks = OutputSlot::OpenedSinks;
|
||||
|
||||
Connections connections_;
|
||||
|
||||
|
|
@ -191,32 +160,22 @@ namespace out {
|
|||
|
||||
|
||||
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 */
|
||||
virtual void buildConnection(ConnectionStorage) =0;
|
||||
|
||||
|
||||
AllocStateHub(uint numChannels)
|
||||
: connections_(numChannels)
|
||||
{ }
|
||||
|
||||
public:
|
||||
virtual
|
||||
~AllocStateHub()
|
||||
/**
|
||||
* The actual implementation of OutputSlot::buildState() needs to build
|
||||
* 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()
|
||||
*/
|
||||
template<class CTOR>
|
||||
AllocState(uint numChannels, CTOR&& populator)
|
||||
: connections_(numChannels, std::forward<CTOR>(populator))
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
private: // Implementation details
|
||||
private: /* === Implementation details === */
|
||||
|
||||
static DataSink
|
||||
connectOutputSink (CON& connection)
|
||||
|
|
|
|||
|
|
@ -59,11 +59,11 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/handle.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "vault/mem/buffer-provider.hpp"
|
||||
#include "vault/mem/buffhandle.hpp"
|
||||
#include "vault/out/timings.hpp"
|
||||
#include "lib/iter-source.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -72,11 +72,7 @@ namespace vault {
|
|||
namespace out {
|
||||
|
||||
using vault::mem::BuffHandle;
|
||||
using vault::mem::BufferProvider;
|
||||
using lib::time::FrameCnt;
|
||||
using lib::time::TimeValue;
|
||||
using lib::time::Time;
|
||||
|
||||
using std::unique_ptr;
|
||||
|
||||
|
||||
|
|
@ -93,28 +89,15 @@ namespace out {
|
|||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
class OutputSlot
|
||||
: 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:
|
||||
virtual ~OutputSlot();
|
||||
|
||||
|
|
@ -128,13 +111,9 @@ namespace out {
|
|||
|
||||
virtual Timings getTimingConstraints() =0;
|
||||
|
||||
protected:
|
||||
~Allocation(); ///< never to be managed by clients directly
|
||||
~Allocation(); ///< this is an interface
|
||||
};
|
||||
|
||||
/** established output channel */
|
||||
class Connection;
|
||||
|
||||
|
||||
/** can this OutputSlot be allocated? */
|
||||
bool isFree() const;
|
||||
|
|
@ -145,6 +124,22 @@ namespace out {
|
|||
/** disconnect from this OutputSlot
|
||||
* @warning may block until DataSinks are gone */
|
||||
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)
|
||||
or (sink1 and sink2
|
||||
and & sink1.impl() == & sink2.impl());
|
||||
}
|
||||
friend bool operator!= (DataSink const& sink1, DataSink const& sink2)
|
||||
{
|
||||
return not (sink1 == sink2);
|
||||
and util::isSameObject (sink1.impl(), sink2.impl()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace vault::out
|
||||
#endif /*VAULT_OUT_OUTPUT_SLOT_H*/
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ namespace test{
|
|||
|
||||
|
||||
// Verify correct behaviour of iteration end
|
||||
CHECK (! (coll.end()));
|
||||
CHECK (not bool(coll.end()));
|
||||
CHECK (isnil (coll.end()));
|
||||
|
||||
VERIFY_ERROR (ITER_EXHAUST, *coll.end() );
|
||||
|
|
@ -303,7 +303,7 @@ namespace test{
|
|||
|
||||
CollD coll (6, Populator(rr, trigger));
|
||||
|
||||
CHECK (!isnil (coll));
|
||||
CHECK (not isnil (coll));
|
||||
CHECK (6 == coll.size());
|
||||
CHECK (0 != Dummy::checksum());
|
||||
|
||||
|
|
@ -314,7 +314,7 @@ namespace test{
|
|||
CHECK (coll[4].calc(0) == 4 + rr);
|
||||
CHECK (coll[5].calc(0) == 5 + rr + trigger);
|
||||
// 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
|
||||
// reveal the trigger value
|
||||
// - the population was indeed done with the anonymous Populator
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "stage/ctrl/bus-term.hpp"
|
||||
#include "stage/model/tangible.hpp"
|
||||
#include "stage/ctrl/state-manager.hpp"
|
||||
|
|
@ -49,6 +50,8 @@
|
|||
#include <string>
|
||||
|
||||
|
||||
using lib::Symbol;
|
||||
|
||||
namespace stage {
|
||||
namespace test{
|
||||
|
||||
|
|
|
|||
|
|
@ -137463,6 +137463,131 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1773354410472" ID="ID_1743624174" MODIFIED="1773354422590" TEXT="bestehende Implementierung überprü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ü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ß auch die Impl-Base fü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ß ich das damals überahupt nicht gesehen habe; mein Level war also, daß ich zwar ziemlich direkt ein solches Protokoll in OO-Interfaces übersetzen konnte, aber das Denken in Zonen / Domä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 Ö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äuft für alle gemeinsam
|
||||
</li>
|
||||
<li>
|
||||
oder die Allokation ist lediglich eine logische Klammer, und die eigentliche Implementierung ist N-fach aufgedoppelt, fü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 »dünn«">
|
||||
<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"> </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">&</font><font color="#3a1f18" face="Bitstream Vera Sans Mono" size="9pt"> </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">  </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"> </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"> </font>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
...natürlich wird die verwendet, aber irgendwo aus der konkreten Implementierung (DiagnosticOutputSlot) heraus. Das ist ein <i>telltale sign</i> — natü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üssen. Das ist hier nicht der Fall; warum sollte ein konkreter OutputSlot von oben herab auf einzelnen Connections zugreifen müssen? Konkret habe ich das verwendet, um das ganze Diagnose-API darauf aufzubauen. Jaja, sowas nennt man »hexagonales Design« — 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 überhaupt keine API-Funktion, sondern dient nur als Typing-Scope">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
und dafür wird aber die VTable »durchgefädelt« ... erst eine davon abgeleitete konkrete Implementierung bietet dann die Factory-Methode, die den Typ tatsä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önnte direkt eine Allocation halten"/>
|
||||
<node CREATED="1773369240283" ID="ID_1908925521" MODIFIED="1773369252845" TEXT="dann wäre bereits AllocState getemplated">
|
||||
<node CREATED="1773369255863" ID="ID_650591769" MODIFIED="1773369272046" TEXT="und hä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="⟹ umstellen auf den »RAII style« 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ßerdem auch unnötigerweise stateful"/>
|
||||
<node CREATED="1773452514440" ID="ID_287465602" MODIFIED="1773452676005" TEXT="gab's damals schon den »Populator« ?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
....oder war das mit der <font face="Monospaced" color="#754848">ScopedCollection</font> ein späterer retro-fit?
|
||||
</p>
|
||||
<p>
|
||||
Jedenfalls halte ich das aus heutiger Sicht immer noch für eine gute Lösung; man könnte höchtstens die ScopedCollection noch etwas ausbauen (Policy für die Storage? UninitialisedStorage fü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> Lambdas sind schön</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1773423115479" ID="ID_1275456830" MODIFIED="1773423123305" TEXT="Probleme / Hü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ß wen konkret getypt sehen?">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771532464268" ID="ID_1570776013" MODIFIED="1771532466986" TEXT="Aufbau"/>
|
||||
|
|
@ -168295,7 +168420,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
|
|||
</node>
|
||||
<node CREATED="1742429811135" ID="ID_586841788" MODIFIED="1742429828889" TEXT="debuild : ein front-End für dpkg-buildpackage + für Quellpakete"/>
|
||||
</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"/>
|
||||
<node CREATED="1743342269411" ID="ID_435457412" MODIFIED="1743342277894" TEXT="leichtgewichtiges Setup für ein DEB-Depot"/>
|
||||
<node CREATED="1743342285825" FOLDED="true" ID="ID_888901502" MODIFIED="1743342445654" TEXT="verwende dies für Lumiera seit vielen Jahren">
|
||||
|
|
@ -168345,6 +168470,21 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
|
|||
<icon BUILTIN="yes"/>
|
||||
</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 'optoinal' 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ö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>
|
||||
|
|
@ -205197,6 +205337,12 @@ env.Command('out.bin', 'in.bin', my_action)</code></pre>
|
|||
<icon BUILTIN="flag-yellow"/>
|
||||
</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ü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 BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1689610305547" ID="ID_1569437785" MODIFIED="1689610311743" TEXT="QA-testing">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue