Invocation: settle upon a way to mark the output buffer

...this is a surprisingly tricky issue, since it undercuts the
generic and recursive implementation of buffer handling;

fortunately I've foreseen such demands may arise down the road
and I've reserved an »Local Key« (now renamed into `LocalTag`),
whose meaning is implementation defined and interpreted by
the specific `BufferProvider`
This commit is contained in:
Fischlurch 2024-07-27 17:17:02 +02:00
parent ea183086ca
commit 6d7a814495
11 changed files with 350 additions and 157 deletions

View file

@ -50,12 +50,12 @@ namespace engine {
/**
* an opaque ID to be used by the BufferProvider implementation.
* an opaque mark to be used by the BufferProvider implementation.
* Typically this will be used, to set apart some pre-registered
* kinds of buffers. It is treated as being part of the buffer type.
* LocalKey objects may be copied but not re-assigned or changed.
* LocalTag objects may be copied but not re-assigned or changed.
*/
class LocalKey
class LocalTag
{
union OpaqueData
{
@ -67,17 +67,19 @@ namespace engine {
public:
explicit
LocalKey (uint64_t opaqueValue=0)
LocalTag (uint64_t opaqueValue=0)
{
privateID_._as_number = opaqueValue;
}
LocalKey (void* impl_related_ptr)
LocalTag (void* impl_related_ptr)
{
privateID_._as_number = 0;
privateID_._as_pointer = impl_related_ptr;
}
/** Marker when no distinct local key is given */
static const LocalTag UNKNOWN;
operator uint64_t() const
{
@ -89,26 +91,26 @@ namespace engine {
return privateID_._as_pointer;
}
bool
isDefined() const
explicit
operator bool() const
{
return bool(privateID_._as_number);
}
friend size_t
hash_value (LocalKey const& lkey)
hash_value (LocalTag const& lkey)
{
boost::hash<uint64_t> hashFunction;
return hashFunction(lkey.privateID_._as_number);
}
friend bool
operator== (LocalKey const& left, LocalKey const& right)
operator== (LocalTag const& left, LocalTag const& right)
{
return uint64_t(left) == uint64_t(right);
}
friend bool
operator!= (LocalKey const& left, LocalKey const& right)
operator!= (LocalTag const& left, LocalTag const& right)
{
return uint64_t(left) != uint64_t(right);
}
@ -116,7 +118,7 @@ namespace engine {
private:
/** assignment usually prohibited */
LocalKey& operator= (LocalKey const& o)
LocalTag& operator= (LocalTag const& o)
{
privateID_ = o.privateID_;
return *this;

View file

@ -104,19 +104,16 @@ namespace engine {
namespace { // internal constants to mark the default case
const LocalKey UNSPECIFIC;
const TypeHandler RAW_BUFFER;
inline bool
nontrivial (TypeHandler const& toVerify)
{
return RAW_BUFFER != toVerify;
return TypeHandler::RAW != toVerify;
}
inline bool
nontrivial (LocalKey const& toVerify)
nontrivial (LocalTag const& toVerify)
{
return UNSPECIFIC != toVerify;
return LocalTag::UNKNOWN != toVerify;
}
}
@ -151,7 +148,7 @@ namespace engine {
protected:
size_t storageSize_;
TypeHandler instanceFunc_;
LocalKey specifics_;
LocalTag specifics_;
public:
@ -165,8 +162,8 @@ namespace engine {
: parent_(familyID)
, hashID_(chainedHash (familyID, storageSize))
, storageSize_(storageSize)
, instanceFunc_(RAW_BUFFER)
, specifics_(UNSPECIFIC)
, instanceFunc_(TypeHandler::RAW)
, specifics_(LocalTag::UNKNOWN)
{ }
// standard copy operations permitted
@ -201,12 +198,12 @@ namespace engine {
* Using a different private ID than the parent type,
* all else remaining the same
*/
Key (Key const& parent, LocalKey anotherTypeSpecificInternalID)
Key (Key const& parent, LocalTag anotherTypeSpecificInternalTag)
: parent_(parent.hashID_)
, hashID_(chainedHash (parent_, anotherTypeSpecificInternalID))
, hashID_(chainedHash (parent_, anotherTypeSpecificInternalTag))
, storageSize_(parent.storageSize_)
, instanceFunc_(parent.instanceFunc_)
, specifics_(anotherTypeSpecificInternalID) // differing from parent
, specifics_(anotherTypeSpecificInternalTag) // differing from parent
{ }
@ -217,19 +214,19 @@ namespace engine {
* For NULL buffer a copy of the parent is returned.
*/
static Key
forEntry (Key const& parent, const void* bufferAddr, LocalKey const& implID =UNSPECIFIC)
forEntry (Key const& parent, const void* bufferAddr, LocalTag const& localTag =LocalTag::UNKNOWN)
{
Key newKey(parent);
Key newKey{parent}; // copy of parent as baseline
if (bufferAddr)
{
newKey.parent_ = HashVal(parent);
newKey.hashID_ = chainedHash(parent, bufferAddr);
if (nontrivial(implID))
if (nontrivial(localTag))
{
REQUIRE (!newKey.specifics_.isDefined(),
"Implementation defined local key should not be overridden. "
"Underlying buffer type already defines a nontrivial LocalKey");
newKey.specifics_ = implID;
if (nontrivial(parent.specifics_))
throw error::Logic{"Implementation defined local key should not be overridden. "
"Underlying buffer type already defines a nontrivial LocalTag"};
newKey.specifics_ = localTag;
} }
return newKey;
}
@ -244,7 +241,7 @@ namespace engine {
}
LocalKey const& localKey() const { return specifics_;}
LocalTag const& localTag() const { return specifics_;}
size_t storageSize() const { return storageSize_; }
HashVal parentKey() const { return parent_;}
@ -273,10 +270,13 @@ namespace engine {
void* buffer_;
protected:
Entry (Key const& parent, void* bufferPtr =0, LocalKey const& implID =UNSPECIFIC)
: Key (Key::forEntry (parent, bufferPtr, implID))
, state_(bufferPtr? LOCKED:NIL)
, buffer_(bufferPtr)
Entry (Key const& parent
,void* bufferPtr =nullptr
,LocalTag const& specialTag =LocalTag::UNKNOWN
)
: Key{Key::forEntry (parent, bufferPtr, specialTag)}
, state_{bufferPtr? LOCKED:NIL}
, buffer_{bufferPtr}
{ }
/// BufferMetadata is allowed to create
@ -290,7 +290,7 @@ namespace engine {
bool
isLocked() const
{
ASSERT (!buffer_ || (NIL != state_ && FREE != state_));
ASSERT (!buffer_ or (NIL != state_ and FREE != state_));
return bool(buffer_);
}
@ -300,7 +300,7 @@ namespace engine {
bool
isTypeKey() const
{
return NIL == state_ && !buffer_;
return NIL == state_ and not buffer_;
}
@ -326,13 +326,13 @@ namespace engine {
{
__must_not_be_NIL();
if ( (state_ == FREE && newState == LOCKED)
||(state_ == LOCKED && newState == EMITTED)
||(state_ == LOCKED && newState == BLOCKED)
||(state_ == LOCKED && newState == FREE)
||(state_ == EMITTED && newState == BLOCKED)
||(state_ == EMITTED && newState == FREE)
||(state_ == BLOCKED && newState == FREE))
if ( (state_ == FREE and newState == LOCKED)
or (state_ == LOCKED and newState == EMITTED)
or (state_ == LOCKED and newState == BLOCKED)
or (state_ == LOCKED and newState == FREE)
or (state_ == EMITTED and newState == BLOCKED)
or (state_ == EMITTED and newState == FREE)
or (state_ == BLOCKED and newState == FREE))
{
// allowed transition
if (newState == FREE)
@ -357,7 +357,7 @@ namespace engine {
Entry&
invalidate (bool invokeDtor =true)
{
if (buffer_ && invokeDtor)
if (buffer_ and invokeDtor)
invokeEmbeddedDtor_and_clear();
buffer_ = 0;
state_ = FREE;
@ -546,8 +546,8 @@ namespace engine {
///////////////////////////TICKET #854 : ensure proper locking happens "somewhere" when mutating metadata
public:
typedef metadata::Key Key;
typedef metadata::Entry Entry;
using Key = metadata::Key;
using Entry = metadata::Entry;
/** establish a metadata registry.
* Such will maintain a family of buffer type entries
@ -566,15 +566,15 @@ namespace engine {
* from that point on. Properties are combined according to
* a fixed type specialisation order, with the buffer size
* forming the base level, possible TypeHandler functors the
* second level, and implementation defined LocalKey entries
* second level, and implementation defined LocalTag entries
* the third level. All these levels describe abstract type
* keys, not entries for concrete buffers. The latter are
* always created as children of a known type key.
*/
Key
key ( size_t storageSize
, TypeHandler instanceFunc =RAW_BUFFER
, LocalKey specifics =UNSPECIFIC)
, TypeHandler instanceFunc =TypeHandler::RAW
, LocalTag specifics =LocalTag::UNKNOWN)
{
REQUIRE (storageSize);
Key typeKey = trackKey (family_, storageSize);
@ -598,7 +598,7 @@ namespace engine {
/** create a sub-type,
* using a different private-ID (implementation defined) */
Key
key (Key const& parentKey, LocalKey specifics)
key (Key const& parentKey, LocalTag specifics)
{
return trackKey (parentKey, specifics);
}
@ -608,13 +608,13 @@ namespace engine {
* @note might create/register a new Entry as a side-effect
*/
Key const&
key (Key const& parentKey, void* concreteBuffer, LocalKey const& implID =UNSPECIFIC)
key (Key const& parentKey, void* concreteBuffer, LocalTag const& specifics =LocalTag::UNKNOWN)
{
Key derivedKey = Key::forEntry (parentKey, concreteBuffer);
Entry* existing = table_.fetch (derivedKey);
return existing? *existing
: markLocked (parentKey,concreteBuffer,implID);
: markLocked (parentKey,concreteBuffer,specifics);
}
/** core operation to access or create a concrete buffer metadata entry.
@ -642,21 +642,21 @@ namespace engine {
Entry&
lock (Key const& parentKey
,void* concreteBuffer
,LocalKey const& implID =UNSPECIFIC
,LocalTag const& specifics =LocalTag::UNKNOWN
,bool onlyNew =false)
{
if (!concreteBuffer)
throw error::Invalid{"Attempt to lock a slot for a NULL buffer"
, LERR_(BOTTOM_VALUE)};
Entry newEntry(parentKey, concreteBuffer, implID);
Entry newEntry{parentKey, concreteBuffer, specifics};
Entry* existing = table_.fetch (newEntry);
if (existing && onlyNew)
if (existing and onlyNew)
throw error::Logic{"Attempt to lock a slot for a new buffer, "
"while actually the old buffer is still locked"
, LERR_(LIFECYCLE)};
if (existing && existing->isLocked())
if (existing and existing->isLocked())
throw error::Logic{"Attempt to re-lock a buffer still in use"
, LERR_(LIFECYCLE)};
@ -695,7 +695,7 @@ namespace engine {
{
const Entry* entry = table_.fetch (key);
return entry
&& entry->isLocked();
and entry->isLocked();
}
@ -713,13 +713,13 @@ namespace engine {
* created, but is marked as FREE
*/
Entry&
markLocked (Key const& parentKey, void* buffer, LocalKey const& implID =UNSPECIFIC)
markLocked (Key const& parentKey, void* buffer, LocalTag const& specifics =LocalTag::UNKNOWN)
{
if (!buffer)
throw error::Fatal{"Attempt to lock for a NULL buffer. Allocation floundered?"
, LERR_(BOTTOM_VALUE)};
return this->lock(parentKey, buffer, implID, true); // force creation of a new entry
return this->lock (parentKey, buffer, specifics, true); // force creation of a new entry
}
/** purge the bare metadata Entry from the metadata tables.
@ -731,7 +731,7 @@ namespace engine {
Entry* entry = table_.fetch (key);
if (!entry) return;
ASSERT (entry && (key == HashVal(*entry)));
ASSERT (entry and (key == HashVal(*entry)));
release (*entry);
}
@ -787,6 +787,5 @@ namespace engine {
}} // namespace steam::engine
#endif
#endif /*STEAM_ENGINE_BUFFR_METADATA_H*/

View file

@ -36,6 +36,10 @@ using util::isSameObject;
namespace steam {
namespace engine {
// storage for the default-marker constants
const TypeHandler TypeHandler::RAW{};
const LocalTag LocalTag::UNKNOWN{};
namespace { // impl. details and definitions
@ -98,10 +102,10 @@ namespace engine {
* actual buffer, which is locked for exclusive use by one client.
*/
BuffHandle
BufferProvider::buildHandle (HashVal typeID, void* storage, LocalKey const& implID)
BufferProvider::buildHandle (HashVal typeID, void* storage, LocalTag const& localTag)
{
metadata::Key& typeKey = meta_->get (typeID);
metadata::Entry& entry = meta_->markLocked(typeKey, storage, implID);
metadata::Entry& entry = meta_->markLocked(typeKey, storage, localTag);
return BuffHandle (BuffDescr(*this, entry), storage);
}
@ -167,7 +171,7 @@ namespace engine {
BufferProvider::emitBuffer (BuffHandle const& handle)
{
metadata::Entry& metaEntry = meta_->get (handle.entryID());
mark_emitted (metaEntry.parentKey(), metaEntry.localKey());
mark_emitted (metaEntry.parentKey(), metaEntry.localTag());
metaEntry.mark(EMITTED);
}
@ -185,7 +189,7 @@ namespace engine {
try {
metadata::Entry& metaEntry = meta_->get (handle.entryID());
metaEntry.mark(FREE); // might invoke embedded dtor function
detachBuffer (metaEntry.parentKey(), metaEntry.localKey());
detachBuffer (metaEntry.parentKey(), metaEntry.localTag());
meta_->release (metaEntry);
}
ERROR_LOG_AND_IGNORE (engine, "releasing a buffer from BufferProvider")
@ -229,7 +233,7 @@ namespace engine {
try {
metadata::Entry& metaEntry = meta_->get (target.entryID());
metaEntry.invalidate (invokeDtor);
detachBuffer (metaEntry.parentKey(), metaEntry.localKey());
detachBuffer (metaEntry.parentKey(), metaEntry.localTag());
meta_->release (metaEntry);
}
ERROR_LOG_AND_IGNORE (engine, "cleanup of buffer metadata while handling an error")

View file

@ -73,7 +73,7 @@ namespace engine {
* The pointer to actual buffer storage can be retrieved by
* - optionally announcing the required buffer(s) beforehand
* - "locking" a buffer to yield a buffer handle
* - dereferencing this smart-handle class
* - then dereferencing the obtained smart-handle
*
* @warning all of BufferProvider is assumed to run within a threadsafe environment.
*
@ -93,8 +93,8 @@ namespace engine {
virtual uint prepareBuffers (uint count, HashVal typeID) =0;
virtual BuffHandle provideLockedBuffer (HashVal typeID) =0;
virtual void mark_emitted (HashVal typeID, LocalKey const&) =0;
virtual void detachBuffer (HashVal typeID, LocalKey const&) =0;
virtual void mark_emitted (HashVal typeID, LocalTag const&) =0;
virtual void detachBuffer (HashVal typeID, LocalTag const&) =0;
public:
@ -131,7 +131,7 @@ namespace engine {
size_t getBufferSize (HashVal typeID) const;
protected:
BuffHandle buildHandle (HashVal typeID, void* storage, LocalKey const&);
BuffHandle buildHandle (HashVal typeID, void* storage, LocalTag const& =LocalTag::UNKNOWN);
bool was_created_by_this_provider (BuffDescr const&) const;
};

View file

@ -111,7 +111,7 @@ namespace engine {
/** convenience shortcut: access the buffer contents casted to a specific type.
* @warning this is a \em blind cast, there is no type safety.
* @note clients can utilise the metadata::LocalKey to keep track of some
* @note clients can utilise the metadata::LocalTag to keep track of some
* specific property of the buffer, like e.g. the type of object.
*/
template<typename BU>

View file

@ -252,9 +252,9 @@ namespace engine {
void
TrackingHeapBlockProvider::mark_emitted (HashVal typeID, LocalKey const& implID)
TrackingHeapBlockProvider::mark_emitted (HashVal typeID, LocalTag const& specifics)
{
diagn::Block* block4buffer = locateBlock (typeID, implID);
diagn::Block* block4buffer = locateBlock (typeID, specifics);
if (!block4buffer)
throw error::Logic ("Attempt to emit a buffer not known to this BufferProvider"
, LUMIERA_ERROR_BUFFER_MANAGEMENT);
@ -265,9 +265,9 @@ namespace engine {
/** mark a buffer as officially discarded */
void
TrackingHeapBlockProvider::detachBuffer (HashVal typeID, LocalKey const& implID)
TrackingHeapBlockProvider::detachBuffer (HashVal typeID, LocalTag const& specifics)
{
diagn::Block* block4buffer = locateBlock (typeID, implID);
diagn::Block* block4buffer = locateBlock (typeID, specifics);
REQUIRE (block4buffer, "releasing a buffer not allocated through this provider");
block4buffer->markReleased();
}

View file

@ -28,7 +28,7 @@
** the fact.
**
** The allocated buffers are numbered with a simple ascending sequence of integers,
** used as LocalKey (see BufferMetadata). Clients can just request a Buffer with the
** used as LocalTag (see BufferMetadata). Clients can just 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,
@ -136,8 +136,8 @@ namespace engine {
virtual uint prepareBuffers (uint count, HashVal typeID);
virtual BuffHandle provideLockedBuffer (HashVal typeID);
virtual void mark_emitted (HashVal entryID, LocalKey const&);
virtual void detachBuffer (HashVal entryID, LocalKey const&);
virtual void mark_emitted (HashVal entryID, LocalTag const&);
virtual void detachBuffer (HashVal entryID, LocalTag const&);
public:
TrackingHeapBlockProvider();

View file

@ -118,6 +118,9 @@ namespace engine {
DoInBuffer destroyAttached;
HashVal identity;
/** Marker for the default case: raw buffer without type handling */
static const TypeHandler RAW;
/** build an invalid NIL TypeHandler */
TypeHandler()
: createAttached()

View file

@ -120,7 +120,7 @@ namespace test {
{
size_t const& investigateSize() const { return this->storageSize_; }
TypeHandler const& investigateHandler() const { return this->instanceFunc_; }
LocalKey const& investigateSpecifics() const { return this->specifics_; }
LocalTag const& investigateSpecifics() const { return this->specifics_; }
KeyTypeSpecialisationDiagnostics (Key const& toInvestigate)
: Key(toInvestigate)
@ -140,7 +140,7 @@ namespace test {
return KeyTypeSpecialisationDiagnostics(subject).investigateHandler();
}
inline const LocalKey
inline const LocalTag
verifySpecifics (Key const& subject)
{
return KeyTypeSpecialisationDiagnostics(subject).investigateSpecifics();
@ -191,7 +191,7 @@ namespace test {
HashVal family(123);
Key k1(family, SIZE_A);
Key k12(k1, SIZE_B);
Key k123(k12, LocalKey(56));
Key k123(k12, LocalTag(56));
CHECK (HashVal (k1));
CHECK (HashVal (k12));
@ -257,8 +257,8 @@ namespace test {
TypeHandler placeMarker = TypeHandler::create<Marker>();
TypeHandler noHandler;
LocalKey opaque1 (rand() % 1000);
LocalKey opaque2 (1000 + rand() % 1000);
LocalTag opaque1 (rand() % 1000);
LocalTag opaque2 (1000 + rand() % 1000);
Key k_siz (kb, SIZE_B); // sub-key to "root": use a different buffer size
Key k_han0(kb, noHandler); // sub-key to "root": use a locally defined type functor
@ -305,19 +305,19 @@ namespace test {
CHECK (SIZE_A == verifySize(k_loc1));
CHECK (SIZE_A == verifySize(k_loc2));
CHECK (RAW_BUFFER == verifyHandler(kb ));
CHECK (RAW_BUFFER == verifyHandler(k_siz ));
CHECK (noHandler == verifyHandler(k_han0));
CHECK (placeMarker == verifyHandler(k_han1));
CHECK (RAW_BUFFER == verifyHandler(k_loc1));
CHECK (RAW_BUFFER == verifyHandler(k_loc2));
CHECK (TypeHandler::RAW == verifyHandler(kb ));
CHECK (TypeHandler::RAW == verifyHandler(k_siz ));
CHECK ( noHandler == verifyHandler(k_han0));
CHECK ( placeMarker == verifyHandler(k_han1));
CHECK (TypeHandler::RAW == verifyHandler(k_loc1));
CHECK (TypeHandler::RAW == verifyHandler(k_loc2));
CHECK (UNSPECIFIC == verifySpecifics(kb ));
CHECK (UNSPECIFIC == verifySpecifics(k_siz ));
CHECK (UNSPECIFIC == verifySpecifics(k_han0));
CHECK (UNSPECIFIC == verifySpecifics(k_han1));
CHECK (opaque1 == verifySpecifics(k_loc1));
CHECK (opaque2 == verifySpecifics(k_loc2));
CHECK (LocalTag::UNKNOWN == verifySpecifics(kb ));
CHECK (LocalTag::UNKNOWN == verifySpecifics(k_siz ));
CHECK (LocalTag::UNKNOWN == verifySpecifics(k_han0));
CHECK (LocalTag::UNKNOWN == verifySpecifics(k_han1));
CHECK ( opaque1 == verifySpecifics(k_loc1));
CHECK ( opaque2 == verifySpecifics(k_loc2));
// Verify 2nd level specialisation (some examples)
@ -338,8 +338,8 @@ namespace test {
CHECK (placeMarker == verifyHandler(k_han1_siz_loc2));
CHECK (placeMarker == verifyHandler(k_loc2_han1_siz));
CHECK (UNSPECIFIC == verifySpecifics(k_han1_siz ));
CHECK (UNSPECIFIC == verifySpecifics(k_siz_han1 ));
CHECK (LocalTag::UNKNOWN == verifySpecifics(k_han1_siz ));
CHECK (LocalTag::UNKNOWN == verifySpecifics(k_siz_han1 ));
CHECK (opaque2 == verifySpecifics(k_han1_siz_loc2));
CHECK (opaque2 == verifySpecifics(k_loc2_han1_siz));

View file

@ -193,7 +193,7 @@ namespace test {
* BufferProviderProtocol_test#verifyStandardCase()
* This testcase here performs precisely the metadata related
* operations necessary to carry out the standard case
* outlined on a higher level in the mentioned test.
* outlined at a higher level in the aforementioned test.
*/
void
verifyStandardCase()
@ -206,8 +206,8 @@ namespace test {
metadata::Key rawBuffType = meta_->key(SIZE_B);
// to announce using a number of buffers of this type
LocalKey transaction1(1);
LocalKey transaction2(2);
LocalTag transaction1(1);
LocalTag transaction2(2);
bufferType1 = meta_->key(bufferType1, transaction1);
rawBuffType = meta_->key(rawBuffType, transaction2);
// these type keys are now handed over to the client,
@ -235,11 +235,11 @@ namespace test {
CHECK (LOCKED == r0.state());
CHECK (LOCKED == r1.state());
CHECK (transaction1 == f0.localKey());
CHECK (transaction1 == f1.localKey());
CHECK (transaction1 == f2.localKey());
CHECK (transaction2 == r0.localKey());
CHECK (transaction2 == r1.localKey());
CHECK (transaction1 == f0.localTag());
CHECK (transaction1 == f1.localTag());
CHECK (transaction1 == f2.localTag());
CHECK (transaction2 == r0.localTag());
CHECK (transaction2 == r1.localTag());
CHECK (f0.access() == frames+0);

View file

@ -4369,9 +4369,7 @@
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1481599413419" HGAP="34" ID="ID_673133356" MODIFIED="1576282358148" TEXT="Ticket #318" VSHIFT="-7">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
....das ist schon mehr ein Meta-Ticket,
@ -4442,9 +4440,7 @@
<icon BUILTIN="yes"/>
<node CREATED="1481684391921" ID="ID_138369898" MODIFIED="1576282358147" TEXT="Front-End">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
das Lock sorgt hier f&#252;r konsistenten Zustand und Sichtbarkeit (memory barrier)
@ -4454,9 +4450,7 @@
</node>
<node CREATED="1481684394544" ID="ID_1314197501" MODIFIED="1576282358147" TEXT="Back-End">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Lock ist hier das Dispatcher-Lock
@ -5092,9 +5086,7 @@
<node CREATED="1553902314962" ID="ID_1100232681" MODIFIED="1553902322907" TEXT="vorl&#xe4;ufige Platzhalter-Implementierung"/>
<node CREATED="1553902329566" ID="ID_149032705" MODIFIED="1576282358142" TEXT="PanelLocator">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
8/2018 there is some overlap with the (not yet fully functional)&#160;
@ -5825,9 +5817,7 @@
<node CREATED="1567875285952" ID="ID_979231150" MODIFIED="1567875288691" TEXT="TestControl"/>
<node COLOR="#435e98" CREATED="1567875664340" ID="ID_994953692" MODIFIED="1567875770727">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<b>TestControl</b>&#160;Dialogbox
@ -7555,9 +7545,7 @@
<node CREATED="1508016623480" ID="ID_66450805" MODIFIED="1518487921064" TEXT="Element speichert seine UICoord"/>
<node CREATED="1508016658684" ID="ID_116864327" MODIFIED="1518487921064" TEXT="globaler Index beim Erstellen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...der beim Erstellen des Elements
@ -10053,9 +10041,7 @@
<node CREATED="1513447967084" ID="ID_476332936" MODIFIED="1513447978718" TEXT="d.h. mu&#xdf; die logische Tiefe widerspiegeln"/>
<node CREATED="1513447979450" ID="ID_224439756" MODIFIED="1513448250249" TEXT="...auch wenn der Vater bereits ersch&#xf6;pft ist">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
wir hatten bisher eine auto-Aufr&#228;um-Routine in iterNext(),
@ -13742,9 +13728,7 @@
<node CREATED="1518742996348" ID="ID_328356111" MODIFIED="1518743006606" TEXT="von der Ebene der Sprache her schwer zu verstehen"/>
<node CREATED="1518743012337" ID="ID_1220573120" MODIFIED="1518743054926">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
bleibt dem Charakter nach <i>imperativ</i>
@ -52706,9 +52690,7 @@
</node>
<node CREATED="1492174243863" ID="ID_900555701" MODIFIED="1492174267140">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
aber: Parametrisierung <i>k&#246;nnte</i>&#160;partiell sein
@ -52757,9 +52739,7 @@
<node CREATED="1492269422257" ID="ID_921483875" MODIFIED="1492269432251" TEXT="aber nur im ProcDispatcher"/>
<node CREATED="1492269451181" ID="ID_800020285" MODIFIED="1492269548819">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
sie wird nicht zum <i>Parameter-Sammeln</i>&#160;verwendet
@ -52774,9 +52754,7 @@
</node>
<node CREATED="1492269922724" ID="ID_806519829" MODIFIED="1576282357981" TEXT="Idee: on demand">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...eine Instanz wird dann erzeugt, wenn sie notwendig wird.
@ -80753,6 +80731,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1713795084878" ID="ID_900623108" MODIFIED="1713795152331" TEXT="das Buffer-Protocol gilt als gesetzt">
<linktarget COLOR="#3c61b7" DESTINATION="ID_900623108" ENDARROW="Default" ENDINCLINATION="-475;-40;" ID="Arrow_ID_245920004" SOURCE="ID_267762321" STARTARROW="None" STARTINCLINATION="-218;8;"/>
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1721958694600" ID="ID_769985598" MODIFIED="1721958851624" TEXT="dokumentiert durch: nur BufferProviderProtocol_test">
<arrowlink COLOR="#5387dc" DESTINATION="ID_1661035289" ENDARROW="Default" ENDINCLINATION="-1176;-93;" ID="Arrow_ID_1311080426" STARTARROW="None" STARTINCLINATION="-1176;64;"/>
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#2a0f69" CREATED="1721958519256" ID="ID_876959484" MODIFIED="1721958541355" TEXT="wichtig zum Verst&#xe4;ndnis: BufferMetadata_test">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1713819850506" ID="ID_1750491613" MODIFIED="1713819862771" TEXT="zu kl&#xe4;ren">
@ -88404,8 +88389,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<i>was bis jetzt feststeht</i>: dem Weaving-Pattern werden <font face="Monospaced" color="#37285a"><b>BufferDescriptor</b></font>s gegeben
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="info"/>
</node>
<node CREATED="1721833630028" ID="ID_1463882000" MODIFIED="1721833743407">
@ -88416,8 +88400,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Begr&#252;ndung: der <i>Aufrufer</i>&#160;legt das zusammen mit der konkreten Funktion fest
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -88425,8 +88408,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Der Aufrufer ist Code im Kontext der Domain-Ontology, und nur von dort kann bekannt sein, was die eingebundene Funktion konkret auf jedem &#187;output slot&#171; liefert
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1721833744653" ID="ID_564134305" MODIFIED="1721833811643">
<richcontent TYPE="NODE"><html>
@ -88436,8 +88418,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Einschr&#228;nkung: der Aufrufer kennt den <i>ben&#246;tigten Typ</i>&#160;des Buffers
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#5b280f" CREATED="1721833852346" ID="ID_1878630710" MODIFIED="1721833866578">
@ -88481,8 +88462,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
hei&#223;t konkret, ein BufferProdiver k&#246;nnte einen BufferDescriptor eines anderen Providers &#252;bernehmen und re-interpretieren
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
@ -88537,8 +88517,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<font color="#302948" face="Monospaced">&#160;&#160;BufferProvider::</font><font color="#251e7b" face="Monospaced">getDescriptor</font><font color="#302948" face="Monospaced">&#160;(</font><font color="#981d2b" face="Monospaced"><b>ARGS</b></font><font color="#302948" face="Monospaced">&#160; ...args)</font>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#5b280f" CREATED="1721841418133" HGAP="22" ID="ID_358050145" MODIFIED="1721841447356" TEXT="das w&#xe4;re dann aber noch eine weitere Indirektion" VSHIFT="11">
@ -88561,8 +88540,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
&#10233; das m&#252;&#223;te dann in den <font face="Monospaced"><b>shed()</b></font>-Aufruf gehen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
</node>
@ -88582,8 +88560,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
...im aktuellen Stand brauchen wir die Info nur w&#228;hrend dem Build-Vorgang; sobald man aber sp&#228;ter &#252;bergeht zu einem ctor-&#955;, m&#252;&#223;te man die Info in die Node (in den Turnout) materialisieren. Nun k&#246;nnte man aktuell &#8222;einfach&#8220; einen std::vector nehmen &#8212; oder aber, genauso &#8222;einfach&#8220; einen weiteren SeveralBuilder mitlaufen lassen. Vorteil: der Speicher liegt im AllocationCluster / Nachteil: der Speicher wird verschwendet
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1721842211509" ID="ID_136741154" MODIFIED="1721842223063" TEXT="nun kann man zwei Richtungen einschlagen...">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1721842070408" ID="ID_405313573" MODIFIED="1721842263407" TEXT="wennschon dennschon &#x27f9; dann auch gleich vorsorglich mit materialisieren">
@ -88648,6 +88625,213 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#494465" DESTINATION="ID_611993343" ENDARROW="Default" ENDINCLINATION="-3;-124;" ID="Arrow_ID_490283859" SOURCE="ID_1921234844" STARTARROW="Default" STARTINCLINATION="-2;70;"/>
<linktarget COLOR="#5d434b" DESTINATION="ID_611993343" ENDARROW="Default" ENDINCLINATION="60;-165;" ID="Arrow_ID_819933510" SOURCE="ID_1665424296" STARTARROW="None" STARTINCLINATION="-74;5;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1721866481394" ID="ID_1853457963" MODIFIED="1721866534078" TEXT="zu kl&#xe4;ren: Scope zur Verdrahtung dieser Services">
<icon BUILTIN="yes"/>
<node CREATED="1721866537521" ID="ID_1964460392" MODIFIED="1721866548867" TEXT="sie sind effektiv global"/>
<node CREATED="1721866551423" ID="ID_779602459" MODIFIED="1721866584882" TEXT="problematisch dabei: der Output-BufferProivder">
<node CREATED="1721866589257" ID="ID_1094487880" MODIFIED="1721866862199" TEXT="dieser mu&#xdf; allerdings einen konkreten Bezug herstellen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
im Codepfad des konkreten Aufrufs erfolgt ein lockBuffer() &#8212; und dieser mu&#223; exakt den Ausgabe-Puffer f&#252;r diesen Aufruf liefern
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1721866600848" ID="ID_1628166057" MODIFIED="1721866621316" TEXT="und zwar f&#xfc;r den einzelnen Slot im jeweiligen Aufruf"/>
<node CREATED="1721866623093" ID="ID_172617821" MODIFIED="1721946404316" TEXT="M&#xf6;glichkeiten f&#xfc;r diesen direkten Bezug">
<node CREATED="1721946663784" ID="ID_958099025" MODIFIED="1721956949794" TEXT="Output stets explizit kopieren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
hei&#223;t: wir vergeben diese null&#228;re Optimierung und legen fest, da&#223; das Ergebnis einfach in einem Buffer im Arbeitsspeicher liegt. Jeder Render-Job bekommt dann einen explizit gecodeten Kopier-Schritt
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1721866917499" ID="ID_1329080039" MODIFIED="1722005129923" TEXT="ein spezielles Tag im Buffer-Descriptor ablegen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das m&#252;&#223;te eine Marke sein, die die spezielle BufferProvider-Implementierung &#8212; also der OutputBufferProvider &#8212; erkennt und daraufhin den konkreten extrnen Output-Buffer herausgibt
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#4395d3" DESTINATION="ID_1329080039" ENDARROW="Default" ENDINCLINATION="-105;0;" ID="Arrow_ID_1999279188" SOURCE="ID_1451110951" STARTARROW="None" STARTINCLINATION="6;-21;"/>
</node>
<node CREATED="1721867643305" ID="ID_327945127" MODIFIED="1721947494363" TEXT="aus dem Schema ausbrechen und diesen Buffer dirrekt durchgeben">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Das w&#252;rde bedeuten, eine spezielle Ausnahme in die shed()-Funktion einzubauen, um das lockBuffer() f&#252;rden tats&#228;chlichen &#187;output-slot&#171; zu unterdr&#252;cken und stattdessen hier einen aus dem Kontext bezogenen Buffer einzusetzen. Im Gegenzug w&#252;rde der R&#252;ckgabewert wegfallen und das Ergebnis w&#252;rde stattdessen per Seiteneffekt herausgef&#252;hrt.
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1721866938881" ID="ID_1696632082" MODIFIED="1721946997871" TEXT="die Annahme machen, da&#xdf; es in jedem Callstack nur einen solchen Request gibt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Diese Annahme kann man ziemlich sicher machen; eine Abweichung davon w&#228;re nur m&#246;glich bei einem ziemlich speziellen Setup, bei dem dann setets mehrere Ergebnise auf verschiedenen Ebenen aber im gleichen Rechenproze&#223; anfallen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1721956892200" ID="ID_1451110951" MODIFIED="1721956974355" TEXT="strukturell w&#xe4;re das Spezial-Tag die beste L&#xf6;sung">
<arrowlink COLOR="#4395d3" DESTINATION="ID_1329080039" ENDARROW="Default" ENDINCLINATION="-105;0;" ID="Arrow_ID_1999279188" STARTARROW="None" STARTINCLINATION="6;-21;"/>
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1721957000178" ID="ID_917881726" MODIFIED="1721962405933" TEXT="fragt sich nur: ist das m&#xf6;glich...?">
<icon BUILTIN="help"/>
<node CREATED="1721957022223" ID="ID_936909569" MODIFIED="1722091785735" TEXT="stelle fest: damals habe ich einen &#xbb;LocalKey&#xab; eingef&#xfc;hrt">
<node COLOR="#435e98" CREATED="1722091787094" ID="ID_1141022486" MODIFIED="1722091804995" TEXT="inzwischen umbenannt &#x27f6; LocalTag">
<font NAME="SansSerif" SIZE="11"/>
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1721957037236" ID="ID_1595632989" MODIFIED="1721957052094" TEXT="und dazu eine hierarchische Struktur in den Buffer-Metadaten">
<node CREATED="1721959590082" ID="ID_526174965" MODIFIED="1722091814802" TEXT="der Metadata-Entry zum Key hat ein zus&#xe4;tzliches Feld LocalTag"/>
<node CREATED="1721959630820" ID="ID_1258781639" MODIFIED="1721959649772" TEXT="dieses kann spezialisiert werden &#x2014; unabh&#xe4;ngig vom Type-Handler"/>
<node CREATED="1721959662520" ID="ID_820266104" MODIFIED="1721959689960" TEXT="sp&#xe4;ter f&#xfc;r die Buffer-Lebenszyklus-Aktionen wird dieses mitgegeben"/>
<node CREATED="1721959691067" ID="ID_1814549151" MODIFIED="1722091848881" TEXT="&#x27f9; die konkrete BufferProvider-Impl sieht deses LocalTag...">
<node CREATED="1721959715905" ID="ID_1998103464" MODIFIED="1721959721516" TEXT="beim lock() eines Buffers"/>
<node CREATED="1721959722368" ID="ID_984626240" MODIFIED="1721959725644" TEXT="beim emit()"/>
<node CREATED="1721959726632" ID="ID_639484944" MODIFIED="1721959731395" TEXT="beim release()"/>
</node>
<node CREATED="1721960062374" ID="ID_465493891" MODIFIED="1721960085785" TEXT="Demo-Impl : TrackingHeapBlockProvider">
<icon BUILTIN="forward"/>
<node CREATED="1721960087782" ID="ID_829505722" MODIFIED="1722091866224">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
dieser assoziiert den <b>Buffer-Header</b>&#160;als LocalTag
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1721960123381" ID="ID_539555902" MODIFIED="1721962016975" TEXT="macht Sinn, da der Type-Handler ja noch generisch und duplizierbar ist"/>
<node CREATED="1721962046996" ID="ID_1135222824" MODIFIED="1721962156716" TEXT="und als Storage nur der eigentliche Buffer gespeichert wird">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...dieser eigentliche Buffer kann auch nochmal per TypeHandler einen &#187;Inlay-Type&#171; bekommen; aber hier beim TrackingHeapBlockProvider ist ja der entscheidenden Punkt, jede Allokation nochmal sekund&#228;r zu verzeichnen und nachzuverfolgen, um entsprechende Verifikationen in den Tests zu erm&#246;glichen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1721962165891" ID="ID_1229002680" MODIFIED="1722091876751" TEXT="das LocalTag darf in jeder Hierarchie genau einmal gesetzt werden">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
siehe Key::forEntry
</p>
<p>
Das hei&#223;t, entweder man setzt ihn schon beim BufferDescriptor, oder man setzt ihn erst mit dem sub-Entry f&#252;r den konkreten Buffer beim lock() &#8212; aber beides zusammen ist nicht erlaubt
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node CREATED="1721957074061" ID="ID_1934276567" LINK="#ID_876959484" MODIFIED="1721958546357" TEXT="siehe BufferMetadata_test::verifyStandardCase()"/>
<node COLOR="#435e98" CREATED="1721962300725" ID="ID_1284720886" MODIFIED="1721962403740" TEXT="Fazit">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1721962307945" ID="ID_944887840" MODIFIED="1721962326774" TEXT="meine Analyse von 2013 war gr&#xfc;ndlich"/>
<node CREATED="1721962327606" ID="ID_535842224" MODIFIED="1721962350354">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
deshalb habe ich <b>genau f&#252;r diesen Zweck</b>&#160;bereits einen Mechanismus geschaffen
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1721962371425" ID="ID_1532700922" MODIFIED="1722091708754">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
dieses <font color="#1b40b4" face="Monospaced">LocalTag</font>&#160;ist aber nicht &#252;berall auf das Buffer-Provider-API herausgef&#252;hrt
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1721962419154" ID="ID_197438854" MODIFIED="1721962438994" TEXT="zu &#xfc;berlegen: wann im Lebenszyklus mu&#xdf; diese Info gegeben werden">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1722005002357" ID="ID_1859901064" MODIFIED="1722005054298" TEXT="im Kern ist es eine spezielle Marke f&#xfc;r jeden einzelnen Aufruf"/>
<node CREATED="1722005137995" ID="ID_1498833312" MODIFIED="1722005163168" TEXT="damit kann sie stets nur f&#xfc;r die einzelne Job-Invocation gegeben sein"/>
<node CREATED="1722005561810" ID="ID_605283552" MODIFIED="1722005604557" TEXT="zu dem Zeitpunkt haben wir einen Buffer-Descriptor vorliegen">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1722006966966" ID="ID_80799942" MODIFIED="1722007044652" TEXT="neues API ben&#xf6;tigt">
<icon BUILTIN="flag-pink"/>
<node CREATED="1722006974253" ID="ID_1472014079" MODIFIED="1722006984025" TEXT="aufrufbar auf/mit einem BufferDescriptor"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1722006984755" ID="ID_1802025811" MODIFIED="1722092863044" TEXT="kann ein LocalTag setzen">
<icon BUILTIN="pencil"/>
<node CREATED="1722092776817" ID="ID_1178263086" MODIFIED="1722092793427" TEXT="Bezugspunkt: BufferMetadata::lock()">
<node CREATED="1722092795833" ID="ID_444477764" MODIFIED="1722092803241" TEXT="konstruiert einen abgeleiteten Entry"/>
<node CREATED="1722092804037" ID="ID_696205920" MODIFIED="1722092813545" TEXT="konstruiert dabei einen abgeleiteten Key"/>
<node CREATED="1722092814539" ID="ID_32890513" MODIFIED="1722092832617" TEXT="speichert diesen abgeleiteten Entriy in die Metadaten-Tabelle"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1722092834937" ID="ID_1568128579" MODIFIED="1722092977474" TEXT="pr&#xfc;fen: Hash-Behandlung konsistent">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
im Besonderen an die Reihenfolge denken ... mir f&#228;llt auf, da&#223; ich <i>chainedHash</i>&#160; verwende; damit w&#228;re der Hash-Key <i>pfadabh&#228;ngig</i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node COLOR="#338800" CREATED="1722006993331" ID="ID_1387727951" MODIFIED="1722091917790" TEXT="mu&#xdf; mehrfach-Spezialisierung unterbinden">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1722007009608" ID="ID_79703512" MODIFIED="1722091915536" TEXT="ben&#xf6;tigt Default-Wert auf der normalen buildHandle">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1722007026247" ID="ID_1017662774" MODIFIED="1722090095412" TEXT="mu&#xdf; daf&#xfc;r die Konstante UNSPECIFIC sichtbar machen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#435e98" CREATED="1722092440857" ID="ID_1519590593" MODIFIED="1722092453705" TEXT="(Assertion versch&#xe4;rft in eine Exception)"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1722090806138" ID="ID_1141466279" MODIFIED="1722092473594">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
nebenbei: umbenennen &#10230; <b>LocalTag</b>
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
@ -88956,7 +89140,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#ca3e80" DESTINATION="ID_1795755773" ENDARROW="Default" ENDINCLINATION="333;-16;" ID="Arrow_ID_778082175" SOURCE="ID_1238813567" STARTARROW="None" STARTINCLINATION="-512;47;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1713824325760" ID="ID_1661035289" MODIFIED="1713824498751" TEXT="BufferProviderProtocol_test">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1713824325760" ID="ID_1661035289" MODIFIED="1721958851624" TEXT="BufferProviderProtocol_test">
<linktarget COLOR="#5387dc" DESTINATION="ID_1661035289" ENDARROW="Default" ENDINCLINATION="-1176;-93;" ID="Arrow_ID_1311080426" SOURCE="ID_769985598" STARTARROW="None" STARTINCLINATION="-1176;64;"/>
<icon BUILTIN="flag-yellow"/>
<node CREATED="1713824328087" ID="ID_1065671274" MODIFIED="1713824335184" TEXT="Standard-Fall fertigstellen"/>
</node>