From bd09d9fbbb60292e4de0b5fff827da01ac2bbf5d Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 23 Mar 2026 21:49:17 +0100 Subject: [PATCH] OutputSlot: draft new setup for the DiagnosticOutputSlot This will be the first ''reality test'' for the new `OutputSlot` internal design: Is it possible to implement a tracking test implementation in a clean and straight-forward way, avoiding all the tangling and indirection that plagued the old prototype implementation from 2012? --- src/vault/out/diagnostic-output-slot.cpp | 111 ++++++++++++- src/vault/out/diagnostic-output-slot.hpp | 47 +++++- src/vault/out/output-slot.hpp | 1 + wiki/thinkPad.ichthyo.mm | 192 +++++++++++++++++++++-- 4 files changed, 331 insertions(+), 20 deletions(-) diff --git a/src/vault/out/diagnostic-output-slot.cpp b/src/vault/out/diagnostic-output-slot.cpp index 0185bcec2..9ef766983 100644 --- a/src/vault/out/diagnostic-output-slot.cpp +++ b/src/vault/out/diagnostic-output-slot.cpp @@ -19,10 +19,12 @@ #include "lib/error.hpp" +#include "lib/nocopy.hpp" #include "vault/out/diagnostic-output-slot.hpp" //#include "vault/out/output-slot-connection.hpp" //#include +#include namespace vault { @@ -30,15 +32,118 @@ namespace out { namespace err = lumiera::error; // using std::vector; +// using Config = DiagnosticOutputSlot::Config; + using std::move; + using std::make_unique; + + namespace { // Implementation details of tracking + + }//(End)Impl details + + class DiagnosticOutputSlot::OutputTracker + : public Config + , util::NonCopyable + { + public: + OutputTracker (Config&& config) + : Config{move (config)} + { } + }; + + + class DiagnosticOutputSlot::DummyConnection + : public OutputSlot::Connection + , util::NonCopyable + { + OutputTracker& tracker_; + + + /* === Connection API === */ + + size_t + getBufferSize() const override + { + return tracker_.bufferSize; + } + + Buff* + claimBufferFor(FrameID frame) override + { + UNIMPLEMENTED ("lock new buffer"); + } + + void + publish (Buff* buff) override + { + UNIMPLEMENTED ("publish buffer"); + } + + void + release (Buff* buff) override + { + UNIMPLEMENTED ("release buffer"); + } + + void + shutDown() override + { + TODO ("Anything to record at connection shut-down?"); + } + + + + public: + DummyConnection (OutputTracker& tracker) + : tracker_{tracker} + { } + }; + DiagnosticOutputSlot::~DiagnosticOutputSlot() { } // emit destructors for hidden implementation here.... + DiagnosticOutputSlot::DiagnosticOutputSlot (Config config) + : DiagnosticOutputSlot{setupOutputTracker(move (config))} + { } -// OutputSlot::~OutputSlot() { } // emit VTables here.... - - + /** + * @internal setup and construction sequence for the diagnostic tracking. + * This tricky call sequence is required to resolve two conflicting goals + * - we want a complete one-shot setup and wiring in the constructor. + * - we want DiagnosticOutputSlot be usable like an OutputSlot, + * even when this implies to create a slicing copy (its a value object!) + * These requirements imply that OutputSlot should be the (first) base object, + * but should also be initialised with the OutputTracker, which however can + * only be initialised _after_ the base object. + * + * Yet the OutputTracker is installed as a »PImpl« and managed by a shared-ptr anyway, + * so that this contradiction can be circumvented by constructing it first, as a constructor + * argument \a trackingSetup prepared through a chained constructor call. It is thus visible + * in the complete scope of the constructor, so that we can pass it to the base class + * constructor, and later then move it into the final location in the derived class. + */ + DiagnosticOutputSlot::DiagnosticOutputSlot (shared_ptr trackingSetup) + : OutputSlot{setupTrackingConnections (*trackingSetup)} + , tracker_{move(trackingSetup)} + { } + + shared_ptr + DiagnosticOutputSlot::setupOutputTracker (Config&& config) + { + + } + unique_ptr + DiagnosticOutputSlot::setupTrackingConnections (DiagnosticOutputSlot::OutputTracker& outputTracker) + { + using AllocState = OutputSlot::AllocState; + using ConStorage = AllocState::ConnectionStorage; + + return make_unique (outputTracker.numDataFeeds + ,[&](ConStorage& storage){ storage.create (outputTracker); } + ); + } + /** */ diff --git a/src/vault/out/diagnostic-output-slot.hpp b/src/vault/out/diagnostic-output-slot.hpp index e8b305b6b..06e4666cf 100644 --- a/src/vault/out/diagnostic-output-slot.hpp +++ b/src/vault/out/diagnostic-output-slot.hpp @@ -69,6 +69,8 @@ namespace out { namespace { // diagnostics & internals.... + const uint DEFAULT_DATAFEEDS = 5; + inline PGrid getTestTimeGrid() { @@ -397,13 +399,52 @@ namespace out { UNIMPLEMENTED ("the old tracking API is abandoned, the new one not yet implemented"); } + class OutputTracker; + shared_ptr tracker_; + + /** @internal fake implementation of a connection, + * with callback to the tracker */ + class DummyConnection; public: - DiagnosticOutputSlot() - : OutputSlot(unique_ptr{nullptr}) //////////////////////OOO Kabooooooom!! --- should actually configure a suitable Allcation subclass here - { } + struct Config + { + uint numDataFeeds{DEFAULT_DATAFEEDS}; + size_t bufferSize{sizeof(TestFrame)}; + + + /** @todo workaround for an arcane complier / language problem, + * causing the compiler wrongly to treat Config as incomplete, + * see [Stackoverflow], [Bugzilla], [CoreWorkingGroup-2335]. + * @note using a static function, thus keeping Config a plain aggregate. + * [Stackoverflow]: https://stackoverflow.com/q/53408962/444796 + * [Bugzilla]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88165 + * [CoreWorkingGroup-2335]: https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2335 + */ + static constexpr Config defaults() { return {}; } + }; + /** + * Official (default) constructor to create a DiagnosticOutputSlot. + * When invoked without argument, the default Config applies, otherwise + * the explicitly given config values are uses. The resulting object + * has value semantics and is automatically activated and ready to use. + * It can be used in the same way as a regular OutputSlot, as a copyable + * value handle; it can even be slice-copied. + * @note you need to keep around one copy after the test, + * in order to [access the diagnostics](\ref watch) + */ + DiagnosticOutputSlot(Config =Config::defaults()); + + // standard copy operations acceptable + ~DiagnosticOutputSlot(); + + private: + DiagnosticOutputSlot(shared_ptr); + + static shared_ptr setupOutputTracker(Config&&); + static unique_ptr setupTrackingConnections(OutputTracker&); /* === diagnostics API === */ diff --git a/src/vault/out/output-slot.hpp b/src/vault/out/output-slot.hpp index fec262528..05c83cfea 100644 --- a/src/vault/out/output-slot.hpp +++ b/src/vault/out/output-slot.hpp @@ -120,6 +120,7 @@ namespace out { DataSink (FUN&& fun) : std::function{std::forward (fun)} { } + /////////////////////////////////////////////TICKET #1377 : presumably we want some stream-type hash ID here -- to allow building a processing-ID for each Render Node invocation }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9197bcb36..4832fd21e 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -114149,7 +114149,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -114372,8 +114373,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + + + + + @@ -137966,10 +137971,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + - + + + + + + +

