Library: better alignment handling
Elements maintained within the storage should be placed such as to comply with their alignment requirements; the element spacing thus must be increased to be a multiple of the given type's alignment. This solution works in most common cases, where the alignement is not larger as the platform's bus width (typically 64bit); but for ''over-aligned types'' this scheme may still generate wrong object start positions (a completely correct solution would require to add a fixed offset to the beginning of the storage array and also to capture the alignment requirements during population and to re-check for each new type.
This commit is contained in:
parent
66a1f6f8ab
commit
6f3bfb5ff3
3 changed files with 176 additions and 24 deletions
|
|
@ -21,19 +21,31 @@
|
|||
*/
|
||||
|
||||
/** @file several-builder.hpp
|
||||
** Some (library-) implementations of the RefArray interface.
|
||||
** Builder to create and populate instances of the lib::Several container.
|
||||
** For mere usage, inclusion of several.hpp should be sufficient, since the
|
||||
** container front-end is generic and intends to hide most details of allocation
|
||||
** and element placement. It is an array-like container, but may hold subclass
|
||||
** elements, while exposing only a reference to the interface type.
|
||||
**
|
||||
** Being an array-like object exposing just a const ref, it is typically used
|
||||
** on interfaces, and the type of the array "elements" usually is a ABC or interface.
|
||||
** The actual implementation typically holds a subclass, and is either based on a vector,
|
||||
** or a fixed storage contained within the implementation. The only price to pay is
|
||||
** a virtual call on element access.
|
||||
** # Implementation data layout
|
||||
**
|
||||
** For advanced uses it would be possible to have a pointer-array or even an embedded
|
||||
** storage of variant-records, able to hold a mixture of subclasses. (the latter cases
|
||||
** will be implemented when needed).
|
||||
** The front-end container lib::Several<I> is actually just a smart-ptr referring
|
||||
** to the actual data storage, which resides within an _array bucket._ Typically
|
||||
** the latter is placed into memory managed by a custom allocator, most notably
|
||||
** lib::AllocationCluster. However, by default, the ArrayBucket<I> will be placed
|
||||
** into heap memory. All further meta information is also maintained alongside
|
||||
** this data allocation, including a _deleter function_ to invoke all element
|
||||
** destructors and de-allocate the bucket itself. Neither the type of the
|
||||
** actual elements, nor the type of the allocator is revealed.
|
||||
**
|
||||
** @warning WIP and in rework 5/2025 -- not clear yet where this design leads to...
|
||||
** Since the actual data elements can (optionally) be of a different type than
|
||||
** the exposed interface type \a I, additional storage and spacing is required
|
||||
** in the element array. The field ArrayBucket<I>::spread defines this spacing
|
||||
** and thus the offset used for subscript access.
|
||||
**
|
||||
** @todo this is a first implementation solution from 6/2025 — and was deemed
|
||||
** _roughly adequate_ at that time, yet should be revalidated once more
|
||||
** observations pertaining real-world usage are available...
|
||||
** @see several-builder-test.cpp
|
||||
**
|
||||
*/
|
||||
|
|
@ -79,6 +91,26 @@ namespace lib {
|
|||
using util::_Fmt;
|
||||
using std::is_trivially_destructible_v;
|
||||
|
||||
/**
|
||||
* Helper to determine the »spread« required to hold
|
||||
* elements of type \a TY in memory _with proper alignment._
|
||||
* @warning assumes that the start of the buffer is also suitably aligned,
|
||||
* which _may not be the case_ for **over-aligned objects** with
|
||||
* `alignof(TY) > alignof(void*)`
|
||||
*/
|
||||
template<typename TY>
|
||||
size_t inline constexpr
|
||||
reqSiz()
|
||||
{
|
||||
size_t quant = alignof(TY);
|
||||
size_t siz = max (sizeof(TY), quant);
|
||||
size_t req = (siz/quant) * quant;
|
||||
if (req < siz)
|
||||
req += quant;
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
template<class I, template<typename> class ALO>
|
||||
class ElementFactory
|
||||
: private ALO<std::byte>
|
||||
|
|
@ -371,7 +403,7 @@ namespace lib {
|
|||
SeveralBuilder&&
|
||||
reserve (size_t cntElm)
|
||||
{
|
||||
adjustStorage (cntElm, sizeof(E));
|
||||
adjustStorage (cntElm, reqSiz<E>());
|
||||
return move(*this);
|
||||
}
|
||||
|
||||
|
|
@ -406,19 +438,19 @@ namespace lib {
|
|||
handling_.template probeMoveCapability<TY>();
|
||||
|
||||
// ensure sufficient element capacity or the ability to adapt element spread
|
||||
if (Coll::spread() < sizeof(TY) and not (Coll::empty() or handling_.canWildMove()))
|
||||
if (Coll::spread() < reqSiz<TY>() and not (Coll::empty() or handling_.canWildMove()))
|
||||
throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)"
|
||||
"into container for element size %d."}
|
||||
% util::typeStr<TY>() % sizeof(TY) % Coll::spread()};
|
||||
% util::typeStr<TY>() % reqSiz<TY>() % Coll::spread()};
|
||||
|
||||
// ensure sufficient storage or verify the ability to re-allocate
|
||||
if (not (Coll::hasReserve(sizeof(TY))
|
||||
or POL::canExpand(sizeof(TY))
|
||||
if (not (Coll::hasReserve(reqSiz<TY>())
|
||||
or POL::canExpand(reqSiz<TY>())
|
||||
or not handling_.lock_move))
|
||||
throw err::Invalid{_Fmt{"Unable to accommodate further element of type %s "}
|
||||
% util::typeStr<TY>()};
|
||||
|
||||
size_t elmSiz = sizeof(TY);
|
||||
size_t elmSiz = reqSiz<TY>();
|
||||
size_t newPos = Coll::size();
|
||||
size_t newCnt = Coll::empty()? INITIAL_ELM_CNT : newPos+1;
|
||||
adjustStorage (newCnt, max (elmSiz, Coll::spread()));
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace lib {
|
|||
Deleter deleter;
|
||||
|
||||
/** mark start of the storage area */
|
||||
alignas(I)
|
||||
alignas(void*)
|
||||
std::byte storage[sizeof(I)];
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81733,6 +81733,110 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1718035817292" ID="ID_908227037" MODIFIED="1718035826853" TEXT="Verwendungen von sizeof(TY)">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1718063961925" ID="ID_277616136" MODIFIED="1718064002838" TEXT="naiv ist nicht korrekt �� Vorsicht Falle">
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
<node CREATED="1718064017691" ID="ID_725413485" MODIFIED="1718064045946" TEXT="Alignment : Objekt muß an Einheiten dieser Größe ausgerichtet sein">
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
<node CREATED="1718064049623" ID="ID_442869624" MODIFIED="1718064442102">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
unser Storage-Puffer ist alignas(I) — das kann <b>zu locker</b> sein für das tatsächliche Objekt
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<u>Beispiel</u>: <b><font face="Monospaced" color="#560799">I</font></b> ist eine leere Klasse, hat also sizeof(<b><font face="Monospaced" color="#560799">I</font></b>) ≡ alignof(<b><font face="Monospaced" color="#560799">I</font></b>) ≡ 1
|
||||
</p>
|
||||
<p>
|
||||
Wenn's dumm läuft, kann der Puffer mit jedem beliebigen Byte-Offset beginnen z.B. 3
|
||||
</p>
|
||||
<p>
|
||||
Nun platzieren wir aber eine Subklasse mit alignof(<b><font face="Monospaced" color="#990761">E</font></b>) ≡ 8 und sizeof(<b><font face="Monospaced" color="#990761">E</font></b>) ≡ 12
|
||||
</p>
|
||||
<p>
|
||||
⟹ die naive Lösung beginnt bei offset ≔ 3 und fügt für jeden Index +12 Bytes hinzu; damit sind <b>alle Objekte grob falsch ausgerichtet</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1718064447034" ID="ID_627454107" MODIFIED="1718064453581" TEXT="korrekt wäre...">
|
||||
<node CREATED="1718064454689" ID="ID_901534814" MODIFIED="1718064478465" TEXT="Anfang des Puffers am Anlignment der Elemente ausrichten"/>
|
||||
<node CREATED="1718064513825" ID="ID_1012833549" MODIFIED="1718064534602" TEXT="Spread auf das nächst größere Vielfache des Element-Alignments aufrunden"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718064594684" ID="ID_1754699530" MODIFIED="1718064617404" TEXT="Subskript und Platzierung korrekt machen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1718064618803" ID="ID_371062072" MODIFIED="1718064688256">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
man könnte das nun <i>ungenau </i>oder <i>punktgenau</i> oder <i>grob korrekt </i>handhaben 
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1718064742835" ID="ID_871080765" MODIFIED="1718064754941" TEXT="»grob korrekt«">
|
||||
<node CREATED="1718064756929" ID="ID_1870004223" MODIFIED="1718064798319" TEXT="wähle für den Puffer das Alignment eines void* (»slot«)"/>
|
||||
<node CREATED="1718064809954" ID="ID_79404905" MODIFIED="1718064835981" TEXT="runde den Spread korrekt auf gemäß Element-Alignment"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1718064840726" ID="ID_1507935794" MODIFIED="1718065973474" TEXT="Problem: over-aligned objects werden nicht korrekt gehandhabt">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1718064941728" ID="ID_710097250" MODIFIED="1718064947808" TEXT="»punktgenau«">
|
||||
<node CREATED="1718064950567" ID="ID_1541540344" MODIFIED="1718065006412" TEXT="speichere das Alignment zusätzlich im ArrayBucket"/>
|
||||
<node CREATED="1718065008351" ID="ID_1578479705" MODIFIED="1718065125011" TEXT="erzeuge einen Offset um das Alignment des Puffer-Start zu korrigieren"/>
|
||||
<node CREATED="1718065126264" ID="ID_1984046754" MODIFIED="1718065139274" TEXT="runde den Spread korrekt auf gemäß Element-Alignment"/>
|
||||
<node CREATED="1718065140862" ID="ID_1650291817" MODIFIED="1718065183602" TEXT="prüfe neben der Größe auch das Alignment jeden neuen Elements"/>
|
||||
<node CREATED="1718065924757" ID="ID_488968875" MODIFIED="1718065956907" TEXT="Alignement-Änderung ablehnen wenn bereits nicht-verschiebbare Objekte im Container liegen"/>
|
||||
<node CREATED="1718066029399" ID="ID_1788091685" MODIFIED="1718066036442" TEXT="Schwierigkeiten">
|
||||
<node CREATED="1718066039054" ID="ID_1592410821" MODIFIED="1718066057551" TEXT="das Schema ist komplex zu implementieren"/>
|
||||
<node CREATED="1718066058875" ID="ID_524666316" MODIFIED="1718066089035" TEXT="das Alignment muß zwingend gespeichert werden (um Änderungen zu erkennen)"/>
|
||||
<node CREATED="1718066107397" ID="ID_539782163" MODIFIED="1718066130765" TEXT="den Offset sollte man ebenfalls speicheren um den Subscript zu beschleunigen"/>
|
||||
<node CREATED="1718066219574" ID="ID_712639460" MODIFIED="1718066247894" TEXT="die Rolle des Datenfelds storage wird schwer verständlich"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1718066280938" ID="ID_1639960105" MODIFIED="1718066299686" TEXT="Beschluß: »punktgenau« wird auf später verschoben">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1718066307946" ID="ID_1884364301" MODIFIED="1718066372700" TEXT="die mögliche Falle mit overaligned objects wird in Kauf genommen">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1718066332967" ID="ID_1686673435" MODIFIED="1718066368819" TEXT="im Rahmen einer späteren Überarbeitung der Bucket-Storage darüber nochmal nachdenken">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718066378097" ID="ID_1766969093" MODIFIED="1718067200842" TEXT="Anpassungen am Code (»grob korrekt«)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1718066394480" ID="ID_326301567" MODIFIED="1718067158583" TEXT="Puffer-Alignment ⟶ void*">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718066404826" ID="ID_239748067" MODIFIED="1718067196230" TEXT="Hilfsfunktion reqSiz<TY>()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718067163803" ID="ID_1053644006" MODIFIED="1718067198266" TEXT=""sizeof(TY)" ⟼ reqSiz<TY>()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718067214231" ID="ID_1276439764" LINK="#ID_1830672111" MODIFIED="1718067239581" TEXT="testen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716901426183" ID="ID_1212967398" MODIFIED="1716901442101" TEXT="Element-Zugriff und Iteration">
|
||||
|
|
@ -81854,8 +81958,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1717797674913" ID="ID_1290234834" MODIFIED="1718038739053" TEXT="Iteration">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1717797674913" ID="ID_1290234834" MODIFIED="1718062292947" TEXT="Iteration">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1717797702893" ID="ID_1535587090" MODIFIED="1718040020040" TEXT="Layout">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1718038819461" ID="ID_834949267" MODIFIED="1718038892881" TEXT="wird wohl eine State-Core-Impl">
|
||||
|
|
@ -81884,11 +81988,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718040049417" ID="ID_360730872" MODIFIED="1718040052952" TEXT="einbauen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1718040049417" ID="ID_360730872" MODIFIED="1718062160943" TEXT="einbauen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717797709076" ID="ID_1453437458" MODIFIED="1718062162753" TEXT="const-Iterator">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1718062164811" ID="ID_1792709896" MODIFIED="1718062223389">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
einfach ein <font face="Monospaced" color="#68360d">lib::IterIndex<</font><font face="Monospaced" color="#9b1905">const</font><font face="Monospaced" color="#68360d"> </font><font face="Monospaced" color="#7e1040">Several<X></font><font face="Monospaced" color="#68360d">></font>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717797709076" ID="ID_1453437458" MODIFIED="1717797713403" TEXT="const-Iterator">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -81928,7 +82045,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1716907312241" ID="ID_835337350" MODIFIED="1716912483271" TEXT="umspannt den Anfang vom Storage-Array"/>
|
||||
<node COLOR="#338800" CREATED="1716907356091" ID="ID_1876919425" MODIFIED="1716912200686" TEXT="enthält den subscript-Code">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1716912163674" ID="ID_581123494" MODIFIED="1716912528793" TEXT="muß hier einen offenen Zugriff hinter das Objektende machen">
|
||||
<node BACKGROUND_COLOR="#dbb34e" COLOR="#7d1d3e" CREATED="1716912163674" ID="ID_581123494" MODIFIED="1718062360235" TEXT="muß hier einen offenen Zugriff hinter das Objektende machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -83171,6 +83288,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716857382441" ID="ID_1397767362" MODIFIED="1716857402102" TEXT="check_ElementAccess">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718067224015" ID="ID_1830672111" MODIFIED="1718067235928" TEXT="Alignment-Behandlung verifizieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716857382442" ID="ID_28139752" MODIFIED="1716857402101" TEXT="check_CustomAllocator">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue