Library: allow for dynamic adjustments in AllocationCluster

This is a low-level interface to allow changing the size of
the currently latest allocation in `AllocationCluster`; a client
aware of this capability can perform a real »in-place re-alloc«,
assuming the very specific usage constraints can be met.

`lib::Several<X>` will use this feature when attached to an
`AllocationCluster`; with this special setup, an previously
unknown number of non-copyable objects can be built without
wasting any storage, as long as the storage reserve in the
current extent of the `AllocationCluster` is sufficient.
This commit is contained in:
Fischlurch 2024-06-13 23:46:17 +02:00
parent 3bbdf40c32
commit bb164e37c8
4 changed files with 258 additions and 53 deletions

View file

@ -30,6 +30,13 @@
** pattern. Optionally it is even possible to skip invocation of object
** destructors, making de-allocation highly efficient (typically the
** memory pages are already cache-cold when about to discarded).
** \par using as STL allocator
** AllocationCluster::Allocator is an adapter to expose the interface
** expected by std::allocator_traits (and thus usable by all standard compliant
** containers). With this usage, the container _manages_ the contained objects,
** including the invocation of their destructors, while relying on the allocator
** to allot and discard bare memory. However, to avoid invoking any destructors,
** the container itself can be created with AllocationCluster::createDisposable.
** @warning deliberately *not threadsafe*.
** @remark confine usage to a single thread or use thread-local clusters.
** @see allocation-cluster-test.cpp
@ -52,6 +59,7 @@
namespace lib {
namespace test { class AllocationCluster_test; } // declared friend for low-level-checks
namespace err = lumiera::error;
/**
@ -77,17 +85,23 @@ namespace lib {
void* pos{nullptr};
size_t rest{0};
auto bytePos() { return static_cast<std::byte*> (pos); }
void*
allot (size_t bytes, size_t alignment)
{
void* loc = std::align (alignment, bytes, pos, rest);
if (loc)
{ // requested allocation indeed fits in space
pos = static_cast<std::byte*>(pos) + bytes;
pos = bytePos() + bytes;
rest -= bytes;
}
return loc;
}
void adjustPos (int offset);
bool hasReserve (int offset) const;
bool matches_last_allocation (void const* loc, size_t siz) const;
};
Storage storage_;
@ -131,6 +145,9 @@ namespace lib {
Allocator<X> getAllocator() { return this; }
bool canAdjust (void* loc, size_t oldSiz, size_t newSiz) const;
void doAdjust (void* loc, size_t oldSiz, size_t newSiz);
private:
/**
* portion out the requested amount of memory,
@ -195,7 +212,7 @@ namespace lib {
* but *without invoking its destructor* on clean-up (for performance reasons).
*/
template<class TY, typename...ARGS>
TY&
inline TY&
AllocationCluster::createDisposable (ARGS&& ...args)
{
return * new(allot<TY>()) TY (std::forward<ARGS> (args)...);
@ -207,7 +224,7 @@ namespace lib {
* @note whenever possible, the #createDisposable variant should be preferred
*/
template<class TY, typename...ARGS>
TY&
inline TY&
AllocationCluster::create (ARGS&& ...args)
{
if constexpr (std::is_trivial_v<TY>)
@ -220,5 +237,55 @@ namespace lib {
}
/**
* Adjust the size of the latest raw memory allocation dynamically.
* @param loc an allocation provided by this AllocationCluster
* @param oldSiz the size requested for the allocation \a loc
* @param newSiz desired new size for this allocation
* @remarks since AllocationCluster must be used in a single threaded environment,
* the invoking code can sometimes arrange to adapt the latest allocation
* to a dynamically changing situation, like e.g. populating a container
* with a previously unknown number of elements. Obviously, the overall
* allocation must stay within the confines of the current extent; it
* is thus mandatory to [check](\ref canAdjust) the ability beforehand.
*/
inline void
AllocationCluster::doAdjust(void* loc, size_t oldSiz, size_t newSiz)
{
if (not canAdjust (loc,oldSiz,newSiz))
throw err::Invalid {"AllocationCluster: unable to perform this allocation adjustment."};
storage_.adjustPos (int(newSiz) - int(oldSiz));
}
inline bool
AllocationCluster::canAdjust(void* loc, size_t oldSiz, size_t newSiz) const
{
int offset{int(newSiz) - int(oldSiz)}; // is properly limited iff oldSiz is correct
return storage_.matches_last_allocation (loc, oldSiz)
and storage_.hasReserve (offset);
}
inline void
AllocationCluster::Storage::adjustPos (int offset) ///< @warning be sure a negative offset is properly limited
{
REQUIRE (pos);
REQUIRE (hasReserve (rest));
pos = bytePos() + offset;
rest -= offset;
}
inline bool
AllocationCluster::Storage::hasReserve (int offset) const
{
return offset <= int(rest);
}
inline bool
AllocationCluster::Storage::matches_last_allocation (void const* loc, size_t siz) const
{
return loc == static_cast<std::byte const*> (pos) - siz;
}
} // namespace lib
#endif /*LIB_ALLOCATION_CLUSTER_H*/

View file

@ -250,8 +250,6 @@ namespace lib {
using Fac::Fac; // pass-through ctor
const bool isDisposable{false}; ///< memory must be explicitly deallocated
bool canExpand(size_t){ return false; }
Bucket*

View file

@ -154,6 +154,7 @@ namespace test {
checkLifecycle();
verifyInternals();
use_as_Allocator();
dynamicAdjustment();
}
@ -220,7 +221,6 @@ namespace test {
* the additional metadata overhead is a power of two, exploiting contextual knowledge
* about layout; moreover, a special usage-mode allows to skip invocation of destructors.
* To document these machinations, change to internal data is explicitly verified here.
* @todo WIP 5/24 define implement
*/
void
verifyInternals()
@ -397,7 +397,7 @@ namespace test {
AllocationCluster clu;
CHECK (clu.numExtents() == 0);
VecI veci{clu.getAllocator<uint16_t>()};
VecI vecI{clu.getAllocator<uint16_t>()};
// Since vector needs a contiguous allocation,
// the maximum number of elements is limited by the Extent size (256 bytes - 2*sizeof(void*))
@ -406,20 +406,91 @@ namespace test {
const uint MAX = 64;
for (uint i=1; i<=MAX; ++i)
veci.push_back(i);
vecI.push_back(i);
CHECK (clu.numExtents() == 2);
CHECK (veci.capacity() == 64);
CHECK (vecI.capacity() == 64);
// fill a set with random strings...
SetS sets{clu.getAllocator<Strg>()};
SetS setS{clu.getAllocator<Strg>()};
for (uint i=0; i<NUM_OBJECTS; ++i)
sets.emplace (test::randStr(32), clu.getAllocator<char>());
CHECK (sets.size() > 0.9 * NUM_OBJECTS);
setS.emplace (test::randStr(32), clu.getAllocator<char>());
CHECK (setS.size() > 0.9 * NUM_OBJECTS);
CHECK (clu.numExtents() > 200);
// verify the data in the first allocation is intact
CHECK (explore(veci).resultSum() == sum(64));
CHECK (explore(vecI).resultSum() == sum(64));
}
/** @test verify the ability to adjust the latest allocation dynamically.
*/
void
dynamicAdjustment()
{
AllocationCluster clu;
auto& l1 = clu.create<array<uchar,12>>();
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 12);
auto& l2 = clu.create<array<uchar,5>>();
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 17);
CHECK ( clu.canAdjust (&l2, 5, 8)); // possible since l2 is verifiable as last allocation
CHECK ( clu.canAdjust (&l2, 5, 5)); // arbitrary adjustments are then possible
CHECK ( clu.canAdjust (&l2, 5, 2));
CHECK ( clu.canAdjust (&l2, 5, 0)); // even shrinking to zero
CHECK (not clu.canAdjust (&l1, 12,24)); // but the preceding allocation can not be changed anymore
CHECK (not clu.canAdjust (&l2, 6, 8)); // similarly, reject requests when passing wrong original size
CHECK (not clu.canAdjust (&l2, 4, 8));
CHECK (not clu.canAdjust (&l2, 5, 1000)); // also requests exceeding the remaining extent space are rejected
CHECK ( clu.canAdjust (&l1, 17,24)); // however, can not detect if a passed wrong size accidentally matches
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 17);
l1[11] = 11; // put some marker values into the storage
l2[0] = 5;
l2[1] = 4;
l2[2] = 3;
l2[3] = 2;
l2[4] = 1;
l2[5] = 55; // yes, even behind the valid range (subscript is unchecked)
l2[6] = 66;
using LERR_(INVALID);
VERIFY_ERROR (INVALID, clu.doAdjust(&l1, 12,24) );
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 17);
// perform a size adjustment on the latest allocation
clu.doAdjust (&l2, 5,12);
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 24);
// no memory corruption
CHECK (l1[11] == 11);
CHECK (l2[0] == 5);
CHECK (l2[1] == 4);
CHECK (l2[2] == 3);
CHECK (l2[3] == 2);
CHECK (l2[4] == 1);
CHECK (l2[5] == 55);
CHECK (l2[6] == 66);
// scale down the latest allocation completely
clu.doAdjust (&l2, 12,0);
CHECK (clu.numExtents() == 1);
CHECK (clu.numBytes() == 12);
// no memory corruption
CHECK (l1[11] == 11);
CHECK (l2[0] == 5);
CHECK (l2[1] == 4);
CHECK (l2[2] == 3);
CHECK (l2[3] == 2);
CHECK (l2[4] == 1);
CHECK (l2[5] == 55);
CHECK (l2[6] == 66);
}
};

