Library: cover handling limits for virtual baseclass scenario

building on the preceding analysis, we can now demonstrate that
the container is initially able to grow, but looses this capability
after accepting one element of unknown subclass type...
This commit is contained in:
Fischlurch 2024-06-12 17:59:56 +02:00
parent 85e3780a34
commit 89dd35e70d
4 changed files with 106 additions and 59 deletions

View file

@ -277,7 +277,7 @@ namespace lib {
,class POL =HeapOwn<I,E> ///< Allocator policy
>
class SeveralBuilder
: Several<I>
: private Several<I>
, util::MoveOnly
, POL
{
@ -390,15 +390,17 @@ namespace lib {
// 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 container for element 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{"Unable to accommodate further element of type %s "}
% util::typeStr<TY>()};
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()};
size_t elmSiz = reqSiz<TY>();
size_t newPos = Coll::size();
@ -410,11 +412,13 @@ namespace lib {
Coll::data_->cnt = newPos+1;
}
/** ensure clean-up can be handled properly.
* @throw err::Invalid when \a TY requires a different style
* of deleter than was established for this instance */
template<class TY>
void
ensureDeleter()
{
// ensure clean-up can be handled properly
Deleter deleterFunctor = selectDestructor<TY>();
if (Coll::data_->deleter) return;
Coll::data_->deleter = deleterFunctor;
@ -424,7 +428,7 @@ namespace lib {
adjustStorage (size_t cnt, size_t spread)
{
size_t demand{cnt*spread};
size_t buffSiz{Coll::data_? Coll::data_->buffSiz : 0};
size_t buffSiz{Coll::storageBuffSiz()};
if (demand == buffSiz)
return;
if (demand > buffSiz)
@ -462,7 +466,7 @@ namespace lib {
adjustSpread (size_t newSpread)
{
REQUIRE (Coll::data_);
REQUIRE (newSpread * Coll::size() <= Coll::data_->buffSiz);
REQUIRE (newSpread * Coll::size() <= Coll::storageBuffSiz());
size_t oldSpread = Coll::spread();
if (newSpread > oldSpread)
// need to spread out

View file

@ -210,6 +210,12 @@ namespace lib {
return data_? data_->spread : sizeof(I);
}
size_t
storageBuffSiz() const
{
return data_? data_->buffSiz : 0;
}
bool
hasReserve (size_t extraSize) const
{

View file

@ -111,6 +111,18 @@ namespace test{
}
};
/**
* A non-copyable struct with 16bit alignment
* - not trivially default constructible
* - but trivially destructible
*/
struct ShortBlocker
: util::NonCopyable
{
int16_t val{short(1 + (rand() % 1'000))};
};
} // (END) test types
@ -164,7 +176,7 @@ namespace test{
* *unchecked wild cast* will happen on access; while certainly dangerous,
* this behaviour allows for special low-level data layout tricks.
* - the results from an iterator can be used to populate by copy
* @todo WIP 6/24 🔁 define implement
* @todo WIP 6/24 define implement
*/
void
check_Builder()
@ -228,7 +240,17 @@ namespace test{
/** @test TODO proper handling of exceptions during population
* @todo WIP 6/24 🔁 define implement
* - when the container is filled with arbitrary subclasses
* of a base interface with virtual destructor, the first element is used
* to accommodate the storage spread; larger elements or elements of a completely
* different type can not be accommodated and the container can not grow beyond
* the initially allocated reserve (defined to be 10 elements by default).
* - when the container is defined to hold elements of a specific fixed subclass,
* it can be filled with default-constructed instances, and the initial allocation
* can be expanded by move-relocation. Yet totally unrelated elements can not be
* accepted (due to unknown destructor); and when accepting another unspecific
* subclass instance, the ability to grow by move-relocation is lost.
* @todo WIP 6/24 🔁 define implement
*/
void
check_ErrorHandling()
@ -266,7 +288,7 @@ namespace test{
// a re-allocation of a larger buffer, followed by copying the elements;
// but since the established scheme allows for _arbitrary_ subclasses,
// the builder does not know the exact type for safe element relocation.
VERIFY_FAIL ("Unable to accommodate further element of type Dummy"
VERIFY_FAIL ("Several-container is unable to accommodate further element of type Dummy"
, builder.fillElm (20) );
CHECK (10 == builder.size());
}
@ -274,27 +296,45 @@ namespace test{
{ // Scenario-2 : Baseclass and elements of a single fixed subclass
SeveralBuilder<Dummy, Num<5>> builder;
Dummy dum;
SHOW_EXPR(dum.getVal())
Dummy nem{move(dum)};
SHOW_EXPR(dum.getVal())
SHOW_EXPR(nem.getVal())
Num<5> no5;
SHOW_EXPR(no5.getVal())
Num<5> ne5{move(no5)};
SHOW_EXPR(no5.getVal())
SHOW_EXPR(ne5.getVal())
builder.fillElm(5);
CHECK (5 == builder.size());
// trigger re-alloc by moving into larger memory block
builder.fillElm(14);
CHECK (19 == builder.size());
CHECK (builder.size() > INITIAL_ELM_CNT);
builder.emplace<short>();
// with the elements added thus far, this instance has been primed to
// rely on a fixed well known element type for move-growth and to use
// the virtual base class destructor for clean-up. It is thus not possible
// to add another element that is not related to this baseclass...
VERIFY_FAIL ("Unable to handle (trivial-)destructor for element type ShortBlocker, "
"since this container has been primed to use virtual-baseclass-destructors."
, builder.emplace<ShortBlocker>() );
CHECK (19 == builder.size());
builder.emplace<Num<1>>(); ///////////////////////////////////OOO this should trigger an exception -> need to code an explicit check right at the start of emplaceNewElm()
CHECK (sizeof(ShortBlocker) < sizeof(Num<5>)); // it was not rejected due to size...
// However, a subclass /different than the defined element type/ is acceptable,
// but only to the condition to lock any further container growth by move-reallocation.
// The rationale is that we can still destroy through the virtual base destructor,
// 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());
// 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
// is exhausted and we are now unable to add any further elements beyond that point.
VERIFY_FAIL ("unable to move elements of mixed unknown detail type, which are not trivially movable"
, builder.fillElm(5); );
// the container is still sound however
auto elms = builder.build();
CHECK (20 == elms.size());
// verify that member fields were not corrupted
for (uint i=0; i<=18; ++i)
CHECK (elms[i].calc(i) == 5 + i + (5+5+5+5+5));
CHECK (elms.back().calc(0) == 1 + 0 + (1));
}
}
@ -302,7 +342,7 @@ SHOW_EXPR(ne5.getVal())
/** @test TODO verify correct placement of instances within storage
* @todo WIP 6/24 🔁 define implement
*/
void
void
check_ElementStorage()
{
}
@ -311,7 +351,7 @@ SHOW_EXPR(ne5.getVal())
/** @test TODO demonstrate integration with a custom allocator
* @todo WIP 6/24 🔁 define implement
*/
void
void
check_CustomAllocator()
{
}

View file

@ -82728,9 +82728,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1717894127145" ID="ID_774641997" MODIFIED="1718073590404" TEXT="andere F&#xe4;lle werden nicht zugelassen">
<icon BUILTIN="bell"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1717894315160" ID="ID_1788527715" MODIFIED="1717894325877" TEXT="auf welcher Ebene wird das gepr&#xfc;ft?">
<node COLOR="#435e98" CREATED="1717894315160" ID="ID_1788527715" MODIFIED="1718206012876" TEXT="auf welcher Ebene wird das gepr&#xfc;ft?">
<icon BUILTIN="help"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1717894328830" ID="ID_1955150114" MODIFIED="1717894371012">
<node COLOR="#435e98" CREATED="1717894328830" ID="ID_1955150114" MODIFIED="1718206021517">
<richcontent TYPE="NODE"><html>
<head/>
<body>
@ -82741,9 +82741,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1717980838451" ID="ID_123345043" MODIFIED="1717980849735" TEXT="hab es jetzt vorerst doch wieder dorthin geschoben"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717980850354" ID="ID_1951694568" MODIFIED="1718200585346" TEXT="diese L&#xf6;sung nochmal &#xfc;berpr&#xfc;fen">
<node COLOR="#1d7bab" CREATED="1717980850354" ID="ID_1951694568" MODIFIED="1718206045690" TEXT="diese L&#xf6;sung nochmal &#xfc;berpr&#xfc;fen">
<linktarget COLOR="#77334a" DESTINATION="ID_1951694568" ENDARROW="Default" ENDINCLINATION="466;38;" ID="Arrow_ID_13456577" SOURCE="ID_1048202028" STARTARROW="None" STARTINCLINATION="325;-27;"/>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1718200372590" HGAP="61" ID="ID_523646974" MODIFIED="1718200393353" TEXT="m&#xf6;glicherweise wird die L&#xf6;sung sehr Kontext-abh&#xe4;ngig" VSHIFT="11">
<icon BUILTIN="idea"/>
<node CREATED="1718200410241" HGAP="22" ID="ID_341859477" MODIFIED="1718200510931" TEXT="unter Umst&#xe4;nden mu&#xdf; man gar nicht unterbinden, was kein Problem darstellt" VSHIFT="9"/>
@ -82757,10 +82757,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node CREATED="1717894410331" ID="ID_732905043" MODIFIED="1717894437670" TEXT="es gen&#xfc;gt, die move_lock-Flag zu pr&#xfc;fen">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1717894410331" ID="ID_732905043" MODIFIED="1718206008045" TEXT="es gen&#xfc;gt, die move_lock-Flag zu pr&#xfc;fen">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1717894472499" ID="ID_534883946" MODIFIED="1718200561076" TEXT="Aber: wird erst relevant wenn tats&#xe4;chlich Objekte verschoben werden m&#xfc;ssen">
<node BACKGROUND_COLOR="#ece3a5" COLOR="#7b2c88" CREATED="1717894472499" ID="ID_534883946" MODIFIED="1718205997336" TEXT="Aber: wird erst relevant wenn tats&#xe4;chlich Objekte verschoben werden m&#xfc;ssen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -82770,8 +82770,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
<arrowlink COLOR="#fdfac6" DESTINATION="ID_332242965" ENDARROW="Default" ENDINCLINATION="-228;8;" ID="Arrow_ID_950941369" STARTARROW="None" STARTINCLINATION="266;9;"/>
<icon BUILTIN="flag-pink"/>
<node CREATED="1718202386482" HGAP="264" ID="ID_875355344" MODIFIED="1718202419463" TEXT="au&#xdf;erdem: sicherstellen da&#xdf; nur valider Copy/Move-Code generiert wird" VSHIFT="38">
<icon BUILTIN="idea"/>
<node COLOR="#435e98" CREATED="1718202386482" HGAP="264" ID="ID_875355344" MODIFIED="1718205946374" TEXT="au&#xdf;erdem: sicherstellen da&#xdf; nur valider Copy/Move-Code generiert wird" VSHIFT="38">
<icon BUILTIN="yes"/>
<node CREATED="1718202425005" ID="ID_787831291" MODIFIED="1718202718252" TEXT="extrem wichtig &#x2014; das ist eine Schw&#xe4;che von std::vector">
<richcontent TYPE="NOTE"><html>
@ -82790,8 +82790,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Soweit <i>die Theorie...</i>&#160;in der Praxis aber <b>scheitert das</b>, weil der Compiler versucht, den realloc-Code zu instantiieren und daf&#252;r keinen Copy/Move-Konstruktor findet
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1718202443155" ID="ID_1046115206" MODIFIED="1718202851765" TEXT="wir wollen definitiv auch non-copyable-Objekte handhaben k&#xf6;nnen">
<richcontent TYPE="NOTE"><html>
@ -82809,11 +82808,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</li>
</ul>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1718202456849" ID="ID_1146034926" MODIFIED="1718202534877" TEXT="das auch testen!">
<arrowlink COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-635;-37;" ID="Arrow_ID_10606647" STARTARROW="None" STARTINCLINATION="-429;58;"/>
<node CREATED="1718202456849" ID="ID_1146034926" MODIFIED="1718206085439" TEXT="das auch testen!">
<arrowlink COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-777;-16;" ID="Arrow_ID_10606647" STARTARROW="None" STARTINCLINATION="-438;67;"/>
</node>
</node>
</node>
@ -82942,18 +82940,18 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="smily_bad"/>
<node CREATED="1717771172737" ID="ID_339804394" MODIFIED="1717771190676" TEXT="das l&#xe4;ge zwar im Bucket in der Storage"/>
<node CREATED="1717771200623" ID="ID_79846525" MODIFIED="1717771208658" TEXT="trotzdem &#xe4;rgerlich">
<node CREATED="1717771319363" ID="ID_165772412" MODIFIED="1717771389855" TEXT="weil es f&#xfc;r den Haupt-Anwendungsfall gar nicht gebraucht wird">
<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>
<node CREATED="1718202490965" ID="ID_247674037" MODIFIED="1718202528909" TEXT="Handhabung von non-copyable-Objekten">
<linktarget COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-635;-37;" ID="Arrow_ID_10606647" SOURCE="ID_1146034926" STARTARROW="None" STARTINCLINATION="-429;58;"/>
</node>
</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"/>
@ -83176,8 +83174,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
...also ist das keine gute Idee, da verwirrend
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="stop-sign"/>
</node>
</node>
@ -83416,8 +83413,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
...&#10004; OK &#8212; selber schuld
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node COLOR="#338800" CREATED="1718122626451" ID="ID_142448404" MODIFIED="1718147515497" TEXT="Iterator einf&#xfc;llen">
@ -83432,9 +83428,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#435e98" CREATED="1718153109115" ID="ID_443086499" MODIFIED="1718153130346" STYLE="fork" TEXT="kein Typ mit anderem nicht-passenden Destruktor-Schema"/>
<node COLOR="#435e98" CREATED="1718122010547" ID="ID_1757791910" MODIFIED="1718153130345" STYLE="fork" TEXT="nicht gen&#xfc;gend Storage und kann nicht verschieben"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1718122030712" ID="ID_1960968889" MODIFIED="1718158946391" TEXT="Base + bekanntes E">
<icon BUILTIN="pencil"/>
<node CREATED="1718122066531" ID="ID_1633309056" MODIFIED="1718122076582" TEXT="kann wachsen (da move-ctor bekannt)">
<node COLOR="#338800" CREATED="1718122030712" ID="ID_1960968889" MODIFIED="1718207777729" TEXT="Base + bekanntes E">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1718122066531" ID="ID_1633309056" MODIFIED="1718207783982" TEXT="kann wachsen (da move-ctor bekannt)">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#761b6d" CREATED="1718158865620" ID="ID_1008642521" MODIFIED="1718158939698" TEXT="erst mal mu&#xdf; Num&lt;5&gt; auch einen move-ctor haben">
<icon BUILTIN="broken-line"/>
</node>
@ -83446,8 +83442,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
und der von Dummy mu&#223; <b>noexcept</b>&#160;sein
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="broken-line"/>
</node>
</node>
@ -83513,8 +83508,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
...es spricht tats&#228;chlich nichts dagegen, diesen Fall auch nachtr&#228;glich noch zuzulassen &#8212; man gibt dann eben die M&#246;glichkeit f&#252;r re-Allocations auf (und wenn <i>das</i>&#160;ein Problem darstellt, macht sich das zu gegebener Zeit <i>eindeutig bemerkbar</i>)
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1718201084309" ID="ID_1592892204" MODIFIED="1718201766838" TEXT="die Pr&#xfc;f-Logik im Code ist bereits vollst&#xe4;ndig und gut angeordnet">
<richcontent TYPE="NOTE"><html>
@ -83538,14 +83532,14 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<linktarget COLOR="#51b6cc" DESTINATION="ID_1592892204" ENDARROW="Default" ENDINCLINATION="281;-14;" ID="Arrow_ID_517622740" SOURCE="ID_357179310" STARTARROW="None" STARTINCLINATION="313;27;"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718201601397" ID="ID_782023787" MODIFIED="1718201981335" TEXT="entsprechend den Test umformulieren">
<node COLOR="#435e98" CREATED="1718201601397" ID="ID_782023787" MODIFIED="1718207773406" TEXT="entsprechend den Test umformulieren">
<arrowlink COLOR="#6079c7" DESTINATION="ID_357857724" ENDARROW="Default" ENDINCLINATION="192;-8;" ID="Arrow_ID_654254378" STARTARROW="None" STARTINCLINATION="-163;11;"/>
<icon BUILTIN="yes"/>
</node>
</node>
</node>
</node>
<node CREATED="1718201827718" ID="ID_357857724" MODIFIED="1718201975615">
<node COLOR="#435e98" CREATED="1718201827718" ID="ID_357857724" MODIFIED="1718207779950">
<richcontent TYPE="NODE"><html>
<head/>
<body>
@ -83557,13 +83551,16 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#6079c7" DESTINATION="ID_357857724" ENDARROW="Default" ENDINCLINATION="192;-8;" ID="Arrow_ID_654254378" SOURCE="ID_782023787" STARTARROW="None" STARTINCLINATION="-163;11;"/>
<font NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1718201899221" ID="ID_1719848161" MODIFIED="1718201919629" TEXT="wenn man eine Subklasse platziert, wird die M&#xf6;glichkeit f&#xfc;r Wachstum beschnitten"/>
<node COLOR="#435e98" CREATED="1718201899221" ID="ID_1719848161" MODIFIED="1718207782278" TEXT="wenn man eine Subklasse platziert, wird die M&#xf6;glichkeit f&#xfc;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 &#xe4;ndern"/>
<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">
<linktarget COLOR="#638ad5" DESTINATION="ID_247674037" ENDARROW="Default" ENDINCLINATION="-777;-16;" ID="Arrow_ID_10606647" SOURCE="ID_1146034926" STARTARROW="None" STARTINCLINATION="-438;67;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716857382441" ID="ID_1397767362" MODIFIED="1716857402102" TEXT="check_ElementAccess">
<icon BUILTIN="flag-yellow"/>