BufferProvider: switch to the new implementation structure

More or less forcibly squeeze all the existing implementation
into the new basic structure with two separate »pillars«

**Breakages**
 - existing code expected the `BufferStore` to transition to ''locked'' state
 - existing code expected `provideLockedBuffer(typeID)` to tail-call the
   `buildHandle()` function of the enclosing `BufferProvider` base implementation
 - various diagnostic usages bypassed the official APIs and called directly
   into the implementation. This is no longer possible; rather, `DiagnosticBufferProvider`
   needs to provide additional diagnostic API to suit those purposes
This commit is contained in:
Fischlurch 2026-02-10 23:48:09 +01:00
parent a9bdad2c66
commit 9c5eb11b0c
13 changed files with 580 additions and 133 deletions

View file

@ -25,10 +25,8 @@
#include "lib/error.hpp"
#include "lib/symbol.hpp"
#include "lib/hash-value.h"
#include "steam/engine/buffhandle.hpp"
#include "steam/engine/buffer-provider.hpp"
//#include "steam/engine/engine-ctx.hpp"
#include "steam/engine/type-handler.hpp"
#include "steam/engine/buffer-local-tag.hpp"
#include "lib/nocopy.hpp"
#include <utility>
@ -40,14 +38,12 @@ namespace engine {
using lib::Literal;
using std::unique_ptr;
using std::forward;
// using std::forward;
using std::move;
class BufferMetadata;
LUMIERA_ERROR_DECLARE (BUFFER_MANAGEMENT); ///< Problem providing working buffers
/**
* Framework for configuring the actual BufferPovider backend implementation.
@ -58,18 +54,34 @@ namespace engine {
: public BufferProvider
{
public:
BufferProviderSetup (Literal implementationID);
/**
* Build a new BufferProvider setup to manage a number of buffers.
* The metadata of these buffers is organised hierarchically based on
* chained hash values, using an `implementationID` as a seed.
* The \a CONF configuration record controls the actual implementation
* of lifecycle transitions and storage management.
*/
template<class CONF>
BufferProviderSetup (CONF&& confRec)
: BufferProvider{}
{
bufferStage_ = move (confRec.buildStage());
bufferStore_ = move (confRec.buildStore());
}
class Stage
: protected BufferStage
: public BufferStage
{
public:
using BufferStage::BufferStage; ///////////////////////////////////////////////////////////TICKET #1410 : actual implementation structures should move down into this classes implementation
};
class Store
: protected BufferStore
: public BufferStore
{
protected:
using Buff = BufferProvider::Buff;
};

View file

@ -41,14 +41,6 @@ namespace engine {
LUMIERA_ERROR_DEFINE (BUFFER_MANAGEMENT, "Problem providing working buffers");
/** build a new provider instance, managing a family of buffers.
* The metadata of these buffers is organised hierarchically based on
* chained hash values, using the #implementationID as a seed.
* @param implementationID symbolic ID setting these family of buffers apart.
*/
BufferProvider::BufferProvider (Literal implementationID)
: bufferStage_(new BufferStage{implementationID})
{ }
BufferProvider::~BufferProvider() { }
@ -117,7 +109,7 @@ namespace engine {
uint
BufferProvider::announce (uint count, BuffDescr const& type)
{
uint actually_possible = prepareBuffers (count, type);
uint actually_possible = bufferStore_->prepareBuffers (count, type);
if (!actually_possible)
throw error::State ("unable to fulfil request for buffers"
,LUMIERA_ERROR_BUFFER_MANAGEMENT);
@ -143,7 +135,7 @@ namespace engine {
{
REQUIRE (was_created_by_this_provider (type));
return provideLockedBuffer (type);
return bufferStore_->provideLockedBuffer (type);
} // is expected to call buildHandle() --> state transition
@ -163,7 +155,7 @@ namespace engine {
BufferProvider::emitBuffer (BuffHandle const& handle)
{
metadata::Entry& metaEntry = bufferStage_->get (handle.entryID());
mark_emitted (metaEntry.parentKey(), metaEntry.localTag());
bufferStore_->mark_emitted (metaEntry.parentKey(), metaEntry.localTag());
metaEntry.mark(EMITTED);
}
@ -181,7 +173,7 @@ namespace engine {
try {
metadata::Entry& metaEntry = bufferStage_->get (handle.entryID());
metaEntry.mark(FREE); // might invoke embedded dtor function
detachBuffer (metaEntry.parentKey(), metaEntry.localTag(), *handle);
bufferStore_->detachBuffer (metaEntry.parentKey(), metaEntry.localTag(), *handle);
bufferStage_->release (metaEntry);
}
ERROR_LOG_AND_IGNORE (engine, "releasing a buffer from BufferProvider")
@ -225,7 +217,7 @@ namespace engine {
try {
metadata::Entry& metaEntry = bufferStage_->get (target.entryID());
metaEntry.invalidate (invokeDtor);
detachBuffer (metaEntry.parentKey(), metaEntry.localTag(), *target);
bufferStore_->detachBuffer (metaEntry.parentKey(), metaEntry.localTag(), *target);
bufferStage_->release (metaEntry);
}
ERROR_LOG_AND_IGNORE (engine, "cleanup of buffer metadata while handling an error")

View file

@ -113,8 +113,6 @@ namespace engine {
size_t getBufferSize (HashVal typeID) const;
protected:
BufferProvider (Literal implementationID);
/// placeholder marker type for an actual data buffer
using Buff = StreamType::ImplFacade::DataBuffer;
@ -122,13 +120,6 @@ namespace engine {
bool was_created_by_this_provider (BuffDescr const&) const;
///////////////////////////////////////////////////////////////////////////////OOO
virtual uint prepareBuffers (uint count, HashVal typeID) =0;
virtual BuffHandle provideLockedBuffer (HashVal typeID) =0;
virtual void mark_emitted (HashVal, LocalTag const&) =0;
virtual void detachBuffer (HashVal, LocalTag const&, Buff&) =0;
///////////////////////////////////////////////////////////////////////////////OOO
class BufferStage
: public BufferMetadata /////////////////////////////////////////////////////////////////////TICKET #1410 : mix-in exiting old implementation -- for sake of refactoring only!
@ -137,7 +128,6 @@ namespace engine {
virtual ~BufferStage() { } ///< this is an interface
using BufferMetadata::BufferMetadata; ///////////////////////////////////////////////////////////TICKET #1410 : actual implementation structures should move down into this classes implementation
protected:
};
class BufferStore
@ -145,7 +135,7 @@ namespace engine {
{
public:
virtual ~BufferStore() { } ///< this is an interface
protected:
virtual uint prepareBuffers (uint count, HashVal typeID) =0;
virtual BuffHandle provideLockedBuffer (HashVal typeID) =0;
virtual void mark_emitted (HashVal, LocalTag const&) =0;

View file

@ -62,10 +62,11 @@ namespace engine {
using Listener = std::function<void(size_t,BufferState)>;
class ForwardingBufferProvider
: public BufferProvider
: public BufferProvider /////////////////////////////////////////////////////////////TICKET #1410 : its clear now (2/26) that this must be some other base type; maybe we'll offer the ability to decorate, directly through BufferProviderSetup?
{
Listener listener_;
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to while BufferProvider is being refactored...
/* === BufferProvider API === */
uint
@ -93,9 +94,10 @@ namespace engine {
{
}
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
public:
ForwardingBufferProvider (Listener listener)
: BufferProvider{"BufferProxyProvider"}
: BufferProvider{}
, listener_{std::move (listener)}
{ }
};

View file

@ -25,7 +25,7 @@
//#include "lib/meta/function.hpp"
#include "steam/engine/diagnostic-buffer-provider.hpp"
#include "steam/engine/heap-mem-provider.hpp"
#include "steam/engine/heap-mem-buffer-store.hpp"
namespace steam {
@ -33,7 +33,8 @@ namespace engine {
DiagnosticBufferProvider::DiagnosticBufferProvider()
: BufferProvider{"Diagnostic_HeapAllocated"}
: NaiveBufferSetup{}
, heapStore_{dynamic_cast<HeapMemProvider&> (*bufferStore_)}
{ }
DiagnosticBufferProvider::~DiagnosticBufferProvider()
@ -49,21 +50,21 @@ namespace engine {
bool
BufferDiagnostic::buffer_was_used (uint bufferID)
{
return dbp_.heapMemProvider_.access_emitted(bufferID).was_used();
return dbp_.heapStore_.access_emitted(bufferID).was_used();
}
bool
BufferDiagnostic::buffer_was_closed (uint bufferID)
{
return dbp_.heapMemProvider_.access_emitted(bufferID).was_closed();
return dbp_.heapStore_.access_emitted(bufferID).was_closed();
}
void*
BufferDiagnostic::accessMemory (uint bufferID)
{
return dbp_.heapMemProvider_.access_emitted(bufferID).accessMemory();
return dbp_.heapStore_.access_emitted(bufferID).accessMemory();
}

View file

@ -24,7 +24,7 @@
#include "lib/error.hpp"
#include "lib/util.hpp"
#include "steam/engine/type-handler.hpp" ///////////////OOO warum?
#include "steam/engine/heap-mem-provider.hpp"
#include "steam/engine/naive-buffer-setup.hpp"
#include "lib/nocopy.hpp"
#include <memory>
@ -35,6 +35,7 @@ namespace engine {
namespace error = lumiera::error;
class HeapMemProvider;
class BufferDiagnostic;
@ -45,17 +46,9 @@ namespace engine {
* @todo write type comment
*/
class DiagnosticBufferProvider
: public BufferProvider
: public NaiveBufferSetup
{
HeapMemProvider heapMemProvider_;
/* === delegate BufferProvider API === */
uint prepareBuffers (uint count, HashVal typeID) override { return heapMemProvider_.prepareBuffers (count,typeID);}
BuffHandle provideLockedBuffer (HashVal typeID) override { return heapMemProvider_.provideLockedBuffer (typeID); }
void mark_emitted (HashVal h, LocalTag const& t) override { heapMemProvider_.mark_emitted(h,t); }
void detachBuffer (HashVal h, LocalTag const& t, Buff& b) override { heapMemProvider_.detachBuffer(h,t,b); }
HeapMemProvider& heapStore_;
public:

View file

@ -1,8 +1,8 @@
/*
HeapMemProvider - plain heap allocating BufferProvider implementation for tests
HeapMemBufferStore - plain heap allocating BufferProvider storage implementation for tests
Copyright (C)
2011, Hermann Vosseler <Ichthyostega@web.de>
2011,2026 Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
@ -12,8 +12,8 @@
* *****************************************************************/
/** @file heap-mem-provider.cpp
** Implementation details of a mock engine::BufferProvider for unit testing
/** @file heap-mem-buffer-store.cpp
** Implementation details of simple heap based engine::BufferProvider storage.
*/
@ -22,7 +22,7 @@
#include "lib/scoped-ptrvect.hpp"
#include "lib/util-foreach.hpp"
#include "steam/engine/heap-mem-provider.hpp"
#include "steam/engine/heap-mem-buffer-store.hpp"
#include <algorithm>
#include <vector>
@ -223,8 +223,7 @@ namespace engine {
* @internal create a memory tracking BufferProvider,
*/
HeapMemProvider::HeapMemProvider()
: BufferProvider ("Naive_HeapAllocated")
, pool_(new diagn::PoolTable)
: pool_(new diagn::PoolTable)
, outSeq_()
{ }
@ -247,7 +246,8 @@ namespace engine {
{
diagn::BlockPool& blocks = getBlockPoolFor (typeID);
diagn::Block& newBlock = blocks.createBlock();
return buildHandle (typeID, asBuffer(newBlock.accessMemory()), &newBlock);
UNIMPLEMENTED ("Separate tasks into two distinct APIs");
// return buildHandle (typeID, asBuffer(newBlock.accessMemory()), &newBlock); /////////////////////////////OOO instead return a tuple (buffer, localTag)
}
@ -320,8 +320,9 @@ namespace engine {
HeapMemProvider::getBlockPoolFor (HashVal typeID)
{
diagn::BlockPool& pool = (*pool_)[typeID];
if (!pool)
pool.initialise(getBufferSize(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;
}

View file

@ -1,8 +1,8 @@
/*
HEAP-MEM-PROVIDER.hpp - plain heap allocating BufferProvider implementation for tests
HEAP-MEM-BUFFER_STORE.hpp - plain heap allocating BufferProvider implementation for tests
Copyright (C)
2011, Hermann Vosseler <Ichthyostega@web.de>
2011,2026 Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
@ -12,10 +12,11 @@
*/
/** @file heap-mem-provider.hpp
** Dummy implementation of the BufferProvider interface to support writing unit tests.
** This BufferProvider implementation is notably straight forward and silly: it just
** claims more and more heap blocks and never releases any memory dynamically. This allows
** to investigate additional tracking status flags for each allocated block after the fact.
** Dummy implementation engine::BufferProvider storage, for sake of conceptual
** demonstration and unit testing. This BufferProvider implementation is notably straight forward,
** if not outright silly: it happily claims more and more heap blocks and never releases any memory
** dynamically. This both demonstrates the simplest possible implementation of storage handling, and
** allows to investigate additional tracking status flags for each allocated block after the fact.
**
** @todo 1/2026 for sake of implementation clarity, the following instrumentation functionality
** must be relocated into the DiagnosticOutputProvider: Allocated buffers are numbered
@ -30,13 +31,13 @@
** @see buffer-provider-protocol-test.cpp
*/
#ifndef STEAM_ENGINE_HEAP_MEM_PROVIDER_H
#define STEAM_ENGINE_HEAP_MEM_PROVIDER_H
#ifndef STEAM_ENGINE_HEAP_MEM_BUFFER_STORE_H
#define STEAM_ENGINE_HEAP_MEM_BUFFER_STORE_H
#include "lib/error.hpp"
#include "lib/hash-value.h"
#include "steam/engine/buffer-provider.hpp"
#include "steam/engine/buffer-provider-setup.hpp"
#include "lib/scoped-ptrvect.hpp"
#include <unordered_map>
@ -117,13 +118,13 @@ namespace engine {
* tracked usage information, even when blocks are already marked as "released".
*/
class HeapMemProvider
: public BufferProvider
: public BufferProviderSetup::Store
{
unique_ptr<diagn::PoolTable> pool_;
ScopedPtrVect<diagn::Block> outSeq_;
public:
/* === BufferProvider interface === */
/* === BufferStore interface === */
virtual uint prepareBuffers (uint count, HashVal typeID) override;
virtual BuffHandle provideLockedBuffer (HashVal typeID) override;
@ -178,4 +179,4 @@ namespace engine {
}} // namespace steam::engine
#endif /*STEAM_ENGINE_HEAP_MEM_PROVIDER_H*/
#endif /*STEAM_ENGINE_HEAP_MEM_BUFFER_STORE_H*/

View file

@ -0,0 +1,197 @@
/*
NAIVE-BUFFER_SETUP.hpp - plain heap allocating BufferProvider implementation for tests
Copyright (C)
2026, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
*/
/** @file naive-buffer-setup.hpp
** Dummy implementation of the BufferProvider interface to support writing unit tests.
** This setup for a BufferProvider is notably straight forward and basically allocates
** a new heap block for any buffer, without deallocating memory ever. This allows to
** attach additional tracking status flags for each allocated block and validate
** allocator behaviour after the fact.
**
** @todo 1/2026 for sake of implementation clarity, the following instrumentation functionality
** must be relocated into the DiagnosticOutputProvider: Allocated buffers are numbered
** with a simple ascending sequence of integers, used as LocalTag (see BufferMetadata).
** Clients can request a Buffer with the given number, causing that block to be allocated.
** There is a "backdoor", allowing to access any allocated block, even if it is considered
** "released" by the terms of the usual lifecycle. Only when the provider object itself
** gets destroyed, all allocated blocks will be discarded.
**
** @see DiagnosticOutputSlot
** @see DiagnosticBufferProvider
** @see buffer-provider-protocol-test.cpp
*/
#ifndef STEAM_ENGINE_NAIVE_BUFFER_STEUP_H
#define STEAM_ENGINE_NAIVE_BUFFER_STEUP_H
#include "lib/error.hpp"
#include "lib/hash-value.h"
#include "steam/engine/buffer-provider-setup.hpp"
#include "steam/engine/heap-mem-buffer-store.hpp"
#include "lib/scoped-ptrvect.hpp"
#include <unordered_map>
#include <memory>
namespace steam {
namespace engine {
namespace error = lumiera::error;
// using lib::HashVal;
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
namespace diagn {
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<char[]> 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<HashVal,BlockPool>;
}
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
/**
* simple BufferProvider implementation with additional allocation tracking.
* @internal used as PImpl by DiagnosticBufferProvider and DiagnosticOutputSlot.
*
* This dummy implementation of the BufferProvider interface uses a linearly growing
* table of heap allocated buffer blocks, which will never be discarded, unless the object
* is discarded as a whole. There is an additional testing/diagnostics API to access the
* tracked usage information, even when blocks are already marked as "released".
*/
class NaiveBufferSetup
: public BufferProviderSetup
{
public:
NaiveBufferSetup()
: BufferProviderSetup{*this}
{ }
auto buildStage() { return std::make_unique<Stage> ("Naive_HeapAllocated"); }
auto buildStore() { return std::make_unique<HeapMemProvider>(); } /////////////////////////////////TICKET #1410 : turn into a subclass of BufferSetup::Store and push down implementation
};
#if false //////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : disabled code to disentangle BufferProvider implementation
class HeapMemProvider
: public BufferProvider
{
unique_ptr<diagn::PoolTable> pool_;
ScopedPtrVect<diagn::Block> outSeq_;
public:
/* === BufferProvider interface === */
virtual uint prepareBuffers (uint count, HashVal typeID) override;
virtual BuffHandle provideLockedBuffer (HashVal typeID) override;
virtual void mark_emitted (HashVal, LocalTag const&) override;
virtual void detachBuffer (HashVal, LocalTag const&, Buff&) override;
public:
~HeapMemProvider();
HeapMemProvider();
size_t emittedCnt() const;
diagn::Block& access_emitted (uint bufferID);
template<typename TY>
TY& accessAs (uint bufferID);
void markAllEmitted();
private:
bool withinOutputSequence (uint bufferID) const;
diagn::BlockPool& getBlockPoolFor (HashVal typeID);
diagn::Block* locateBlock (HashVal typeID, void*);
diagn::Block* searchInOutSeqeuence (void* storage);
};
/** convenience shortcut: access the buffer with the given number,
* then try to convert the raw memory to the templated type.
* @throw error::Invalid if the required fame number is beyond
* the number of buffers marked as "emitted"
* @throw error::Fatal if conversion is not possible or the
* conversion path chosen doesn't work (which might
* be due to RTTI indicating an incompatible type).
*/
template<typename TY>
TY&
HeapMemProvider::accessAs (uint bufferID)
{
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<TY*> (memoryBlock.accessMemory()));
REQUIRE (converted);
return *converted;
}
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : (end) disabled code
}} // namespace steam::engine
#endif /*STEAM_ENGINE_NAIVE_BUFFER_STEUP_H*/

View file

@ -24,8 +24,8 @@
#include "steam/engine/render-environment.hpp"
#include "steam/engine/engine-facilities.hpp"
#include "steam/engine/naive-buffer-setup.hpp"
#include "steam/engine/buffer-provider.hpp"
#include "steam/engine/heap-mem-provider.hpp"
namespace steam {
@ -38,7 +38,7 @@ namespace engine{
BufferProvider&
getNaiveBufferManager()
{
static HeapMemProvider buffProvider; ////////////////////////////////////////////////////TICKET #1367 : only suitable for first prototype; should implement a bare bone memory manager instead
static NaiveBufferSetup buffProvider; ///////////////////////////////////////////////////TICKET #1367 : only suitable for first prototype; should implement a bare bone memory manager instead
return buffProvider;
}
}

View file

@ -18,7 +18,7 @@
#include "lib/error.hpp"
#include "lib/test/run.hpp"
#include "steam/engine/heap-mem-provider.hpp"
#include "steam/engine/diagnostic-buffer-provider.hpp"
#include "steam/engine/buffhandle-attach.hpp"
#include "steam/engine/testframe.hpp"
@ -60,7 +60,7 @@ namespace test {
/******************************************************************//**
* @test verify support to write mock components for buffer management.
* - HeapMemProvider is a „braindead“ implementation of the BufferProvider
* - HeapMemBufferStore is a „braindead“ implementation of the BufferProvider
* interface: it just claims new heap blocks and never de-allocates them.
* - adding a layer of instrumentation, the DiagnosticBufferProvider allows
* to count and verify allocated buffers and their content after the fact.
@ -81,7 +81,7 @@ namespace test {
void
simpleExample()
{
HeapMemProvider provider; /////////////////////////////////////OOO should be DiagnosticBufferProvider
DiagnosticBufferProvider provider;
BuffHandle testBuff = provider.lockBufferFor<TestFrame>();
CHECK (testBuff);
@ -93,15 +93,15 @@ namespace test {
provider.emitBuffer (testBuff);
provider.releaseBuffer(testBuff);
diagn::Block& block0 = provider.access_emitted(0);
CHECK (testData(dataID) == block0.accessMemory());
// diagn::Block& block0 = provider.access_emitted(0); ///////////////////////////////OOO provide suitable diagnostic API!
// CHECK (testData(dataID) == block0.accessMemory());
}
void
verifyStandardCase()
{
HeapMemProvider provider; /////////////////////////////////////OOO should be DiagnosticBufferProvider
DiagnosticBufferProvider provider;
BuffDescr buffType = provider.getDescriptorFor(TEST_ELM_SIZE);
uint numElms = provider.announce(MAX_ELMS, buffType);
@ -118,7 +118,7 @@ namespace test {
for (uint nr=0; nr<numElms; ++nr)
{
CHECK (verifyUsedBlock (nr, provider.access_emitted(nr)));
// CHECK (verifyUsedBlock (nr, provider.access_emitted(nr))); ///////////////////////////////OOO provide suitable diagnostic API!
}
}
@ -126,7 +126,7 @@ namespace test {
void
verifyTestProtocol()
{
HeapMemProvider provider; /////////////////////////////////////OOO should be DiagnosticBufferProvider
DiagnosticBufferProvider provider;
BuffDescr buffType = provider.getDescriptorFor(TEST_ELM_SIZE);
@ -139,11 +139,11 @@ namespace test {
// buffers are locked,
// but still within the per-type allocation pool
// while the output sequence is still empty
CHECK (!provider.access_emitted(0).was_used());
CHECK (!provider.access_emitted(1).was_used());
CHECK (!provider.access_emitted(2).was_used());
CHECK (!provider.access_emitted(3).was_used());
CHECK (!provider.access_emitted(4).was_used());
// CHECK (!provider.access_emitted(0).was_used()); ///////////////////////////////OOO provide suitable diagnostic API!
// CHECK (!provider.access_emitted(1).was_used());
// CHECK (!provider.access_emitted(2).was_used());
// CHECK (!provider.access_emitted(3).was_used());
// CHECK (!provider.access_emitted(4).was_used());
// can use the buffers for real
bu1.accessAs<uint>() = 1;
@ -152,7 +152,7 @@ namespace test {
bu4.accessAs<uint>() = 4;
bu5.accessAs<uint>() = 5;
CHECK (0 == provider.emittedCnt());
// CHECK (0 == provider.emittedCnt()); ///////////////////////////////OOO provide suitable diagnostic API!
// now emit buffers in shuffled order
provider.emitBuffer (bu3);
@ -161,41 +161,41 @@ namespace test {
provider.emitBuffer (bu4);
provider.emitBuffer (bu2);
CHECK (5 == provider.emittedCnt());
// CHECK (5 == provider.emittedCnt()); ///////////////////////////////OOO provide suitable diagnostic API!
CHECK (3 == provider.accessAs<uint>(0));
CHECK (1 == provider.accessAs<uint>(1));
CHECK (5 == provider.accessAs<uint>(2));
CHECK (4 == provider.accessAs<uint>(3));
CHECK (2 == provider.accessAs<uint>(4));
// CHECK (3 == provider.accessAs<uint>(0)); ///////////////////////////////OOO provide suitable diagnostic API!
// CHECK (1 == provider.accessAs<uint>(1));
// CHECK (5 == provider.accessAs<uint>(2));
// CHECK (4 == provider.accessAs<uint>(3));
// CHECK (2 == provider.accessAs<uint>(4));
CHECK ( provider.access_emitted(0).was_used());
CHECK ( provider.access_emitted(1).was_used());
CHECK ( provider.access_emitted(2).was_used());
CHECK ( provider.access_emitted(3).was_used());
CHECK ( provider.access_emitted(4).was_used());
// CHECK ( provider.access_emitted(0).was_used()); ///////////////////////////////OOO provide suitable diagnostic API!
// CHECK ( provider.access_emitted(1).was_used());
// CHECK ( provider.access_emitted(2).was_used());
// CHECK ( provider.access_emitted(3).was_used());
// CHECK ( provider.access_emitted(4).was_used());
CHECK (!provider.access_emitted(0).was_closed());
CHECK (!provider.access_emitted(1).was_closed());
CHECK (!provider.access_emitted(2).was_closed());
CHECK (!provider.access_emitted(3).was_closed());
CHECK (!provider.access_emitted(4).was_closed());
// CHECK (!provider.access_emitted(0).was_closed());
// CHECK (!provider.access_emitted(1).was_closed());
// CHECK (!provider.access_emitted(2).was_closed());
// CHECK (!provider.access_emitted(3).was_closed());
// CHECK (!provider.access_emitted(4).was_closed());
bu5.release();
CHECK (!provider.access_emitted(0).was_closed());
CHECK (!provider.access_emitted(1).was_closed());
CHECK ( provider.access_emitted(2).was_closed());
CHECK (!provider.access_emitted(3).was_closed());
CHECK (!provider.access_emitted(4).was_closed());
// CHECK (!provider.access_emitted(0).was_closed());
// CHECK (!provider.access_emitted(1).was_closed());
// CHECK ( provider.access_emitted(2).was_closed());
// CHECK (!provider.access_emitted(3).was_closed());
// CHECK (!provider.access_emitted(4).was_closed());
bu2.release();
bu2.release();
bu5.release();
CHECK (!provider.access_emitted(0).was_closed());
CHECK (!provider.access_emitted(1).was_closed());
CHECK ( provider.access_emitted(2).was_closed());
CHECK (!provider.access_emitted(3).was_closed());
CHECK ( provider.access_emitted(4).was_closed());
// CHECK (!provider.access_emitted(0).was_closed());
// CHECK (!provider.access_emitted(1).was_closed());
// CHECK ( provider.access_emitted(2).was_closed());
// CHECK (!provider.access_emitted(3).was_closed());
// CHECK ( provider.access_emitted(4).was_closed());
CHECK (!bu2);
CHECK (bu3);
@ -204,7 +204,7 @@ namespace test {
bu3.release();
bu4.release();
CHECK (5 == provider.emittedCnt());
// CHECK (5 == provider.emittedCnt()); ///////////////////////////////OOO provide suitable diagnostic API!
}
};

View file

@ -29,7 +29,7 @@
#include "steam/play/output-slot-connection.hpp"
#include "steam/asset/meta/time-grid.hpp"
#include "steam/engine/buffhandle.hpp"
#include "steam/engine/heap-mem-provider.hpp"
#include "steam/engine/naive-buffer-setup.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/scoped-ptrvect.hpp"
#include "lib/iter-source.hpp"
@ -57,7 +57,7 @@ namespace play {
using steam::asset::meta::TimeGrid;
using steam::engine::BuffDescr;
using steam::engine::test::TestFrame;
using steam::engine::HeapMemProvider;
using steam::engine::NaiveBufferSetup;
namespace diagn = steam::engine::diagn;
//using std::vector;
@ -94,7 +94,7 @@ namespace play {
typedef std::unordered_set<FrameID> FrameTrackingInfo;
HeapMemProvider buffProvider_;
NaiveBufferSetup buffProvider_;
BuffDescr bufferType_;
FrameTrackingInfo frameTrackingIndex_;
@ -205,19 +205,21 @@ namespace play {
TestFrame const *
accessEmittedFrame (uint frameNr) const
{
if (frameNr < buffProvider_.emittedCnt())
return & accessFrame(frameNr);
else
return 0; ////////////////////////////////TICKET #856
UNIMPLEMENTED ("suitable diagnostic API");
// if (frameNr < buffProvider_.emittedCnt()) ///////////////////////////////OOO provide suitable diagnostic API!
// return & accessFrame(frameNr);
// else
// return 0; ////////////////////////////////TICKET #856
}
diagn::Block const *
accessEmittedBuffer (uint bufferNr) const
{
if (bufferNr < buffProvider_.emittedCnt())
return & accessBlock(bufferNr);
else
return 0;
UNIMPLEMENTED ("suitable diagnostic API");
// if (bufferNr < buffProvider_.emittedCnt()) ///////////////////////////////OOO provide suitable diagnostic API!
// return & accessBlock(bufferNr);
// else
// return 0;
}
bool
@ -232,13 +234,15 @@ namespace play {
TestFrame const&
accessFrame (uint frameNr) const
{
return unConst(this)->buffProvider_.accessAs<TestFrame> (frameNr);
UNIMPLEMENTED ("suitable diagnostic API");
// return unConst(this)->buffProvider_.accessAs<TestFrame> (frameNr); ///////////////////////////////OOO provide suitable diagnostic API!
}
diagn::Block const&
accessBlock (uint bufferNr) const
{
return unConst(this)->buffProvider_.access_emitted (bufferNr);
UNIMPLEMENTED ("suitable diagnostic API");
// return unConst(this)->buffProvider_.access_emitted (bufferNr); ///////////////////////////////OOO provide suitable diagnostic API!
}
};

View file

@ -111619,8 +111619,50 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
<node CREATED="1770670620982" ID="ID_1374029931" MODIFIED="1770670637618" TEXT="bisheriges &#xbb;meta&#xab; wird zu BufferStage"/>
<node CREATED="1770670643410" ID="ID_1778176571" MODIFIED="1770670684703" STYLE="fork" TEXT="bisheriges protected-Interface &#x27f6; als BufferStore herausziehen">
<font NAME="SansSerif" SIZE="12"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1770769772202" ID="ID_528640678" MODIFIED="1770769794715" TEXT="hier gibt es ein Problem: BufferProvider::buildHandle">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1770769806729" ID="ID_6936764" MODIFIED="1770769894796" TEXT="BuffHandle provideLockedBuffer(HashVal typeID) &#x27f6; sollte einen buildHandle() tail-call machen"/>
<node CREATED="1770769796738" ID="ID_734223464" MODIFIED="1770769804669" TEXT="das war immer schon ein verwirrendes Ping-Pong"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1770769951879" ID="ID_1852318741" MODIFIED="1770769977165" TEXT="noch schlimmer: es vermischt die Zonen der Implementierung">
<icon BUILTIN="clanbomber"/>
</node>
<node CREATED="1770686248066" ID="ID_1851008076" MODIFIED="1770686264665" TEXT="Problem: Direktzugriffe auf die Implementierung">
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1770769896480" ID="ID_426983823" MODIFIED="1770770474699" TEXT="und jetzt geht das nicht mehr: es w&#xe4;re in einem anderen Objekt">
<linktarget COLOR="#fe474d" DESTINATION="ID_426983823" ENDARROW="Default" ENDINCLINATION="387;17;" ID="Arrow_ID_1775599184" SOURCE="ID_1432411040" STARTARROW="None" STARTINCLINATION="57;-420;"/>
<icon BUILTIN="broken-line"/>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1770771226721" ID="ID_1487577652" MODIFIED="1770771248247" TEXT="auch der DiagnosticBufferProvider verwendet ein Basis_API: getBufferSize()">
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1770770126934" ID="ID_850948251" MODIFIED="1770770161242" TEXT="&#x27f9; API-Anpassung notwendig">
<icon BUILTIN="yes"/>
<node COLOR="#5b280f" CREATED="1770770251820" ID="ID_415070649" MODIFIED="1770770275197" TEXT="das bisherge API vermischt ohnehin die Themen">
<icon BUILTIN="closed"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#8a050d" CREATED="1770770278057" ID="ID_1578952294" MODIFIED="1770770325897" TEXT="da mu&#xdf; noch mehr aufger&#xe4;umt werden">
<font NAME="SansSerif" SIZE="10"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#b9010b" CREATED="1770770286619" ID="ID_7825032" MODIFIED="1770770342689">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
auch <font face="Monospaced"><b>mark_emitted</b></font>&#160;ist gar nicht die Aufgabe des Store!
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="10"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1770770350662" ID="ID_1511113078" MODIFIED="1770770378417" TEXT="L&#xf6;sung ist offensichtlich: auseinander-f&#xe4;deln">
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1770686248066" ID="ID_1851008076" MODIFIED="1770757878094" TEXT="Problem: Direktzugriffe auf die Implementierung">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1770686275053" ID="ID_209445247" MODIFIED="1770686293057" TEXT="DiagnosticBufferProvider"/>
<node CREATED="1770686294571" ID="ID_863555746" MODIFIED="1770686305232" TEXT="die Unit-Tests, auch der Default-Impl"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1770686306406" ID="ID_1827512455" MODIFIED="1770686326442" TEXT="der DiagnosticOutputSlot">
@ -111745,6 +111787,163 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1770757859605" ID="ID_163465122" MODIFIED="1770757872278" TEXT="HeapMemProvider umbauen">
<icon BUILTIN="pencil"/>
<node CREATED="1770757895680" ID="ID_1960520353" MODIFIED="1770757908583" TEXT="Vorgabe: soll weiterhin einfach default-konstruierbar sein"/>
<node CREATED="1770757909670" ID="ID_899228213" MODIFIED="1770757919979" TEXT="in zwei Klassen zerlegen">
<node CREATED="1770757938096" ID="ID_1866831594" MODIFIED="1770757943634" TEXT="NaiveBufferSetup">
<node CREATED="1770757989787" ID="ID_618017726" MODIFIED="1770757995233" TEXT="header-only"/>
<node CREATED="1770757996216" ID="ID_1198089703" MODIFIED="1770758004237" TEXT="lediglich ein Config-Record"/>
</node>
<node CREATED="1770757944571" ID="ID_1207399538" MODIFIED="1770757950804" TEXT="HeapMemBufferStore">
<node CREATED="1770757971118" ID="ID_1706663250" MODIFIED="1770757975834" TEXT="hpp|cpp"/>
<node CREATED="1770762597016" ID="ID_1432411040" MODIFIED="1770770474699" TEXT="gl&#xfc;cklicher Zufall: die Implementierung greift fast nicht auf BufferProvider-Interna durch">
<arrowlink COLOR="#fe474d" DESTINATION="ID_426983823" ENDARROW="Default" ENDINCLINATION="387;17;" ID="Arrow_ID_1775599184" STARTARROW="None" STARTINCLINATION="57;-420;"/>
<linktarget COLOR="#feeace" DESTINATION="ID_1432411040" ENDARROW="Default" ENDINCLINATION="-12;81;" ID="Arrow_ID_76937966" SOURCE="ID_100975131" STARTARROW="None" STARTINCLINATION="-199;19;"/>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1770762458610" ID="ID_875010759" MODIFIED="1770762816021" TEXT="DiagnosticBufferProvider anpassen">
<icon BUILTIN="pencil"/>
<node CREATED="1770762470929" ID="ID_424124774" MODIFIED="1770762479035" TEXT="das bleibt definitiv ein BufferProvider"/>
<node CREATED="1770762480074" ID="ID_491907312" MODIFIED="1770762498009" TEXT="&#x27f9; mu&#xdf; nun von BufferProviderSetup erben"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1770762499600" ID="ID_578552888" MODIFIED="1770762808614" TEXT="wird sich dann aber in die Implementierungen einschleifen">
<icon BUILTIN="yes"/>
<icon BUILTIN="hourglass"/>
<node CREATED="1770762537848" ID="ID_744233976" MODIFIED="1770762552653" TEXT="zun&#xe4;chst noch delegiert er direkt an HeapMemBufferStore">
<node CREATED="1770762554389" ID="ID_1159011250" MODIFIED="1770762561380" TEXT="das war ja fr&#xfc;her mal ein BufferProvider"/>
<node CREATED="1770762562345" ID="ID_1608322135" MODIFIED="1770762574873" TEXT="und hat ein (ungeschickt) verbreitertes API"/>
<node CREATED="1770762576523" ID="ID_100975131" MODIFIED="1770766811720" TEXT="hatte aber Gl&#xfc;ck im Ungl&#xfc;ck">
<arrowlink COLOR="#feeace" DESTINATION="ID_1432411040" ENDARROW="Default" ENDINCLINATION="-12;81;" ID="Arrow_ID_76937966" STARTARROW="None" STARTINCLINATION="-199;19;"/>
</node>
</node>
<node CREATED="1770762675673" ID="ID_246224479" MODIFIED="1770762789759" TEXT="soll dann aber im n&#xe4;chsten Schritt das Tracking selber implementieren">
<icon BUILTIN="hourglass"/>
</node>
<node CREATED="1770762688231" ID="ID_1626867644" MODIFIED="1770762782204" TEXT="und wird sich daf&#xfc;r vstl. Dekoratoren &#xfc;ber die Implementierungs-Klassen legen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
idealerweise funktioniert das sogar ohne dynamic-cast: denn die Dekoratoren k&#246;nnten direkt per&#160;callback-&#955; verdrahtet sein
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1770765035161" ID="ID_763895589" MODIFIED="1770765044567" TEXT="wie generisch wird das sein?">
<icon BUILTIN="help"/>
<node CREATED="1770765047151" ID="ID_1369329762" MODIFIED="1770765133094">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<u><font color="#210aa6">Frage</font></u><font color="#210aa6">:</font>&#160;kann <font face="Monospaced" color="#5b3535">ProviderBufferProvider</font>&#160;einen <i>beliebigen</i>&#160; <font face="Monospaced" color="#5b3535">DiagnosticBuffer</font>&#160;instrumentieren?
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1770765146770" ID="ID_763561545" MODIFIED="1770765167773" TEXT="&#x27f9; gewisse Limitierungen sind zwangsl&#xe4;ufig">
<node CREATED="1770765183203" ID="ID_798928441" MODIFIED="1770765202678" TEXT="die Instrumentierung mu&#xdf; vor dem Einsatz aufgebaut werden"/>
<node CREATED="1770765205184" ID="ID_1324258640" MODIFIED="1770765221801" TEXT="insofern mu&#xdf; die DiagnosticBufferProvider-Instanz vorher existieren"/>
<node CREATED="1770765224298" ID="ID_20191492" MODIFIED="1770765244749" TEXT="aus Gr&#xfc;nden der Einfachheit soll DiagnosticProvider selber der BufferProvider sein"/>
<node CREATED="1770765260219" ID="ID_901586804" MODIFIED="1770765300102" TEXT="&#x27f9; das bedeutet: das Ziel der Instrumentierung mu&#xdf; &#xbb;kanibalisiert&#xab; werden">
<font NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1770765321000" ID="ID_1181670397" MODIFIED="1770765383761">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
&#10233; jedweder State des BufferProvider <b>mu&#223;</b>&#160;in den zwei Implementierungs-S&#228;ulen liegen
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1770765436568" ID="ID_149178331" MODIFIED="1770765532514">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
(alternativ m&#252;&#223;te <i>ausschlie&#223;lich</i>&#160;ein Diagnose-Accessor erzeugt werden)
</p>
</body>
</html>
</richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
das sagt auch der Name, es w&#228;re dann kein <font face="Monospaced">BufferProvider</font>...
</p>
<p>
Und ein solches <i>alternatives</i>&#160;Nutz-Szenario w&#228;re in der Tat denkbar, m&#252;&#223;te dann aber eigens und daneben stehend implementiert werden
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1770765542064" ID="ID_33780277" MODIFIED="1770765572176" TEXT="idealerweise sollte aber DiagnosticBufferProvider nicht von der konkreten Impl abh&#xe4;ngig sein">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1770765576724" ID="ID_1961847255" MODIFIED="1770765581656" TEXT="Beschlu&#xdf;">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
<node CREATED="1770765583502" ID="ID_1200358280" MODIFIED="1770765677346" TEXT="wir halten diese M&#xf6;glichkeiten alle explizit offen">
<icon BUILTIN="yes"/>
</node>
<node CREATED="1770765595718" ID="ID_962837679" MODIFIED="1770766950666" TEXT="zun&#xe4;chst wird aber nur die einfachste L&#xf6;sung implementiert (KISS)">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1770765611528" ID="ID_930758460" MODIFIED="1770766965294" TEXT="und das w&#xe4;re, direkt von NaiveBufferSetup zu erben">
<icon BUILTIN="forward"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1770765634549" ID="ID_802045878" MODIFIED="1770765677346" TEXT="Konsequenz &#x27f9; BufferProviderSetup mu&#xdf; die Dekorations-Mechanik generisch anbieten">
<icon BUILTIN="yes"/>
<node CREATED="1770765700160" ID="ID_1579675471" LINK="https://en.cppreference.com/w/cpp/language/access.html#Protected_member_access" MODIFIED="1770766571232" TEXT="Thema: Sichtbarkeit von protected elements">
<arrowlink COLOR="#4f5d8f" DESTINATION="ID_1070045765" ENDARROW="Default" ENDINCLINATION="-1154;119;" ID="Arrow_ID_484648111" STARTARROW="None" STARTINCLINATION="-1340;84;"/>
</node>
<node CREATED="1770766854965" ID="ID_164565147" MODIFIED="1770766871197" TEXT="man mu&#xdf; einen unique_ptr eines Dekorators erzeugen k&#xf6;nnen"/>
<node CREATED="1770766872225" ID="ID_1590901542" MODIFIED="1770766901998" TEXT="dieser Dekorator mu&#xdf; den urspr&#xfc;nglichen unique_ptr &#x201e;huckepack&#x201c; nehmen"/>
<node CREATED="1770766910933" ID="ID_1255549720" MODIFIED="1770766930079" TEXT="damit kann sich eine abgeleitete Klasse in bestehende Chains &#xbb;einschleifen&#xab;"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1770771357183" ID="ID_1793741597" MODIFIED="1770771891888" TEXT="DiagnosticBufferProviderTest anpassen">
<icon BUILTIN="flag-pink"/>
<node COLOR="#d70247" CREATED="1770771371541" ID="ID_318424657" MODIFIED="1770771443467" TEXT="der hat bisher gar nicht auf dem DiagnosticBufferProvider gearbeitet">
<icon BUILTIN="broken-line"/>
</node>
<node COLOR="#5b280f" CREATED="1770771385939" ID="ID_1071035672" MODIFIED="1770771428112" TEXT="sondern &#x201e;wild&#x201c; auf das HeapMemProvider-API daneben zugegriffen">
<icon BUILTIN="closed"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1770771747922" ID="ID_246706757" MODIFIED="1770771768414" TEXT="gilt auch f&#xfc;r DiagnosticOutputSlot">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1770771469374" ID="ID_733817882" MODIFIED="1770771479444" TEXT="problematische Zugriffe">
<node CREATED="1770771484104" ID="ID_833241344" MODIFIED="1770771491247" TEXT="provider.accessEmitted(nr)"/>
<node CREATED="1770771513515" ID="ID_1719397050" MODIFIED="1770771523955" TEXT="provider.accessAs&lt;Type&gt;(nr)"/>
<node CREATED="1770771552023" ID="ID_1783764547" MODIFIED="1770771558695" TEXT="provider.emittedCnt()"/>
</node>
</node>
</node>
</node>
</node>
@ -158620,7 +158819,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1734709116112" ID="ID_1235302182" MODIFIED="1734709126137" TEXT="unterscheide explizit und implizit">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1734708975355" ID="ID_1311116905" MODIFIED="1734712892968" TEXT="explicit convertible">
<node CREATED="1734708975355" FOLDED="true" ID="ID_1311116905" MODIFIED="1734712892968" TEXT="explicit convertible">
<linktarget COLOR="#8c85c9" DESTINATION="ID_1311116905" ENDARROW="Default" ENDINCLINATION="-3938;658;" ID="Arrow_ID_974872159" SOURCE="ID_1098163848" STARTARROW="None" STARTINCLINATION="-405;33;"/>
<node CREATED="1734708872513" ID="ID_179340258" MODIFIED="1734709676425" TEXT="es ist nicht ganz klar was damit gemeint ist....">
<icon BUILTIN="messagebox_warning"/>
@ -158656,6 +158855,61 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
</node>
</node>
</node>
<node CREATED="1770766014454" ID="ID_1109377879" MODIFIED="1770766020966" TEXT="rules...">
<node CREATED="1770766044584" ID="ID_397656010" MODIFIED="1770766178305" TEXT="private member access">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Gilt stets auch f&#252;r <i>andere Objekt-Instanzen</i>&#160;des gleichen Typs. Gilt auch f&#252;r nested Classes, und member functions, und nested Classes in member functions; wobei allerdings, die Instanz mu&#223; man explizit in der Hand haben (es gibt hier keine solche &#187;magic&#171; wie in Java, wo eine non-static nested class automatisch auch einen outer.this-ptr bekommt)
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1770765867372" ID="ID_1070045765" MODIFIED="1770766571232" TEXT="protected member access">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
konzeptionell: das ist ein separates API f&#252;r abgeleitete Klassen
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#4f5d8f" DESTINATION="ID_1070045765" ENDARROW="Default" ENDINCLINATION="-1154;119;" ID="Arrow_ID_484648111" SOURCE="ID_1579675471" STARTARROW="None" STARTINCLINATION="-1340;84;"/>
<node CREATED="1770765894191" ID="ID_399765269" MODIFIED="1770766423176" TEXT="nur auf Instanzen des gleichen, abgeleiteten Typs">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Man mu&#223; unterscheiden zwischen Deklarationen und dem Zugang zu konkreten Members. <i>Deklarationen</i>&#160;sieht jede abgeleitete Klasse. Aber auf <i>protected Members</i>&#160;in einer Basisklasse zugreifen kann man <b>nur</b>&#160;durch eine Instanz einer abgeleiteten Klasse; und zwar mu&#223; der Typ dieser Instanz <b>gleich</b>&#160;(oder abgeleitet) sein wie der Typ, aus dem heraus der Code zugreift. Konkret: auf base.member kann ich nur durch eine derived&amp; zugreifen (das schlie&#223;t *this ein). Aber nicht durch irgend ein anderes Objekt oder eine base&amp;
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1770765911615" ID="ID_247300867" MODIFIED="1770766562132" TEXT="sonst k&#xf6;nnte eine abgeleitete Klasse eine fremde abgeleitete Klasse manipulieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Ohne diese Regel w&#228;ren wilde Kreuz-Zugriffe auf komplett andere Vererbungslinien m&#246;glich; man bedenke im Besonderen, da&#223; 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&#246;nnte das alles unterlaufen. Es ist ja ohnehin ein Zugest&#228;ndnis, da&#223; man auf was anderes als *this &#252;berhaupt zugreifen darf.
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node CREATED="1734712757872" ID="ID_562062528" MODIFIED="1734712773062" TEXT="&#x3bb;">
<font NAME="SansSerif" SIZE="16"/>
<node CREATED="1734711676585" ID="ID_338918761" MODIFIED="1734712797437" TEXT="&#x3bb;-Funktionspointer decay">