View file

@ -81325,9 +81325,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715526412553" ID="ID_1310310561" MODIFIED="1715526457239" TEXT="bietet zus&#xe4;tzlich die F&#xe4;higkeit zur inplace-Allokation"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1715530825487" ID="ID_744922331" MODIFIED="1715530828707" TEXT="Design">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1715530839818" ID="ID_1299414083" MODIFIED="1715530843266" TEXT="Analyse">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1715530844562" ID="ID_598901793" MODIFIED="1715530852442" TEXT="warum nicht einen Vector?">
<node COLOR="#338800" CREATED="1715530839818" FOLDED="true" ID="ID_1299414083" MODIFIED="1718320555733" TEXT="Analyse">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1715530844562" ID="ID_598901793" MODIFIED="1718320534356" TEXT="warum nicht einen Vector?">
<icon BUILTIN="help"/>
<node CREATED="1715530856096" ID="ID_1985014876" MODIFIED="1715530876386" TEXT="im Grunde brauchen wir ein Array"/>
<node CREATED="1715530878893" ID="ID_155576825" MODIFIED="1715530901590" TEXT="das Vector-Interface ist zu m&#xe4;chtig (und zu konkret)"/>
@ -81346,11 +81346,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_cancel"/>
</node>
</node>
<node CREATED="1715532455035" ID="ID_1288992537" MODIFIED="1715532458010" TEXT="ich m&#xf6;chte">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1715532455035" ID="ID_1288992537" MODIFIED="1718320531044" TEXT="ich m&#xf6;chte">
<icon BUILTIN="yes"/>
<node CREATED="1715532458922" ID="ID_716858129" MODIFIED="1715532474934" TEXT="Zugriff auf bestehende Elemente"/>
<node CREATED="1715532475464" ID="ID_618278235" MODIFIED="1715532480906" TEXT="Elemente sind aber non-const"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1715532483303" ID="ID_622474774" MODIFIED="1715532787640" TEXT="konkreter Element-Typ kann erased sein?">
<icon BUILTIN="help"/>
<node CREATED="1715532483303" ID="ID_622474774" MODIFIED="1718320526176" TEXT="konkreter Element-Typ kann erased sein">
<icon BUILTIN="forward"/>
</node>
<node CREATED="1715532503700" ID="ID_1038248531" MODIFIED="1715532511472" TEXT="L&#xe4;nge als State"/>
<node CREATED="1715532672941" ID="ID_1970537209" MODIFIED="1715532683208" TEXT="feste Gr&#xf6;&#xdf;e (unabh&#xe4;ngig von Element-Storage)"/>
@ -81383,7 +81384,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node CREATED="1715532630466" ID="ID_169592902" MODIFIED="1715533548154" TEXT="mu&#xdf; dazu passenden Builder konzipieren...">
<font NAME="SansSerif" SIZE="12"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1715532833936" ID="ID_1009009693" MODIFIED="1715532840949" TEXT="Problem: Link zum Allocator">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1715532833936" ID="ID_1009009693" MODIFIED="1718320501473" TEXT="Problem: Link zum Allocator">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1715532843871" ID="ID_774375232" MODIFIED="1715532859150" TEXT="entweder der Allocator wird als Pointer mitgeschleppt">
<node CREATED="1715532914728" ID="ID_1541420443" MODIFIED="1715532932838" TEXT="erfordert entweder separates Allocator-Objekt"/>
@ -81411,7 +81412,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715533107500" ID="ID_1456027641" MODIFIED="1715533121838" TEXT="idealerweise Wachstumsf&#xe4;higkeit wie ein Vector"/>
<node CREATED="1715533124273" ID="ID_508327678" MODIFIED="1715533140797" TEXT="Inhalt eines Vectors komplett per move &#xfc;bernehmen"/>
<node CREATED="1715533141623" ID="ID_1757204023" MODIFIED="1715533168654" TEXT="Inhalt eines Array komplett &#xfc;bernehmen"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1715533192160" ID="ID_1324375347" MODIFIED="1715533214590" TEXT="Problem: deleter / braucht impliziten Link zum Allocator">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1715533192160" ID="ID_1324375347" MODIFIED="1718320493417" TEXT="Problem: deleter / braucht impliziten Link zum Allocator">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1715533228879" ID="ID_1909155403" MODIFIED="1715533251166" TEXT="der Destruktor mu&#xdf; wissen wie der Storage-Block freizugeben ist"/>
<node CREATED="1715533251792" ID="ID_1479555840" MODIFIED="1715533283445" TEXT="u.u. mu&#xdf; &#xfc;berhaupt keine Freigabe gemacht werden">
@ -81502,7 +81503,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<head/>
<body>
<p>
...man verwendet <i>nur speziell im produktiven Einsatz im Node-Graph</i>&#160; einen besonderen Allocator, der zwar den Destruktor aufruft, aber den Speicher nicht freigibt; alloziert wird immer in einen kompakten Block hinein, der dann auf der Basis der Proze&#223;-Kenntnis als Ganzes verworfen und neu verwendet wird.
...man verwendet <i>nur speziell im produktiven Einsatz im Node-Graph</i> einen besonderen Allocator, der zwar den Destruktor aufruft, aber den Speicher nicht freigibt; alloziert wird immer in einen kompakten Block hinein, der dann auf der Basis der Proze&#223;-Kenntnis als Ganzes verworfen und neu verwendet wird.
</p>
</body>
</html></richcontent>
@ -81661,7 +81662,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1715627027263" ID="ID_1272289707" MODIFIED="1716848766314" TEXT="Aufgabe: den Standard-Allocator besser verstehen">
<node COLOR="#435e98" CREATED="1715627027263" FOLDED="true" ID="ID_1272289707" MODIFIED="1716848766314" TEXT="Aufgabe: den Standard-Allocator besser verstehen">
<icon BUILTIN="yes"/>
<node CREATED="1715627069918" ID="ID_1496924967" MODIFIED="1715627170299" TEXT="es k&#xf6;nnte n&#xe4;mlich eine Konvergenz geben">
<richcontent TYPE="NOTE"><html>
@ -82642,11 +82643,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717777116726" ID="ID_1692491444" MODIFIED="1717777127002" TEXT="resize mit Element-Typ">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1717777116726" ID="ID_1692491444" MODIFIED="1718320365056" TEXT="resize mit Element-Typ">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717777127619" ID="ID_42350747" MODIFIED="1717777133490" TEXT="resize auf gegebenen Spread">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1717777127619" ID="ID_42350747" MODIFIED="1718320366608" TEXT="resize auf gegebenen Spread">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717777134500" ID="ID_1083429601" MODIFIED="1717777151106" TEXT="shrink-to-fit">
<icon BUILTIN="flag-yellow"/>
@ -82831,9 +82832,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
<node CREATED="1718212749620" ID="ID_1659701829" MODIFIED="1718213228515">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
sonst w&#252;rde eine Spread-Vergr&#246;&#223;erung
@ -82842,12 +82841,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
tats&#228;chlich die Reserve <i>verkleinern...</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -82876,8 +82872,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<u>Begr&#252;ndung</u>: das ganze Thema &#187;spread&#171; ist extrem technisch und f&#252;r den Nutzer normalerweise nicht nachvollziehbar, aber die Kapazit&#228;t in Anzahl der freien Slots ist sehr wohl verst&#228;ndlich f&#252;r den User; es w&#228;re also <i>ziemlich &#252;berraschend</i>&#160;wenn &#8212; scheinbar ohne ersichtlichen Grund &#8212; pl&#246;tzlich die Reserve-Kapazit&#228;t verschwunden w&#228;re.
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node COLOR="#338800" CREATED="1717893967870" ID="ID_1707818601" MODIFIED="1717894043447" TEXT="Spread-Anpassung zweistufig">
@ -82970,8 +82965,18 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718328808453" ID="ID_119150059" MODIFIED="1718328816482" TEXT="Spezialisierung f&#xfc;r AllocationCluster">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1718328836352" ID="ID_456408300" MODIFIED="1718328872260" TEXT="Trigger: der Standard-Allocator-Adapter von AllocationCluster">
<icon BUILTIN="info"/>
</node>
<node COLOR="#435e98" CREATED="1717770993835" ID="ID_1878698297" MODIFIED="1718073615124" TEXT="Problem: Gr&#xf6;&#xdf;e der Basis-Allokation">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718328650553" ID="ID_1053724868" MODIFIED="1718328832230" TEXT="dynamische Allokations-&#xc4;nderung einbinden">
<arrowlink COLOR="#415ab7" DESTINATION="ID_1869643772" ENDARROW="Default" ENDINCLINATION="-1433;-63;" ID="Arrow_ID_166309661" STARTARROW="None" STARTINCLINATION="1447;92;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1717770993835" FOLDED="true" ID="ID_1878698297" MODIFIED="1718073615124" TEXT="Problem: Gr&#xf6;&#xdf;e der Basis-Allokation">
<linktarget COLOR="#6045d8" DESTINATION="ID_1878698297" ENDARROW="Default" ENDINCLINATION="13;-122;" ID="Arrow_ID_605494253" SOURCE="ID_916393989" STARTARROW="None" STARTINCLINATION="-437;29;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1717771028662" ID="ID_1266328566" MODIFIED="1717771040728" TEXT="diese k&#xf6;nnte....">
@ -82994,16 +82999,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1717771200623" ID="ID_79846525" MODIFIED="1717771208658" TEXT="trotzdem &#xe4;rgerlich">
<node CREATED="1717771319363" ID="ID_165772412" MODIFIED="1718206065687" TEXT="weil es f&#xfc;r den Haupt-Anwendungsfall gar nicht gebraucht wird">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
denn der Allocation-Cluster wei&#223; selber die Zahl seiner belegten Roh-Bl&#246;cke; zur de-Allokation mu&#223; ansonsten gar nichts gemacht werden
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1717771640460" ID="ID_1646507168" MODIFIED="1717771661118" TEXT="weil die Datenstruktur doch so sch&#xf6;n elegant sein sollte....">
<icon BUILTIN="smiley-oh"/>
@ -83192,8 +83194,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716914886169" ID="ID_505410227" MODIFIED="1716914902542" TEXT="&#xc4;nderung Spread">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#5b280f" CREATED="1716914886169" ID="ID_505410227" MODIFIED="1718297612308" TEXT="&#xc4;nderung Spread">
<icon BUILTIN="button_cancel"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1718297613563" HGAP="24" ID="ID_516072366" MODIFIED="1718297623575" TEXT="YAGNI" VSHIFT="4">
<icon BUILTIN="hourglass"/>
</node>
</node>
<node COLOR="#338800" CREATED="1716914892972" ID="ID_1080699305" MODIFIED="1718147544739" TEXT="Platzieren neuer Daten">
<icon BUILTIN="button_ok"/>
@ -83220,9 +83225,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716936138265" ID="ID_344813639" MODIFIED="1716936143886" TEXT="Allokations-Policies">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1716936150419" ID="ID_442325434" MODIFIED="1716936174356" TEXT="HeapOwn">
<node CREATED="1716936175678" ID="ID_1766388404" MODIFIED="1716936183114" TEXT="die C-Funktionen nutzen (wegen realloc)"/>
<node CREATED="1716936231944" ID="ID_1000807546" LINK="https://en.cppreference.com/w/cpp/memory/c/realloc" MODIFIED="1716936247901" TEXT="Doku std::realloc()">
<icon BUILTIN="info"/>
<node CREATED="1716936175678" ID="ID_1766388404" MODIFIED="1718320002038" TEXT="verwendet die Standard-AllocationPolicy"/>
<node CREATED="1718320003314" ID="ID_1600782840" MODIFIED="1718320016768" TEXT="setzt in diese den std::allocator&lt;byte&gt; ein"/>
<node CREATED="1718320035606" ID="ID_267945187" MODIFIED="1718320065582" TEXT="&#x27f9; der Deleter im ArrayBucket wird ElementFactory::delete() aufrufen">
<node CREATED="1718320072353" ID="ID_1223722656" MODIFIED="1718320095882" TEXT="hierdurch werden der Reihe nach die Elemente an den Allokator zur Zerst&#xf6;rung gebracht"/>
<node CREATED="1718320100357" ID="ID_1051852408" MODIFIED="1718320160945" TEXT="danach wird das ArrayBucket selber nicht zerst&#xf6;rt (das passiert schon vom lib::Several aus)"/>
<node CREATED="1718320162597" ID="ID_1683490945" MODIFIED="1718320193995" TEXT="sondern nur noch die low-level Storage f&#xfc;r den Array-Datenpuffer freigegeben"/>
</node>
</node>
</node>
@ -83231,8 +83239,31 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1718147568653" ID="ID_175737075" MODIFIED="1718147586344" TEXT="makeSeveral ( initializer_list )">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718147641688" ID="ID_866349389" MODIFIED="1718147693481" TEXT="makeSeveral&lt;TY&gt; (elms...)">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1718298480031" ID="ID_937591590" MODIFIED="1718298490716" TEXT="makeSeveral&lt;I,E&gt;()">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1718147641688" ID="ID_866349389" MODIFIED="1718298475923" TEXT="makeSeveral&lt;TY&gt; (elms...)">
<icon BUILTIN="hourglass"/>
<node CREATED="1718298492724" ID="ID_1330684020" MODIFIED="1718298598007" TEXT="hier k&#xf6;nne man einiges an &#xbb;Intelligenz&#xab; einbauen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...im Besonderen k&#246;nnte man den std::common_type verwenden, um ein m&#246;gliches Interface zu inferieren, und zudem einen gemeinsamen Element-Typ zu erkennen...
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1718298506332" ID="ID_1158180092" MODIFIED="1718298677922" TEXT="bezweifle aber derzeit, da&#xdf; das f&#xf6;rderlich ist">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...denn lib::Several ist ein ziemlich trickreicher low-level-Container; es k&#246;nnte gef&#228;hrlich werden, wenn man beliebige Typ-Parameter verwendet; insofern ist es nicht w&#252;nschenswert, dem User das explizite W&#228;hlen der Typ-Parameter zu ersparen (abgesehen von dem einfachen Fall mit der Initializer-list)
</p>
</body>
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1718147675355" ID="ID_1373098366" MODIFIED="1718147685899" TEXT="sinnvolle Syntax f&#xfc;r Allokator??">
<icon BUILTIN="help"/>
@ -83645,8 +83676,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716857382441" ID="ID_1397767362" MODIFIED="1718219037095" TEXT="check_ElementStorage">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1716857382441" ID="ID_1397767362" MODIFIED="1718298219855" TEXT="check_ElementStorage">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1718290606176" ID="ID_1457988951" MODIFIED="1718290634409" TEXT="grunds&#xe4;tzlich: Platzierung mit gleichm&#xe4;&#xdf;igem Spread">
<icon BUILTIN="button_ok"/>
</node>
@ -83666,8 +83697,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
</node>
</node>
<node CREATED="1718202490965" ID="ID_247674037" MODIFIED="1718206085439" TEXT="Handhabung von non-copyable-Objekten">
<node COLOR="#338800" CREATED="1718202490965" ID="ID_247674037" MODIFIED="1718297858099" TEXT="Handhabung von non-copyable-Objekten">
<linktarget COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-777;-16;" ID="Arrow_ID_10606647" SOURCE="ID_1146034926" STARTARROW="None" STARTINCLINATION="-438;67;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716857382442" ID="ID_28139752" MODIFIED="1716857402101" TEXT="check_CustomAllocator">
@ -84302,6 +84334,39 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1718320662514" ID="ID_1230271493" MODIFIED="1718328703884" TEXT="dynamische re-Allokation in Grenzen erm&#xf6;glichen">
<icon BUILTIN="button_ok"/>
<node CREATED="1718320687487" ID="ID_633607607" MODIFIED="1718320721888" TEXT="Feature speziell f&#xfc;r die Render-Engine">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Und zwar weil sich aus der konkreten Implementierung diese M&#246;glichkeit einfach ergibt
</p>
</body>
</html>
</richcontent>
</node>
<node COLOR="#435e98" CREATED="1718320726218" ID="ID_1869643772" MODIFIED="1718328832230" TEXT="wird im Besonderen von lib::Several &#xfc;ber einen dedizierte Policy genutzt">
<linktarget COLOR="#415ab7" DESTINATION="ID_1869643772" ENDARROW="Default" ENDINCLINATION="-1433;-63;" ID="Arrow_ID_166309661" SOURCE="ID_1053724868" STARTARROW="None" STARTINCLINATION="1447;92;"/>
<icon BUILTIN="info"/>
</node>
<node CREATED="1718320753278" ID="ID_517105268" MODIFIED="1718320773100" TEXT="Idee: den jeweils letzten Block kann man noch &#xbb;flicken&#xab;">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1718320776115" ID="ID_658099032" MODIFIED="1718320779891" TEXT="Implementierung">
<node COLOR="#338800" CREATED="1718320780738" ID="ID_228969406" MODIFIED="1718328621566" TEXT="M&#xf6;glichkeit erkennen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1718320785785" ID="ID_1660113692" MODIFIED="1718328621567" TEXT="Anpassung vornehmen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1718320861990" ID="ID_1106019475" MODIFIED="1718328618246" TEXT="testen...">
<arrowlink COLOR="#7aa9ba" DESTINATION="ID_1762316214" ENDARROW="Default" ENDINCLINATION="-502;-27;" ID="Arrow_ID_1080500991" STARTARROW="None" STARTINCLINATION="-365;86;"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node COLOR="#338800" CREATED="1715725950719" FOLDED="true" ID="ID_1150594476" MODIFIED="1716848654942" TEXT="Testf&#xe4;lle vereinfachen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1715782655513" ID="ID_563670116" MODIFIED="1716837163217" TEXT="Basis-Testf&#xe4;lle anpassen">
@ -84396,6 +84461,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1718320844138" ID="ID_1762316214" MODIFIED="1718328710748" TEXT="zus&#xe4;tzlicher Test zur dynamischen Allokations-Anpassung">
<linktarget COLOR="#7aa9ba" DESTINATION="ID_1762316214" ENDARROW="Default" ENDINCLINATION="-502;-27;" ID="Arrow_ID_1080500991" SOURCE="ID_1106019475" STARTARROW="None" STARTINCLINATION="-365;86;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716848462075" ID="ID_1540153344" MODIFIED="1716848472810" TEXT="Node-Factory initial zum Laufen bekommen">