Library: rework handling of resize and spread changes
- spread change now retains the nominal element reserve - `capacity()` and `capReserve()` now exposed on the builder API - factor out the handling check safety functions - rewrite the `resize()` builder function to be more generic __Test now covers__ example with trivial data type, which can indeed be resized and allows to grow buffer on-the fly without requiring any knowledge of the actual type (due to using `memmove`)
This commit is contained in:
parent
89dd35e70d
commit
00287360be
4 changed files with 159 additions and 34 deletions
|
|
@ -299,10 +299,15 @@ namespace lib {
|
|||
|
||||
/* ===== Builder API ===== */
|
||||
|
||||
template<typename TY =E>
|
||||
SeveralBuilder&&
|
||||
reserve (size_t cntElm)
|
||||
reserve (size_t cntElm =1
|
||||
,size_t elmSiz =reqSiz<TY>())
|
||||
{
|
||||
adjustStorage (cntElm, reqSiz<E>());
|
||||
ensureElementCapacity<TY> (elmSiz);
|
||||
ensureStorageCapacity<TY> (elmSiz,cntElm);
|
||||
elmSiz = max (elmSiz, Coll::spread());
|
||||
adjustStorage (cntElm, elmSiz);
|
||||
return move(*this);
|
||||
}
|
||||
|
||||
|
|
@ -365,8 +370,10 @@ namespace lib {
|
|||
return move (*this);
|
||||
}
|
||||
|
||||
size_t size() const { return Coll::size(); }
|
||||
bool empty() const { return Coll::empty();}
|
||||
size_t size() const { return Coll::size(); }
|
||||
bool empty() const { return Coll::empty();}
|
||||
size_t capacity() const { return Coll::storageBuffSiz() / Coll::spread(); }
|
||||
size_t capReserve() const { return capacity() - size(); }
|
||||
|
||||
|
||||
private:
|
||||
|
|
@ -384,23 +391,9 @@ namespace lib {
|
|||
{
|
||||
static_assert (is_object_v<TY> and not (is_const_v<TY> or is_volatile_v<TY>));
|
||||
|
||||
// mark when target type is not trivially movable
|
||||
probeMoveCapability<TY>();
|
||||
|
||||
// ensure sufficient element capacity or the ability to adapt element spread
|
||||
if (Coll::spread() < reqSiz<TY>() and not (Coll::empty() or canWildMove()))
|
||||
throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)"
|
||||
"into Several-container for element size %d."}
|
||||
% util::typeStr<TY>() % reqSiz<TY>() % Coll::spread()};
|
||||
|
||||
// ensure sufficient storage or verify the ability to re-allocate
|
||||
if (not (Coll::empty() or Coll::hasReserve(reqSiz<TY>())
|
||||
or POL::canExpand(reqSiz<TY>())
|
||||
or canDynGrow()))
|
||||
throw err::Invalid{_Fmt{"Several-container is unable to accommodate further element of type %s; "
|
||||
"storage reserve (%s bytes) exhausted and unable to move elements "
|
||||
"of mixed unknown detail type, which are not trivially movable." }
|
||||
% util::typeStr<TY>() % Coll::storageBuffSiz()};
|
||||
probeMoveCapability<TY>(); // mark when target type is not (trivially) movable
|
||||
ensureElementCapacity<TY>(); // sufficient or able to adapt spread
|
||||
ensureStorageCapacity<TY>(); // sufficient or able to grow buffer
|
||||
|
||||
size_t elmSiz = reqSiz<TY>();
|
||||
size_t newPos = Coll::size();
|
||||
|
|
@ -424,6 +417,34 @@ namespace lib {
|
|||
Coll::data_->deleter = deleterFunctor;
|
||||
}
|
||||
|
||||
/** ensure sufficient element capacity or the ability to adapt element spread */
|
||||
template<class TY>
|
||||
void
|
||||
ensureElementCapacity (size_t requiredSiz =reqSiz<TY>())
|
||||
{
|
||||
if (Coll::spread() < requiredSiz and not (Coll::empty() or canWildMove()))
|
||||
throw err::Invalid{_Fmt{"Unable to place element of type %s (size=%d)"
|
||||
"into Several-container for element size %d."}
|
||||
% util::typeStr<TY>() % requiredSiz % Coll::spread()};
|
||||
}
|
||||
|
||||
/** ensure sufficient storage reserve or verify the ability to re-allocate */
|
||||
template<class TY>
|
||||
void
|
||||
ensureStorageCapacity (size_t requiredSiz =reqSiz<TY>(), size_t newElms =1)
|
||||
{
|
||||
if (not (Coll::empty()
|
||||
or Coll::hasReserve (requiredSiz, newElms)
|
||||
or POL::canExpand (requiredSiz*newElms)
|
||||
or canDynGrow()))
|
||||
throw err::Invalid{_Fmt{"Several-container is unable to accommodate further element of type %s; "
|
||||
"storage reserve (%d bytes ≙ %d elms) exhausted and unable to move "
|
||||
"elements of mixed unknown detail type, which are not trivially movable." }
|
||||
% util::typeStr<TY>() % Coll::storageBuffSiz() % capacity()};
|
||||
}
|
||||
|
||||
|
||||
/** possibly grow storage and re-arrange elements to accommodate desired capacity */
|
||||
void
|
||||
adjustStorage (size_t cnt, size_t spread)
|
||||
{
|
||||
|
|
@ -433,9 +454,11 @@ namespace lib {
|
|||
return;
|
||||
if (demand > buffSiz)
|
||||
{// grow into exponentially expanded new allocation
|
||||
if (spread > Coll::spread())
|
||||
cnt = max (cnt, buffSiz / Coll::spread()); // retain reserve
|
||||
size_t safetyLim = LUMIERA_MAX_ORDINAL_NUMBER * Coll::spread();
|
||||
size_t expandAlloc = min (safetyLim
|
||||
,max (2*buffSiz, demand));
|
||||
,max (2*buffSiz, cnt*spread));
|
||||
if (expandAlloc < demand)
|
||||
throw err::State{_Fmt{"Storage expansion for Several-collection "
|
||||
"exceeds safety limit of %d bytes"} % safetyLim
|
||||
|
|
|
|||
|
|
@ -217,10 +217,13 @@ namespace lib {
|
|||
}
|
||||
|
||||
bool
|
||||
hasReserve (size_t extraSize) const
|
||||
hasReserve (size_t requiredSize, size_t newElms =1) const
|
||||
{
|
||||
if (extraSize > spread())
|
||||
extraSize += (extraSize - spread())*size();
|
||||
if (requiredSize < spread())
|
||||
requiredSize = spread();
|
||||
size_t extraSize{requiredSize * newElms};
|
||||
if (requiredSize > spread())
|
||||
extraSize += (requiredSize - spread())*size();
|
||||
return data_
|
||||
and data_->buffSiz >= size()*spread() + extraSize;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,6 +321,8 @@ namespace test{
|
|||
// but we aren't able to move elements safely any more, since we don't capture the type.
|
||||
builder.emplace<Num<1>>();
|
||||
CHECK (20 == builder.size());
|
||||
CHECK (20 == builder.capacity());
|
||||
CHECK ( 0 == builder.capReserve());
|
||||
|
||||
// But here comes the catch: since we choose to accept arbitrary sub-types not identified in detail,
|
||||
// the container has lost its ability of move-reallocation; with 20 elements the current reserve
|
||||
|
|
@ -336,6 +338,23 @@ namespace test{
|
|||
CHECK (elms[i].calc(i) == 5 + i + (5+5+5+5+5));
|
||||
CHECK (elms.back().calc(0) == 1 + 0 + (1));
|
||||
}
|
||||
|
||||
{ // Scenario-3 : arbitrary elements of trivial type
|
||||
SeveralBuilder<uint8_t> builder;
|
||||
|
||||
string BFR{"starship is cool"};
|
||||
builder.appendAll (BFR);
|
||||
CHECK (16 == builder.size());
|
||||
CHECK ( 4 == builder.capReserve());
|
||||
|
||||
builder.append(int64_t(33));
|
||||
CHECK (17 == builder.size());
|
||||
CHECK ( 3 == builder.capReserve());
|
||||
|
||||
auto elms = builder.build();
|
||||
SHOW_EXPR(elms.size())
|
||||
SHOW_EXPR(join(elms, "·"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -82828,6 +82828,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1717893927188" ID="ID_407717086" MODIFIED="1717893962751" TEXT="leeren Container gleich mit einer größeren Allokation starten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718212710737" ID="ID_119846820" MODIFIED="1718212744211" TEXT="bei spread-Vergrößerung: Puffer gemäß bestehender Reserve überdimensionieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1718212749620" ID="ID_1659701829" MODIFIED="1718213228515">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
sonst würde eine Spread-Vergrößerung
|
||||
</p>
|
||||
<p>
|
||||
tatsächlich die Reserve <i>verkleinern...</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
Beispiel:
|
||||
</li>
|
||||
<li>
|
||||
Buffer hat Kapazität für 10 Elemente bei Spread ≡ 1 und 3 Elemente sind belegt
|
||||
</li>
|
||||
<li>
|
||||
es wird ein 4.Element der Größe 8 bytes verlangt
|
||||
</li>
|
||||
<li>
|
||||
4*8 = 32 > 10 ⟹ <font face="Monospaced">realloc()</font>
|
||||
</li>
|
||||
<li>
|
||||
naiver weise würde man jetzt auf 32 Bytes vergrößern, aber danach wäre der Buffer bei Spread ≡ 8 sofort wieder ganz voll
|
||||
</li>
|
||||
<li>
|
||||
daher ist es sinnvoll, die bisherige Reserve von 7 freien Slots zu beachten; d.h. man vergrößert auf 10*8 = 80 bytes
|
||||
</li>
|
||||
<li>
|
||||
danach paßt das 4. Element rein und es ist nach-wie-vor Platz für 6 weitere Elemente
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
<u>Begründung</u>: das ganze Thema »spread« ist extrem technisch und für den Nutzer normalerweise nicht nachvollziehbar, aber die Kapazität in Anzahl der freien Slots ist sehr wohl verständlich für den User; es wäre also <i>ziemlich überraschend</i> wenn — scheinbar ohne ersichtlichen Grund — plötzlich die Reserve-Kapazität verschwunden wäre.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717893967870" ID="ID_1707818601" MODIFIED="1717894043447" TEXT="Spread-Anpassung zweistufig">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1717893983028" ID="ID_571700268" MODIFIED="1717893999382" TEXT="wenn realloc ⟹ passiert implizit"/>
|
||||
|
|
@ -83111,16 +83164,37 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1717634297656" ID="ID_330412196" MODIFIED="1717688579115" TEXT="Move-builder und Container per Slice ausgeben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716914869721" ID="ID_756769385" MODIFIED="1716914902541" TEXT="basis-Allokation">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1718213506519" ID="ID_1529967473" MODIFIED="1718213512271" TEXT="Informationsfunktionen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1718213513318" ID="ID_652722114" MODIFIED="1718213515426" TEXT="size()"/>
|
||||
<node CREATED="1718213516285" ID="ID_325529445" MODIFIED="1718213517889" TEXT="empty()"/>
|
||||
<node CREATED="1718213518597" ID="ID_1291451885" MODIFIED="1718213521849" TEXT="capacity()">
|
||||
<node CREATED="1718213537147" HGAP="44" ID="ID_923597162" MODIFIED="1718213590857" TEXT="Anzahl mögliche Elemente bei aktuellem Spread" VSHIFT="3">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1718213522557" ID="ID_1863830248" MODIFIED="1718213648344" TEXT="capReserve()">
|
||||
<node CREATED="1718213537147" HGAP="25" ID="ID_744290406" MODIFIED="1718213620124" TEXT="noch unbelegte Reserve möglicher Elemente" VSHIFT="3">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1716914877848" ID="ID_1535626389" MODIFIED="1718217001870" TEXT="Größenänderung Allokation">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1718216970318" ID="ID_653307930" MODIFIED="1718216999025" TEXT="Vergrößerung: reserve<T>(cnt, size)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1718216875365" ID="ID_808859315" MODIFIED="1718216924186" TEXT="Handling-Checks vorher">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716936092764" ID="ID_618217173" MODIFIED="1718216922790" TEXT="Objekte einzeln verschieben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1718216902576" ID="ID_1819814974" MODIFIED="1718216911891" TEXT="entweder per bekanntem Element-Typ"/>
|
||||
<node CREATED="1716936101233" ID="ID_1155209653" MODIFIED="1718216920176" TEXT="oder via std::memmove"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716914877848" ID="ID_1535626389" MODIFIED="1716914902541" TEXT="Größenänderung Allokation">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716914886169" ID="ID_505410227" MODIFIED="1716914902542" TEXT="Änderung Spread">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1716936092764" ID="ID_618217173" MODIFIED="1716936100479" TEXT="Objekte einzeln verschieben"/>
|
||||
<node CREATED="1716936101233" ID="ID_1155209653" MODIFIED="1716936109052" TEXT="per std::memmove"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1716914892972" ID="ID_1080699305" MODIFIED="1718147544739" TEXT="Platzieren neuer Daten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -83553,9 +83627,15 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node COLOR="#435e98" CREATED="1718201899221" ID="ID_1719848161" MODIFIED="1718207782278" TEXT="wenn man eine Subklasse platziert, wird die Möglichkeit für Wachstum beschnitten"/>
|
||||
</node>
|
||||
<node CREATED="1718122252659" ID="ID_616405505" MODIFIED="1718122291873" TEXT="Triviale Typen">
|
||||
<node CREATED="1718122293022" ID="ID_697520417" MODIFIED="1718122302248" TEXT="kann wachsen"/>
|
||||
<node CREATED="1718122302932" ID="ID_293207594" MODIFIED="1718122311738" TEXT="kann spread ändern"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1718122252659" ID="ID_616405505" MODIFIED="1718208089182" TEXT="Triviale Typen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#435e98" CREATED="1718122293022" ID="ID_697520417" MODIFIED="1718209949804" TEXT="kann wachsen"/>
|
||||
<node COLOR="#435e98" CREATED="1718122302932" ID="ID_293207594" MODIFIED="1718209952087" TEXT="kann spread ändern">
|
||||
<node COLOR="#435e98" CREATED="1718211785014" ID="ID_185961323" MODIFIED="1718211802523" TEXT="explizit im Debugger beobachtet">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1718153752253" ID="ID_1509145683" MODIFIED="1718153763392" TEXT="kann aber keinen nicht-trivialen Typ platzieren"/>
|
||||
</node>
|
||||
<node CREATED="1718202490965" ID="ID_247674037" MODIFIED="1718206085439" TEXT="Handhabung von non-copyable-Objekten">
|
||||
|
|
|
|||
Loading…
Reference in a new issue