From e10aa751bbbf3ad3981068ed5d5a9affdd790404 Mon Sep 17 00:00:00 2001
From: Ichthyostega
Date: Thu, 12 Feb 2026 02:28:41 +0100
Subject: [PATCH] BufferProvider: design a new diagnostics API
To push ahead with the refactoring,
I will build the test/diagnostics API completely anew,
and attach it solely to an instance of `DiagnosticBufferProvider`.
Unfortunately this ''leads us into chainsaw surgery...''
* it uncovers a host of conceptual contradictions
* actually, the `HeapMemProvider` was more an implementation
of diagnostic tracking, than it was an actual `BufferProvider`
implementation (hence the old name: `TrackingHeapBlockProivder`)
* and this lured me into using these tracking functions directly,
while the `DiagnosticBufferProvider` remained in unfinished state.
So basically I have now **disabled** all verification from the Unit-tests.
I'll have to rebuild them from scratch, thereby reproducing the logic/intention
---
.../engine/diagnostic-buffer-provider.cpp | 38 +-
.../engine/diagnostic-buffer-provider.hpp | 38 +-
src/steam/engine/heap-mem-buffer-store.cpp | 91 ++-
src/steam/engine/heap-mem-buffer-store.hpp | 74 +-
.../engine/buffer-provider-protocol-test.cpp | 6 +-
.../diagnostic-buffer-provider-test.cpp | 4 +
.../steam/play/diagnostic-output-slot.hpp | 8 +
wiki/thinkPad.ichthyo.mm | 675 +++++++++++++++---
8 files changed, 750 insertions(+), 184 deletions(-)
diff --git a/src/steam/engine/diagnostic-buffer-provider.cpp b/src/steam/engine/diagnostic-buffer-provider.cpp
index 2b0bb6aa5..e46ad4086 100644
--- a/src/steam/engine/diagnostic-buffer-provider.cpp
+++ b/src/steam/engine/diagnostic-buffer-provider.cpp
@@ -31,10 +31,19 @@
namespace steam {
namespace engine {
+ /**
+ * Implementation of tracking and instrumentation
+ */
+ class DiagnosticBufferProvider::BlockTracker
+ {
+
+ };
+
DiagnosticBufferProvider::DiagnosticBufferProvider()
: NaiveBufferSetup{}
, heapStore_{dynamic_cast (*bufferStore_)}
+ , tracker_{std::make_unique()}
{ }
DiagnosticBufferProvider::~DiagnosticBufferProvider()
@@ -50,22 +59,45 @@ namespace engine {
bool
BufferDiagnostic::buffer_was_used (uint bufferID)
{
- return dbp_.heapStore_.access_emitted(bufferID).was_used();
+ NOTREACHED ("shall use new API only");
+// return dbp_.heapStore_.access_emitted(bufferID).was_used(); //////////////////////////////////////////TICKET 1410 : switch to newly defined tracking-API
}
bool
BufferDiagnostic::buffer_was_closed (uint bufferID)
{
- return dbp_.heapStore_.access_emitted(bufferID).was_closed();
+ NOTREACHED ("shall use new API only");
+// return dbp_.heapStore_.access_emitted(bufferID).was_closed();//////////////////////////////////////////TICKET 1410 : switch to newly defined tracking-API
}
void*
BufferDiagnostic::accessMemory (uint bufferID)
{
- return dbp_.heapStore_.access_emitted(bufferID).accessMemory();
+ NOTREACHED ("shall use new API only");
+// return dbp_.heapStore_.access_emitted(bufferID).accessMemory(); ///////////////////////////////////////TICKET 1410 : switch to newly defined tracking-API
+ }
+
+ diagn::StateReg&
+ BufferDiagnostic::created ()
+ {
+ UNIMPLEMENTED ("track all created buffer blocks");
+ }
+
+ diagn::StateReg&
+ BufferDiagnostic::emitted ()
+ {
+ UNIMPLEMENTED ("track all emitted buffer blocks");
+ }
+
+ diagn::StateReg&
+ BufferDiagnostic::released()
+ {
+ UNIMPLEMENTED ("track all released buffer blocks");
}
+
+
}} // namespace engine
diff --git a/src/steam/engine/diagnostic-buffer-provider.hpp b/src/steam/engine/diagnostic-buffer-provider.hpp
index 237a09ae7..6673af5b0 100644
--- a/src/steam/engine/diagnostic-buffer-provider.hpp
+++ b/src/steam/engine/diagnostic-buffer-provider.hpp
@@ -35,9 +35,31 @@ namespace engine {
namespace error = lumiera::error;
- class HeapMemProvider;
+ class HeapMemProvider; //////////////////////////////OOO fällt dann weg nach dem Umbau
class BufferDiagnostic;
+ namespace diagn {// state descriptors for diagnostics....
+
+ struct Block
+ : BuffHandle
+ , util::NonCopyable
+ {
+
+ Block(BuffHandle const& handle) : BuffHandle{handle} { }
+ Block(BuffDescr const& descr) : BuffHandle{descr} { }
+ };
+
+ class StateReg
+ : util::NonCopyable
+ {
+ public:
+ size_t cnt() const;
+ Block const& operator[] (size_t seqNr) const;
+ Block const& byHandle (HashVal handle) const;
+ };
+
+ }//(End)diagnostic descriptors.
+
/****************************************************************//**
@@ -48,8 +70,9 @@ namespace engine {
class DiagnosticBufferProvider
: public NaiveBufferSetup
{
- HeapMemProvider& heapStore_;
-
+ HeapMemProvider& heapStore_; //////////////////////////////OOO fällt dann weg nach dem Umbau
+ class BlockTracker;
+ std::unique_ptr tracker_;
public:
~DiagnosticBufferProvider();
@@ -70,10 +93,13 @@ namespace engine {
{ }
- bool buffer_was_used (uint bufferID);
- bool buffer_was_closed (uint bufferID);
- void* accessMemory (uint bufferID);
+ bool buffer_was_used (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410
+ bool buffer_was_closed (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410
+ void* accessMemory (uint bufferID); ///< @deprecated ////////////////////////////////////////TICKET 1410
bool all_buffers_released();
+ diagn::StateReg& created ();
+ diagn::StateReg& emitted ();
+ diagn::StateReg& released();
};
inline BufferDiagnostic
diff --git a/src/steam/engine/heap-mem-buffer-store.cpp b/src/steam/engine/heap-mem-buffer-store.cpp
index d1a32f367..28dd3c31b 100644
--- a/src/steam/engine/heap-mem-buffer-store.cpp
+++ b/src/steam/engine/heap-mem-buffer-store.cpp
@@ -41,6 +41,51 @@ namespace engine {
using Buff = StreamType::ImplFacade::DataBuffer;
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 1410 : need to question what implementation structures are needed, after »tracking« was extracted...
+ /**
+ * Helper for implementing a diagnostic BufferProvider:
+ * A block of heap allocated storage, with the capability
+ * to store some additional tracking information.
+ */
+ class HeapMemProvider::Block
+ : util::NonCopyable
+ {
+ unique_ptr storage_;
+
+ bool was_released_;
+
+ public:
+ explicit
+ Block(size_t bufferSize)
+ : storage_(bufferSize? new char[bufferSize] : NULL)
+ , was_released_(false)
+ { }
+
+ bool
+ was_used() const
+ {
+ return bool(storage_);
+ }
+
+ bool
+ was_closed() const
+ {
+ return was_released_;
+ }
+
+ void*
+ accessMemory() const
+ {
+ REQUIRE (storage_, "Block was never prepared for use");
+ return storage_.get();
+ }
+
+ void
+ markReleased()
+ {
+ was_released_ = true;
+ }
+ };
namespace { // implementation helpers...
inline Buff*
@@ -50,7 +95,7 @@ namespace engine {
}
- using diagn::Block;
+ using Block = HeapMemProvider::Block;
/** helper to find Block entries
* based on their raw memory address */
@@ -82,10 +127,11 @@ namespace engine {
}
-
- namespace diagn {
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 1410 : need to question what implementation structures are needed, after »tracking« was extracted...
- using PoolBlocks = ScopedPtrVect;
+ using PoolBlocks = ScopedPtrVect;
/**
* @internal Pool of allocated buffer Blocks of a specific size.
@@ -98,10 +144,11 @@ namespace engine {
* and later gets "emitted" to an output sequence, where it remains for
* later investigation and diagnostics.
*/
- class BlockPool
+ class HeapMemProvider::BlockPool
{
uint maxAllocCount_;
size_t memBlockSize_;
+ using PoolBlocks = ScopedPtrVect;
PoolBlocks blockList_;
public:
@@ -205,7 +252,7 @@ namespace engine {
return not block.was_used() or block.was_closed();
}
};
- }
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET 1410 : need to question what implementation structures are needed, after »tracking« was extracted...
@@ -213,7 +260,7 @@ namespace engine {
const uint MAX_BUFFERS = 50;
- diagn::Block emptyPlaceholder(0);
+ Block emptyPlaceholder(0);
} // (END) Details of allocation and accounting
@@ -223,7 +270,7 @@ namespace engine {
* @internal create a memory tracking BufferProvider,
*/
HeapMemProvider::HeapMemProvider()
- : pool_(new diagn::PoolTable)
+ : pool_(new PoolTable)
, outSeq_()
{ }
@@ -236,7 +283,7 @@ namespace engine {
uint
HeapMemProvider::prepareBuffers(uint requestedAmount, HashVal typeID)
{
- diagn::BlockPool& responsiblePool = getBlockPoolFor (typeID);
+ BlockPool& responsiblePool = getBlockPoolFor (typeID);
return responsiblePool.prepare_for (requestedAmount);
}
@@ -244,8 +291,8 @@ namespace engine {
BuffHandle
HeapMemProvider::provideLockedBuffer(HashVal typeID)
{
- diagn::BlockPool& blocks = getBlockPoolFor (typeID);
- diagn::Block& newBlock = blocks.createBlock();
+ BlockPool& blocks = getBlockPoolFor (typeID);
+ Block& newBlock = blocks.createBlock();
UNIMPLEMENTED ("Separate tasks into two distinct APIs");
// return buildHandle (typeID, asBuffer(newBlock.accessMemory()), &newBlock); /////////////////////////////OOO instead return a tuple (buffer, localTag)
}
@@ -254,11 +301,11 @@ namespace engine {
void
HeapMemProvider::mark_emitted (HashVal typeID, LocalTag const& specifics)
{
- diagn::Block* block4buffer = locateBlock (typeID, specifics);
+ Block* block4buffer = locateBlock (typeID, specifics);
if (!block4buffer)
throw error::Logic ("Attempt to emit a buffer not known to this BufferProvider"
, LUMIERA_ERROR_BUFFER_MANAGEMENT);
- diagn::BlockPool& pool = getBlockPoolFor (typeID);
+ BlockPool& pool = getBlockPoolFor (typeID);
Block* active = pool.transferResponsibility (block4buffer);
if (active)
outSeq_.manage (active);
@@ -275,7 +322,7 @@ namespace engine {
void
HeapMemProvider::detachBuffer (HashVal typeID, LocalTag const& specifics, Buff& storage)
{
- diagn::Block* block4buffer = locateBlock (typeID, specifics);
+ Block* block4buffer = locateBlock (typeID, specifics);
REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
REQUIRE (util::isSameAdr (storage, block4buffer->accessMemory()));
block4buffer->markReleased();
@@ -298,7 +345,7 @@ namespace engine {
blockPool.discard();
}
- diagn::Block&
+ HeapMemProvider::Block&
HeapMemProvider::access_emitted (uint bufferID)
{
if (!withinOutputSequence (bufferID))
@@ -316,26 +363,28 @@ namespace engine {
return bufferID < outSeq_.size();
}
- diagn::BlockPool&
+ HeapMemProvider::BlockPool&
HeapMemProvider::getBlockPoolFor (HashVal typeID)
{
- diagn::BlockPool& pool = (*pool_)[typeID];
+ BlockPool& pool = (*pool_)[typeID];
UNIMPLEMENTED ("Separate tasks into two distinct APIs");
// if (!pool)
// pool.initialise(getBufferSize(typeID)); //////////////////////////OOO getBufferSize is a helper function in the BufferProvider protected API. Need to be "here"
return pool;
}
- diagn::Block*
+ HeapMemProvider::Block*
HeapMemProvider::locateBlock (HashVal typeID, void* storage)
{
- diagn::BlockPool& pool = getBlockPoolFor (typeID);
- diagn::Block* block4buffer = pool.find (storage); ////////////////////////////////TICKET #856
+ BlockPool& pool = getBlockPoolFor (typeID);
+ Block* block4buffer = pool.find (storage); ////////////////////////////////TICKET #856
return block4buffer? block4buffer
: searchInOutSeqeuence (storage);
}
- diagn::Block*
+
+
+ HeapMemProvider::Block*
HeapMemProvider::searchInOutSeqeuence (void* blockLocation)
{
return pick_Block_by_storage (outSeq_, blockLocation); ////////////////////////////////TICKET #856
diff --git a/src/steam/engine/heap-mem-buffer-store.hpp b/src/steam/engine/heap-mem-buffer-store.hpp
index f2056675d..0af39deb5 100644
--- a/src/steam/engine/heap-mem-buffer-store.hpp
+++ b/src/steam/engine/heap-mem-buffer-store.hpp
@@ -57,54 +57,6 @@ namespace engine {
using std::unique_ptr;
- /**
- * Helper for implementing a diagnostic BufferProvider:
- * A block of heap allocated storage, with the capability
- * to store some additional tracking information.
- */
- class Block
- : util::NonCopyable
- {
- unique_ptr storage_;
-
- bool was_released_;
-
- public:
- explicit
- Block(size_t bufferSize)
- : storage_(bufferSize? new char[bufferSize] : NULL)
- , was_released_(false)
- { }
-
- bool
- was_used() const
- {
- return bool(storage_);
- }
-
- bool
- was_closed() const
- {
- return was_released_;
- }
-
- void*
- accessMemory() const
- {
- REQUIRE (storage_, "Block was never prepared for use");
- return storage_.get();
- }
-
- void
- markReleased()
- {
- was_released_ = true;
- }
- };
-
- class BlockPool;
-
- using PoolTable = std::unordered_map;
}
@@ -120,8 +72,13 @@ namespace engine {
class HeapMemProvider
: public BufferProviderSetup::Store
{
- unique_ptr pool_;
- ScopedPtrVect outSeq_;
+ public: /////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : looks like I'll re-implement the storage from scratch, since »tracking« is no longer required here
+ class Block;
+ class BlockPool;
+ private:
+ using PoolTable = std::unordered_map;
+ unique_ptr pool_;
+ ScopedPtrVect outSeq_;
public:
/* === BufferStore interface === */
@@ -137,7 +94,7 @@ namespace engine {
size_t emittedCnt() const;
- diagn::Block& access_emitted (uint bufferID);
+ Block& access_emitted (uint bufferID);
template
TY& accessAs (uint bufferID);
@@ -146,9 +103,9 @@ namespace engine {
private:
bool withinOutputSequence (uint bufferID) const;
- diagn::BlockPool& getBlockPoolFor (HashVal typeID);
- diagn::Block* locateBlock (HashVal typeID, void*);
- diagn::Block* searchInOutSeqeuence (void* storage);
+ BlockPool& getBlockPoolFor (HashVal typeID);
+ Block* locateBlock (HashVal typeID, void*);
+ Block* searchInOutSeqeuence (void* storage);
};
@@ -168,11 +125,12 @@ namespace engine {
if (!withinOutputSequence (bufferID))
throw error::Invalid ("Buffer with the given ID not yet emitted");
- diagn::Block& memoryBlock = access_emitted (bufferID);
- TY* converted = std::launder (reinterpret_cast (memoryBlock.accessMemory()));
+ Block& memoryBlock = access_emitted (bufferID);
+ NOTREACHED ("TICKET #1410 : tracking implementation -> DiagnosticBufferProvider");
+// TY* converted = std::launder (reinterpret_cast (memoryBlock.accessMemory())); /////////////////////TICKET 1410 : my assumption is that Block will be implemented differently -- at least not used this way...
- REQUIRE (converted);
- return *converted;
+// REQUIRE (converted);
+// return *converted;
}
diff --git a/tests/core/steam/engine/buffer-provider-protocol-test.cpp b/tests/core/steam/engine/buffer-provider-protocol-test.cpp
index dd7145a2a..78eac783f 100644
--- a/tests/core/steam/engine/buffer-provider-protocol-test.cpp
+++ b/tests/core/steam/engine/buffer-provider-protocol-test.cpp
@@ -80,8 +80,8 @@ namespace test {
{
verifySimpleUsage();
verifyRenderingUsage();
- verifyObjectAttachment();
- verifyObjectAttachmentFailure();
+// verifyObjectAttachment();
+// verifyObjectAttachmentFailure(); //////////////////////////OOO need a completely new test case to cover behaviour of failed ctor calls
}
@@ -181,6 +181,7 @@ namespace test {
}
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
void
verifyObjectAttachment()
{
@@ -256,6 +257,7 @@ namespace test {
VERIFY_ERROR (LIFECYCLE, handle_DD.accessAs() );
VERIFY_ERROR (LIFECYCLE, handle_DD.create() );
}
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
};
diff --git a/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp b/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp
index cc6780418..b2b5d8fc7 100644
--- a/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp
+++ b/tests/core/steam/engine/diagnostic-buffer-provider-test.cpp
@@ -42,18 +42,22 @@ namespace test {
bool
has_expectedContent (uint nr, diagn::Block& memoryBlock)
{
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
void* mem = memoryBlock.accessMemory();
uint data = *static_cast (mem);
return data == testNumbers[nr];
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
bool
verifyUsedBlock (uint nr, diagn::Block& memoryBlock)
{
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
return memoryBlock.was_used()
and memoryBlock.was_closed()
and has_expectedContent (nr, memoryBlock);
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
}
diff --git a/tests/core/steam/play/diagnostic-output-slot.hpp b/tests/core/steam/play/diagnostic-output-slot.hpp
index 18952c5c0..609c5b0c8 100644
--- a/tests/core/steam/play/diagnostic-output-slot.hpp
+++ b/tests/core/steam/play/diagnostic-output-slot.hpp
@@ -212,6 +212,7 @@ namespace play {
// return 0; ////////////////////////////////TICKET #856
}
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
diagn::Block const *
accessEmittedBuffer (uint bufferNr) const
{
@@ -221,6 +222,7 @@ namespace play {
// else
// return 0;
}
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
bool
wasAllocated (uint frameNr) const
@@ -238,12 +240,14 @@ namespace play {
// return unConst(this)->buffProvider_.accessAs (frameNr); ///////////////////////////////OOO provide suitable diagnostic API!
}
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
diagn::Block const&
accessBlock (uint bufferNr) const
{
UNIMPLEMENTED ("suitable diagnostic API");
// return unConst(this)->buffProvider_.access_emitted (bufferNr); ///////////////////////////////OOO provide suitable diagnostic API!
}
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
};
@@ -412,20 +416,24 @@ namespace play {
bool
output_was_emitted (uint channel, FrameID outputFrame)
{
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
diagn::Block const *block = accessSequence(channel)
.accessEmittedBuffer(outputFrame);
return block
and block->was_used();
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
bool
output_was_closed (uint channel, FrameID outputFrame)
{
+#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
diagn::Block const *block = accessSequence(channel)
.accessEmittedBuffer(outputFrame);
return block
and block->was_closed();
+#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}
};
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 7d5a61e59..25cd4c1f7 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -84896,7 +84896,8 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
+
@@ -85214,6 +85215,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
@@ -95845,7 +95847,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
@@ -104822,7 +104824,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -105073,12 +105075,15 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
+
+
+
@@ -109721,8 +109726,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
+
@@ -109801,9 +109807,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
+
+
+
@@ -109848,6 +109857,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
@@ -110884,7 +110897,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -110893,6 +110906,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
@@ -110926,7 +110941,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -110935,6 +110950,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
@@ -110981,6 +110997,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
@@ -111165,13 +111182,17 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
@@ -111199,8 +111220,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
+
+
@@ -111380,6 +111401,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
@@ -111443,7 +111469,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -111452,10 +111478,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
-
+
@@ -111464,6 +111492,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
@@ -111476,10 +111505,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
+
+
+
+
@@ -111643,20 +111674,18 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
auch mark_emitted ist gar nicht die Aufgabe des Store!
-
-
+
-
+
+
@@ -111753,28 +111782,22 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
...was bedeutet, daß sie auch durch frei stehende Klassen implementiert werden können
-
-
+
-
-
-
+
heißen: Stage und Store
-
-
+
@@ -111804,6 +111827,16 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+
+
+
+
+
@@ -111824,16 +111857,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
idealerweise funktioniert das sogar ohne dynamic-cast: denn die Dekoratoren könnten direkt per callback-λ verdrahtet sein
-
-
+
@@ -111841,16 +111871,13 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
Frage: kann ProviderBufferProvider einen beliebigen DiagnosticBuffer instrumentieren?
-
-
+
@@ -111861,33 +111888,25 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
-
-
+
⟹ jedweder State des BufferProvider muß in den zwei Implementierungs-Säulen liegen
-
-
+
-
-
-
+
(alternativ müßte ausschließlich ein Diagnose-Accessor erzeugt werden)
-
-
+
-
-
-
+
das sagt auch der Name, es wäre dann kein BufferProvider...
@@ -111896,8 +111915,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
Und ein solches alternatives Nutz-Szenario wäre in der Tat denkbar, müßte dann aber eigens und daneben stehend implementiert werden
-
-
+
@@ -111915,7 +111933,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
+
@@ -111938,7 +111957,10 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
+
+
+
@@ -111947,9 +111969,364 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nicht einmal ... der Buffer-Pointer wird sowiso schon auf NULL gesetzt
+
+
+ .... außerdem: diese Art der Diagnose geht sowiso nur für Einzel-Resourcen (also Sub-Typen), nicht für Buffer-Descriptoren — sofern man das Thema »announcement« explizit ausklammert (YAGNI — es gibt bisher keinen Bedarf, das in einem Test abzudecken, und wer weiß, wie später mal die Diagnose am produktiven Buffer-Manager aussieht....)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UND: es muß eine Erweiterung sein
+
+
+
+
+
+
+
+ zusätzlich zum BuffHandle...
+
+
+ -
+ speichert es stets nochmal redundant den Pointer zur Storage
+
+ -
+ speichert es Infos zum Lebenszyklus
+
+ -
+ speichert es (optional, spätermal) ob der Speicher recycled wurde
+
+
+
+ ganz allgemein: Redundanz ist hier von Vorteil — wir sind in einem geschlossenen Ökosystem
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sonst werden Konsistenz-Fragen schnell zum Albtraum
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...das brauchen wir derzeit (noch) nicht, erscheint aber durchaus sinnvoll zur Fehlersuche:
+
+
+ -
+ in welchem Status befindet sich ein Handle
+
+ -
+ wurde es mehrfach verwendet (derzeit nicht möglich, aber denkbar)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ es gibt da sowas wie ein Test-protocol
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ich find Dich scheiße!
+
+
+
+
+
+
+
+
+
+
+
+ Ich wollte den Code so geschmeidig machen, daß man ihn fast nicht mehr merkt — so daß man trotzdem alles machen kann. (kann mich tatsächlich noch erinnern, jetzt wo ich das sehe, daß ich damals eifrig darauf bedacht war, so zu sein; diese Haltung hatte ich vor allem vor 2012 — das hat sich dann unmerklich verflüchtigt)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...das wäre durchaus plausibel.
+
+
+ Seinerzeit ging ich davon aus, daß die Render-Engine von Christian geschrieben wird, und deshalb mit void* arbeiten wird — also war ein typisiertes Overlay etwas, was ich gedanklich immer noch schamvoll verborgen habe, etwas für »Weicheier«. Die Auseinandersetzung mit der Historie des Projekts (letzten Herbst 2025) hat mir gezeigt, daß ich damals tatsächlich vom Bewußtsein her weit hinter dem realen Zustand war. Effektiv war Christian bereits raus aus dem Projekt. Bei Meetings war er allerdings immer noch sehr dominant, und ich habe ihn giftig attackiert. In 2010/11 hat er Benny ins Projekt gebracht. Tatsächlich hat Christian 2012 die letzten Anläufe gestartet, seine Kern-Ideen zur Projektorganisation in Lumiera zu verankern (an der Implementierung hatte er schon längst jedwedes Interesse verloren, wenn er jemals daran eines gehabt hatte; anfangs wollte er vor allem sein C-Framework realisieren ... und da stand ich im Weg).
+
+
+ Was ich aber auch jetzt erst realisiert habe: der Umstand, daß ich die ganzen Jahre dermaßen »auf dem Schlauch gestanden« bin war entscheidend dafür, daß Lumiera zu dem wurde, was es heute ist.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Um die Sache nochmal von der anderen Seite her zu durchdenken, jenseits der Ressentiments....
+
+
+ Wenn man sich auf den Standpunkt stellt, daß »Buffer« eine feste Struktur sind, die „eh da ist“ — und man sich dann vorstellt, innerhalb von diesem Rahmen so ad-hoc zu arbeiten, dann ist es nicht abwegig, einen smart-ptr sich vorzustellen, mit dem man das macht. Der Punkt ist: das ist eine Vorstellung wie man arbeiten könnte! Die richtige Frage wäre also, warum sollte ich mir vorstellen, so arbeiten zu wollen?
+
+
+ Antwort: wenn ich mich im Rahmen einer fest gefügten Ontologie bewege, die in Buffern, Allokationen und Pointern ausgedrückt wird. Dann ist es tatsächlich sinnvoll, sich Handwerkszeug zu schaffen, um in diesem starren Rahmen trotzdem flexible Dinge machen zu können.
+
+
+
+
+
+
+
+
+
+ Ich habe mich darzu durchgerungen, auf eine übergreifende minimal-Ontologie zu verzichten. Um es noch genauer zu sagen: es gibt sie weiterhin, aber sie ist reduziert auf das »Verarbeiten« im Sinne von „Anwenden einer Funktion (opaque) auf Daten (opaque)“, also eine Assoziation zwischen zwei Klassen von IDs (Funktionen und Datentypen). Dem entsprechend ist man nun immer in der Lage, sich nach Bedarf eine Funktion zu schaffen.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ auf dieser Ebene wäre das nämlich leicht zu realisieren, und würde nahtlos ins Protokoll passen: man würde lediglich erlauben, den spezialisierteren Type-Handler auch noch in einem späteren Schritt anzuhängen. Das überschneidet sich zwar formell mit der Möglichkeit, eine Anzahl Buffer anzukündigen (»announce«), was aber praktisch irrelevant ist (da ein spezialisierterer Typehandler nicht die Größe des Speichers ändert)
+
+
+
+
+
+
+
+
+
+ In der aktuellen Form — mit einer ganz knapp definierten Funktionalität in der Engine, kann dieser Fall niemals auftreten: es ist nämlich nun so, daß Client-Code niemals einen Buffer-Descriptor in die Hand bekommt. Vielmehr muß stets im Vorraus bereits festgelegt sein, welche Operationen in der Engine überhaupt auftreten können; in diesem Punkt bin ich viel radikaler geworden; selbst der Effekt von Automation oder von Mute-Schaltern muß vorgeplant werden
+
+
+
+
+
+
+
+
+
+ Ich betone viel mehr den Einzelfall, und bin immer skeptischer geworden gegenüber der universellen Lösung; Pattern greifen ineinander und es muß nicht ein Pattern alles lösen; wenn also die Engine einmal etwas gänzlich anderes machen soll, dann baut man eben eine gänzlich andere Engine.
+
+
+
+
+
+
+
+
+
+ Auch Optionalität drückt man heute als Typ aus, und nicht mehr als dynamisches Verhalten. Will damit sagen, wenn man es kann.
+
+
+ Ich hab inzwischen gelernt, selbst unter beschränktem, vorher festgelegtem Speicher einen Varianten-Typ darzustellen; auch die Frage ob Destruktoren aufgerufen werden, läßt sich als Teil des Typ(Kontrakts) verstehen. Das ist doch die Stärke der Objektorientierung, daß man Verhaltensmuster in den Typ hineinnehmen kann. Ein Container kann z.B. uninitialised Storage bieten, und dann sich bei Bedarf dorch um eingepflanze Objekte automatisch kümmern. So etwas muß nicht mehr das globale Framework machen. Aus dieser Perspektive heraus lehne ich ja auch »Garbage-collection« ab, und sage, werdet euch mal klar, was ihr wollt!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bedingt durch den Umstand, daß mir das Thema irgendwo über die Implementierungs-Iterationen halb entglitten ist (und dann liegenblieb), habe ich den den DiagnosticBufferProvider weiterentwickelt und vergessen, daß der zugehörige DiagnosticBufferProvider_test eben nicht das Diagnose-Interface verwendet, sondern daran vorbei auf den »TrackingHeapBlockProvider« (wie er damals hieß) durchgreift. Daher gibt es nun zwei halbgare Testframeworks, die sich überlappen und dabei teilweise widersprechen. Heureka!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -111959,6 +112336,66 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+ danach folgt das »eigentliche« Aufräumen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...und das beruht auf einem Hash-Lookup (riskant!)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -111974,6 +112411,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
@@ -112051,6 +112489,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
@@ -112086,9 +112525,20 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+
+
+
+
+
+
@@ -116834,7 +117284,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -129384,7 +129834,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -129426,7 +129876,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -129462,7 +129912,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -131580,6 +132030,29 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -131873,6 +132346,26 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+
+
+
+
+
+ Erfahrungen
+
+
+ aus dem
+
+
+ Prototyping
+
+
+
+
+
+
+
+
@@ -131987,7 +132480,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
-
+
@@ -154117,7 +154610,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
+
@@ -154340,7 +154833,7 @@ std::cout << tmpl.render({"what", "World"}) << s
-
+
@@ -158858,55 +159351,43 @@ std::cout << tmpl.render({"what", "World"}) << s
-
-
-
+
Gilt stets auch für andere Objekt-Instanzen des gleichen Typs. Gilt auch für nested Classes, und member functions, und nested Classes in member functions; wobei allerdings, die Instanz muß man explizit in der Hand haben (es gibt hier keine solche »magic« wie in Java, wo eine non-static nested class automatisch auch einen outer.this-ptr bekommt)
-
-
+
-
-
-
+
konzeptionell: das ist ein separates API für abgeleitete Klassen
-
-
+
-
-
-
+
Man muß unterscheiden zwischen Deklarationen und dem Zugang zu konkreten Members. Deklarationen sieht jede abgeleitete Klasse. Aber auf protected Members in einer Basisklasse zugreifen kann man nur durch eine Instanz einer abgeleiteten Klasse; und zwar muß der Typ dieser Instanz gleich (oder abgeleitet) sein wie der Typ, aus dem heraus der Code zugreift. Konkret: auf base.member kann ich nur durch eine derived& zugreifen (das schließt *this ein). Aber nicht durch irgend ein anderes Objekt oder eine base&
-
-
+
-
-
-
+
Ohne diese Regel wären wilde Kreuz-Zugriffe auf komplett andere Vererbungslinien möglich; man bedenke im Besonderen, daß die Situation durch Mehrfachvererbung ziemlich komplex sein kann; zudem kann eine andere abgeleitete Klasse die Basis auf komplexe Weise instrumentiert haben, und ein solcher Kreuz-Zugriff könnte das alles unterlaufen. Es ist ja ohnehin ein Zugeständnis, daß man auf was anderes als *this überhaupt zugreifen darf.
-
-
+
@@ -164012,6 +164493,12 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
+
+
+
+
+
+
@@ -164495,7 +164982,7 @@ unsigned int ThreadIdAsInt = *static_cast<unsigned int*>(static_cast<vo
-
+