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:
Fischlurch 2024-06-09 17:19:40 +02:00
parent 54bd568714
commit 954a399b1c
2 changed files with 143 additions and 39 deletions

View file

@ -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)
{

View file

@ -82215,7 +82215,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1717539729616" ID="ID_1305258499" MODIFIED="1717539743649" TEXT="global disposable oder unmanaged &#x27f9; keiner"/>
<node CREATED="1717539852917" ID="ID_1428257938" MODIFIED="1717543030532" TEXT="&#x2228; Basistyp und konkreter Typ sind trivially destructible"/>
<node CREATED="1717539745205" ID="ID_222469132" MODIFIED="1717544076400" TEXT="&#x2228; Basistyp hat virtuellen Deleter und Typ ist Subklasse"/>
<node CREATED="1717540047343" ID="ID_1258092354" MODIFIED="1717544130652" TEXT="&#x2228; Typ &#x2261; Element-Typ und erbt von Basistyp"/>
<node CREATED="1717540047343" ID="ID_1258092354" MODIFIED="1717943093340" TEXT="&#x2228; Typ &#x2261; 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:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1717542702415" ID="ID_1473880478" MODIFIED="1717545646724" TEXT="canAdjust &#x27f5; 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&#xe4;ren: wie wird er konkret verwendet?">
<icon BUILTIN="help"/>
<node CREATED="1717546388726" ID="ID_1089262988" MODIFIED="1717546407495" TEXT="mu&#xdf; einen Pointer auf ein Trampolin speichern k&#xf6;nnen"/>
@ -82335,6 +82335,14 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1717710901355" ID="ID_718524980" MODIFIED="1717715225349" TEXT="das Meiste ist n&#xe4;mlich generische Boilerplate"/>
<node CREATED="1717715255933" ID="ID_261113900" MODIFIED="1717715273774" TEXT="damit k&#xf6;nnte auch das Thema &#xbb;durchreichen des Basis-Allokators&#xab; generisch gel&#xf6;st werden"/>
</node>
<node CREATED="1717942814818" ID="ID_1746173014" MODIFIED="1717943166752" TEXT="m&#xf6;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 &#x27f9; keiner (fix)"/>
<node CREATED="1717942989115" ID="ID_1148848955" MODIFIED="1717943002567" TEXT="trivially destructible &#x27f9; keiner (Lock)"/>
<node CREATED="1717942989115" ID="ID_90163723" MODIFIED="1717943128363" TEXT="virtual Base &#x27f9; invoke Base-destructor (Lock)"/>
<node CREATED="1717942989115" ID="ID_426648590" MODIFIED="1717943121885" TEXT="element type &#x27f9; invoke Element-destructor (Lock)"/>
</node>
</node>
<node CREATED="1717543083078" ID="ID_530261806" MODIFIED="1717543114805" TEXT="getMover()"/>
</node>
@ -82498,11 +82506,77 @@ Date:&#160;&#160;&#160;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&#xdf; 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&#xdf; 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&#xfc;gt werden"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1717942762161" ID="ID_1712399838" MODIFIED="1717942772934" TEXT="Knackpunkt: kann sich der Deleter &#xe4;ndern?">
<icon BUILTIN="help"/>
<node CREATED="1717942774837" ID="ID_927074944" MODIFIED="1717943198780" TEXT="Regeln f&#xfc;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="&#x27f9; wir m&#xfc;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&#xdf;en">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1717943344630" ID="ID_115481539" MODIFIED="1717943372882" TEXT="mu&#xdf; 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 &#x2259; de-Allokation &#x27f9; an die Policy delegiert">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1717943727408" ID="ID_398573642" MODIFIED="1717943750861" TEXT="Konsequenz: Destruktor &#x2260; de-Allokation">
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1717943774986" ID="ID_1922725758" MODIFIED="1717943879338" TEXT="auch f&#xfc;r &#xbb;unmanaged&#xab;-Allokatoren den Destruktor aufrufen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...man k&#246;nnte geneigt sein, das zu &#252;berspringen; aber ich entscheide mich hier <b>explizit dagegen</b>, weil es <i>gegen den Stil von C++ verst&#246;&#223;t.</i>&#160;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="&#x27f9; Bedeutungs-&#xc4;nderung: deleter &#x2261; nullptr &#x27fc; unvollst&#xe4;ndig initialisiertes ArrayBucket">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1717942044777" HGAP="36" ID="ID_1959983303" MODIFIED="1717942720203" TEXT="sicherstellen da&#xdf; er beim realloc weitergegeben wird" VSHIFT="-1">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1717942172616" ID="ID_1961893400" MODIFIED="1717942648138" TEXT="so fr&#xfc;h wie m&#xf6;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="&#x27f9; 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&#xfc;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">