Library: logic to select a suitable deleter
- ensure the ''deleter function'' is invoked - care for proper ''deleter'' setup in case of exception while copying - need to »lock-in« on one specific kind of ''destructor invocation scheme,'' since we do not keep track of individual concrete element types
This commit is contained in:
parent
54bd568714
commit
954a399b1c
2 changed files with 143 additions and 39 deletions
|
|
@ -51,6 +51,7 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
|
@ -171,12 +172,15 @@ namespace lib {
|
|||
{
|
||||
Bucket* newBucket = Fac::create (cnt, spread);
|
||||
if (data)
|
||||
{
|
||||
size_t elms = min (cnt, data->cnt);
|
||||
for (size_t idx=0; idx<elms; ++idx)
|
||||
moveElem(idx, data, newBucket);
|
||||
data->destroy();
|
||||
}
|
||||
try {
|
||||
newBucket->deleter = data->deleter;
|
||||
size_t elms = min (cnt, data->cnt);
|
||||
for (size_t idx=0; idx<elms; ++idx)
|
||||
moveElem(idx, data, newBucket);
|
||||
data->destroy();
|
||||
}
|
||||
catch(...)
|
||||
{ newBucket->destroy(); }
|
||||
return newBucket;
|
||||
/*
|
||||
size_t buffSiz{data? data->buffSiz : 0};
|
||||
|
|
@ -246,6 +250,7 @@ namespace lib {
|
|||
Fac::template createAt<E> (tar, idx
|
||||
,std::move_if_noexcept (src->subscript(idx)));
|
||||
}
|
||||
tar->cnt = idx+1; // mark fill continuously for proper clean-up after exception
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -263,14 +268,26 @@ namespace lib {
|
|||
template<class I, class E>
|
||||
struct HandlingStrategy
|
||||
{
|
||||
bool disposable ;
|
||||
bool lock_move ;
|
||||
enum DestructionMethod { UNKNOWN
|
||||
, TRIVIAL
|
||||
, ELEMENT
|
||||
, VIRTUAL
|
||||
};
|
||||
static Literal
|
||||
render(DestructionMethod m)
|
||||
{
|
||||
switch (m)
|
||||
{
|
||||
case TRIVIAL: return "trivial";
|
||||
case ELEMENT: return "fixed-element-type";
|
||||
case VIRTUAL: return "virtual-baseclass";
|
||||
default:
|
||||
throw err::Logic{"unknown DestructionMethod"};
|
||||
}
|
||||
}
|
||||
|
||||
HandlingStrategy (bool unmanaged)
|
||||
: disposable{unmanaged or (is_trivially_destructible_v<E> and
|
||||
is_trivially_destructible_v<I>)}
|
||||
, lock_move{false}
|
||||
{ }
|
||||
DestructionMethod destructor{UNKNOWN};
|
||||
bool lock_move{false};
|
||||
|
||||
/** mark that we're about to accept an otherwise unknown type,
|
||||
* which can not be trivially moved. This irrevocably disables
|
||||
|
|
@ -291,24 +308,36 @@ namespace lib {
|
|||
|
||||
|
||||
template<typename TY>
|
||||
bool
|
||||
canDestroy()
|
||||
std::function<void(I&)>
|
||||
selectDestructor()
|
||||
{
|
||||
return (disposable and is_trivially_destructible_v<TY>)
|
||||
or (is_trivially_destructible_v<TY> and is_trivially_destructible_v<I>)
|
||||
or (has_virtual_destructor_v<I> and is_Subclass<TY,I>())
|
||||
or (is_same_v<TY,E> and is_Subclass<E,I>());
|
||||
if (is_trivially_destructible_v<TY>)
|
||||
{
|
||||
__ensureMark (TRIVIAL, util::typeStr<TY>());
|
||||
return [](auto){ /* calmness */ };
|
||||
}
|
||||
if (is_same_v<TY,E> and is_Subclass<E,I>())
|
||||
{
|
||||
__ensureMark (ELEMENT, util::typeStr<TY>());
|
||||
return [](I& elm){ reinterpret_cast<E&>(elm).~E(); };
|
||||
}
|
||||
if (is_Subclass<TY,I>() and has_virtual_destructor_v<I>)
|
||||
{
|
||||
__ensureMark (VIRTUAL, util::typeStr<TY>());
|
||||
return [](I& elm){ elm.~I(); };
|
||||
}
|
||||
throw err::Invalid{_Fmt{"Unsupported kind of destructor for element type %s."}
|
||||
% util::typeStr<TY>()};
|
||||
}
|
||||
|
||||
auto
|
||||
getDeleter()
|
||||
void
|
||||
__ensureMark(DestructionMethod expectedKind, string typeID)
|
||||
{
|
||||
if (disposable)
|
||||
return nullptr;
|
||||
if (has_virtual_destructor_v<I>)
|
||||
return nullptr;
|
||||
else
|
||||
return nullptr;
|
||||
if (destructor != UNKNOWN and destructor != expectedKind)
|
||||
throw err::Invalid{_Fmt{"Unable to handle destructor for element type %s, "
|
||||
"since this container has been primed to use %s-deleters."}
|
||||
% typeID % render(expectedKind)};
|
||||
destructor = expectedKind;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -328,7 +357,7 @@ namespace lib {
|
|||
{
|
||||
using Coll = Several<I>;
|
||||
|
||||
HandlingStrategy<I,E> handling_{POL::isDisposable};
|
||||
HandlingStrategy<I,E> handling_{};
|
||||
|
||||
public:
|
||||
SeveralBuilder() = default;
|
||||
|
|
@ -375,9 +404,8 @@ namespace lib {
|
|||
void
|
||||
emplaceElm (ARGS&& ...args)
|
||||
{
|
||||
if (not handling_.template canDestroy<TY>())
|
||||
throw err::Invalid{_Fmt{"Unable to handle destructor for element type %s"}
|
||||
% util::typeStr<TY>()};
|
||||
// ensure proper configuration of clean-up for the container
|
||||
auto invokeDestructor = handling_.template selectDestructor<TY>();
|
||||
|
||||
// mark when target type is not trivially movable
|
||||
handling_.template probeMoveCapability<TY>();
|
||||
|
|
@ -392,11 +420,13 @@ namespace lib {
|
|||
size_t newPos = Coll::size();
|
||||
size_t newCnt = Coll::empty()? INITIAL_ELM_CNT : newPos+1;
|
||||
adjustStorage (newCnt, max (elmSiz, Coll::spread()));
|
||||
ENSURE (Coll::data_);
|
||||
if (not Coll::data_->deleter)
|
||||
UNIMPLEMENTED ("setup deleter trampoline");
|
||||
Coll::data_->cnt = newPos+1;
|
||||
POL::template createAt<TY> (Coll::data_, newPos, forward<ARGS> (args)...);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
adjustStorage (size_t cnt, size_t spread)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -82215,7 +82215,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1717539729616" ID="ID_1305258499" MODIFIED="1717539743649" TEXT="global disposable oder unmanaged ⟹ keiner"/>
|
||||
<node CREATED="1717539852917" ID="ID_1428257938" MODIFIED="1717543030532" TEXT="∨ Basistyp und konkreter Typ sind trivially destructible"/>
|
||||
<node CREATED="1717539745205" ID="ID_222469132" MODIFIED="1717544076400" TEXT="∨ Basistyp hat virtuellen Deleter und Typ ist Subklasse"/>
|
||||
<node CREATED="1717540047343" ID="ID_1258092354" MODIFIED="1717544130652" TEXT="∨ Typ ≡ Element-Typ und erbt von Basistyp"/>
|
||||
<node CREATED="1717540047343" ID="ID_1258092354" MODIFIED="1717943093340" TEXT="∨ Typ ≡ Element-Typ (beliebig aber fest)"/>
|
||||
</node>
|
||||
<node CREATED="1717539954701" ID="ID_1347402773" MODIFIED="1717540865774" TEXT="Construct">
|
||||
<arrowlink COLOR="#d90152" DESTINATION="ID_1442794254" ENDARROW="Default" ENDINCLINATION="2;12;" ID="Arrow_ID_92396700" STARTARROW="None" STARTINCLINATION="-2;-10;"/>
|
||||
|
|
@ -82266,8 +82266,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1717542702415" ID="ID_1473880478" MODIFIED="1717545646724" TEXT="canAdjust ⟵ wild-move-Flag"/>
|
||||
</node>
|
||||
<node CREATED="1717543060128" ID="ID_1973537913" MODIFIED="1717543071098" TEXT="Handler">
|
||||
<node CREATED="1717543072032" ID="ID_1791379026" MODIFIED="1717723687678" TEXT="getDeleter()">
|
||||
<arrowlink COLOR="#e1073d" DESTINATION="ID_1412900866" ENDARROW="Default" ENDINCLINATION="344;0;" ID="Arrow_ID_453255140" STARTARROW="Default" STARTINCLINATION="344;0;"/>
|
||||
<node CREATED="1717543072032" ID="ID_1791379026" MODIFIED="1717942738739" TEXT="getDeleter()">
|
||||
<arrowlink COLOR="#e1073d" DESTINATION="ID_1412900866" ENDARROW="Default" ENDINCLINATION="336;-46;" ID="Arrow_ID_453255140" STARTARROW="Default" STARTINCLINATION="344;0;"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1717546372010" ID="ID_231852526" MODIFIED="1717596420967" TEXT="klären: wie wird er konkret verwendet?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1717546388726" ID="ID_1089262988" MODIFIED="1717546407495" TEXT="muß einen Pointer auf ein Trampolin speichern können"/>
|
||||
|
|
@ -82335,6 +82335,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1717710901355" ID="ID_718524980" MODIFIED="1717715225349" TEXT="das Meiste ist nämlich generische Boilerplate"/>
|
||||
<node CREATED="1717715255933" ID="ID_261113900" MODIFIED="1717715273774" TEXT="damit könnte auch das Thema »durchreichen des Basis-Allokators« generisch gelöst werden"/>
|
||||
</node>
|
||||
<node CREATED="1717942814818" ID="ID_1746173014" MODIFIED="1717943166752" TEXT="mögliche Arten von Deletern">
|
||||
<linktarget COLOR="#6172af" DESTINATION="ID_1746173014" ENDARROW="Default" ENDINCLINATION="165;696;" ID="Arrow_ID_28316112" SOURCE="ID_927074944" STARTARROW="None" STARTINCLINATION="-72;-321;"/>
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1717942842494" ID="ID_18567223" MODIFIED="1717942848417" TEXT="unmanaged ⟹ keiner (fix)"/>
|
||||
<node CREATED="1717942989115" ID="ID_1148848955" MODIFIED="1717943002567" TEXT="trivially destructible ⟹ keiner (Lock)"/>
|
||||
<node CREATED="1717942989115" ID="ID_90163723" MODIFIED="1717943128363" TEXT="virtual Base ⟹ invoke Base-destructor (Lock)"/>
|
||||
<node CREATED="1717942989115" ID="ID_426648590" MODIFIED="1717943121885" TEXT="element type ⟹ invoke Element-destructor (Lock)"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1717543083078" ID="ID_530261806" MODIFIED="1717543114805" TEXT="getMover()"/>
|
||||
</node>
|
||||
|
|
@ -82498,11 +82506,77 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1717723649872" ID="ID_1412900866" MODIFIED="1717723682406" TEXT="Deleter einbinden?">
|
||||
<linktarget COLOR="#e1073d" DESTINATION="ID_1412900866" ENDARROW="Default" ENDINCLINATION="344;0;" ID="Arrow_ID_453255140" SOURCE="ID_1791379026" STARTARROW="Default" STARTINCLINATION="344;0;"/>
|
||||
<icon BUILTIN="help"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1717894220868" HGAP="30" ID="ID_1883351365" MODIFIED="1717894241964" TEXT="muß passieren sobald wir ein ArrayBucket erstellen" VSHIFT="24">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1717723649872" ID="ID_1412900866" MODIFIED="1717942738739" TEXT="Deleter einbinden">
|
||||
<linktarget COLOR="#e1073d" DESTINATION="ID_1412900866" ENDARROW="Default" ENDINCLINATION="336;-46;" ID="Arrow_ID_453255140" SOURCE="ID_1791379026" STARTARROW="Default" STARTINCLINATION="344;0;"/>
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1717894220868" HGAP="34" ID="ID_1883351365" MODIFIED="1717942742521" TEXT="muß passieren sobald wir ein ArrayBucket erstellen" VSHIFT="44">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1717942010130" ID="ID_1773419398" MODIFIED="1717942017651" TEXT="systematisch wird schwierig..."/>
|
||||
<node CREATED="1717942018222" ID="ID_1128164934" MODIFIED="1717942030673" TEXT="pragmatisch: dort wo neue Objekte hinzugefügt werden"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1717942762161" ID="ID_1712399838" MODIFIED="1717942772934" TEXT="Knackpunkt: kann sich der Deleter ändern?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1717942774837" ID="ID_927074944" MODIFIED="1717943198780" TEXT="Regeln für Deleter-Art">
|
||||
<arrowlink COLOR="#6172af" DESTINATION="ID_1746173014" ENDARROW="Default" ENDINCLINATION="165;696;" ID="Arrow_ID_28316112" STARTARROW="None" STARTINCLINATION="-72;-321;"/>
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717943179894" ID="ID_1140852482" MODIFIED="1717946248832" TEXT="⟹ wir müssen uns auf eine Variante festlegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717943200583" ID="ID_1577714293" MODIFIED="1717946250661" TEXT="und ab diesem Punkt andere Varianten ausschließen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943344630" ID="ID_115481539" MODIFIED="1717943372882" TEXT="muß ggfs konkreten Allokator einbinden">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943385927" ID="ID_662106434" MODIFIED="1717943434357" TEXT="Deleter-Erstellung wird damit stets zweistufig">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943398172" ID="ID_474906646" MODIFIED="1717943434357" TEXT="und findet nur einmal statt (wenn es noch keinen gibt)">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943412882" ID="ID_1368104122" MODIFIED="1717943434358" TEXT="damit wird auch die Variante des Element-Typs festgelegt">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943441718" ID="ID_1930279043" MODIFIED="1717943474267" TEXT="2.Stufe ≙ de-Allokation ⟹ an die Policy delegiert">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1717943727408" ID="ID_398573642" MODIFIED="1717943750861" TEXT="Konsequenz: Destruktor ≠ de-Allokation">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1717943774986" ID="ID_1922725758" MODIFIED="1717943879338" TEXT="auch für »unmanaged«-Allokatoren den Destruktor aufrufen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...man könnte geneigt sein, das zu überspringen; aber ich entscheide mich hier <b>explizit dagegen</b>, weil es <i>gegen den Stil von C++ verstößt.</i> Wenn man den Deleter-Aufruf vermeiden will, dann soll man eben triviale Objekte verwenden. Ende der Diskussion.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e5e897" COLOR="#5c00fa" CREATED="1717943901657" ID="ID_1634025872" MODIFIED="1717943996482" TEXT="⟹ Bedeutungs-Änderung: deleter ≡ nullptr ⟼ unvollständig initialisiertes ArrayBucket">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717942044777" HGAP="36" ID="ID_1959983303" MODIFIED="1717942720203" TEXT="sicherstellen daß er beim realloc weitergegeben wird" VSHIFT="-1">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1717942172616" ID="ID_1961893400" MODIFIED="1717942648138" TEXT="so früh wie möglich einbinden (damit der neue Block sauber freigegeben werden kann)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717942214546" ID="ID_1993324579" MODIFIED="1717942644266" TEXT="⟹ im Fall von Exceptions stets per Deleter freigeben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#a50125" CREATED="1717942153139" ID="ID_696699633" MODIFIED="1717942713440" TEXT="vorsicht Falle: Exception nach partiellem Kopieren">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node COLOR="#435e98" CREATED="1717942654759" ID="ID_995578878" MODIFIED="1717942711066" TEXT="Abhilfe: element-count stets dynamisch mitführen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1717723703235" ID="ID_239148471" MODIFIED="1717894210685" TEXT="Objekt platzieren mit durchgereichten ctor-Argumenten">
|
||||
|
|
|
|||
Loading…
Reference in a new issue