+ Die Standard-Implementierung in AllocState<CON> verwendet eine ScopedCollection. Man muß sich also festlegen +

+ +
+ +
+ + @@ -138143,7 +138163,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -138212,8 +138232,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) die connect()-Funktion liefert eine IterSource<DataSink>

- - +
@@ -138394,8 +138413,17 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + + +

+ dieses neue Verschaltungs-Konzept implementieren +

+ +
+ @@ -138760,8 +138788,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) ein shared-ptr mit Alias auf die jeweilige Connection

- - + @@ -138935,7 +138962,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

- +
@@ -139195,9 +139222,146 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
- + + + + + + + + + + + + + + + + + +

+ ...weil es die produktiven Einrichtungen widerspiegelt, genauso verwendet wird, und nach Bedarf auch im weiteren Umfeld als Diagnose-Tracker verwendbar wäre +

+ +
+ + + + + + + + + + + + + + +
    +
  • + Vorteil: einfach und offensichtlich +
  • +
  • + Nachteil: komplett anders als der echte OutputSlot +
  • +
+ +
+
+ + + +
+ + + + +

+ Das hier ist ein TEST. +

+

+ Ich muß ihn nicht einmal mehr (neu) schreiben, sondern nur noch flicken. +

+

+ Und niemand weiß ob jemals mehr davon gebraucht wird... +

+ +
+
+
+ + + + + + +

+ Man muß einen DiagnosticOutputSlot erzeugen und konfigurieren können, und diesen dann weiter verwenden, als wäre es ein normaler OutputSlot +

+ +
+
+ + + +
+
+ + + + + + +

+ Muß offensichtlich, aus Gründen der Symmetrie, und wegen den Anforderungen an den Gebrauch +

+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ dieser wird transient als Konstruktor-Argument gebaut +

+ +
+
+
+
+