Library: how to use a standard allocator for LinkedElements

By default, LinkedElements uses a policy OwningHeapAllocated;
while retaining this interface, this policy should be recast
to rely on a standard compliant allocator, with a default
fallback to `std::allocator<T>`

This way, a single policy would serve all the cases where
objects are actually owned and managed by `LinkedElements`,
and most special policies would be redundant.

This turns out to be quite tedious and technical however,
since the newer standard mandates to use std::allocator_traits
as front-end, and moreover the standard allocators are always
tied to one specific target type, while `LinkedElements` is
deliberately used to maintain a polymorphic sequence.
This commit is contained in:
Fischlurch 2024-05-26 01:51:23 +02:00
parent 3edf727c23
commit 5259000bc4
2 changed files with 173 additions and 6 deletions

View file

@ -66,6 +66,7 @@
#include "lib/util.hpp"
#include <utility>
#include <memory>
namespace lib {
@ -109,6 +110,84 @@ namespace lib {
}
};
template<class ALO>
struct OwningAlloc
: util::MoveOnly
{
using Allo = ALO;
using AlloT = std::allocator_traits<Allo>;
using BaseType = typename Allo::value_type;
Allo allocator_;
OwningAlloc (Allo allo = Allo{})
: allocator_{allo}
{ }
template<typename X>
auto
adaptAllocator (Allo const& baseAllocator)
{
using XAllo = typename AlloT::template rebind_alloc<X>;
if constexpr (std::is_constructible_v<XAllo, Allo>)
return XAllo(allocator_);
else
return XAllo();
}
template<class ALOT, typename...ARGS>
auto&
construct (typename ALOT::alocator_type& allo, ARGS&& ...args)
{
auto loc = ALOT::allocate (allocator_, 1);
ALOT::construct (allocator_, loc, std::forward<ARGS>(args)...);
return *loc;
}
template<class ALOT, typename...ARGS>
void
destroy (typename ALOT::alocator_type& allo, typename ALOT::pointer elm)
{
ALOT::destroy (allo, elm);
ALOT::deallocate (allo, elm, 1);
}
/** create new element using the embedded allocator */
template<class TY, typename...ARGS>
TY&
create (ARGS&& ...args)
{
if constexpr (std::is_same_v<TY, BaseType>)
{
return construct<AlloT> (allocator_, std::forward<ARGS>(args)...);
}
else
{
using XAlloT = typename AlloT::template rebind_traits<TY>;
auto xAllo = adaptAllocator<TY> (allocator_);
return construct<XAlloT> (xAllo, std::forward<ARGS>(args)...);
}
}
template<class TY>
void
destroy (TY* elm)
{
if constexpr (std::is_same_v<TY, BaseType>)
{
destroy<AlloT> (allocator_, elm);
}
else
{
using XAlloT = typename AlloT::template rebind_traits<TY>;
auto xAllo = adaptAllocator<TY> (allocator_);
destroy<XAlloT> (xAllo, elm);
}
}
};

View file

@ -64932,10 +64932,89 @@
<node COLOR="#338800" CREATED="1686696718121" ID="ID_1035772269" MODIFIED="1686696767814" TEXT="vorl&#xe4;ufig implementiert durch std::list mit Inline-Buffer">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1686696768847" ID="ID_48162464" MODIFIED="1686696788657" TEXT="das gleiche Aufruf-Pattern in AllocationCluster integrieren">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1686696768847" ID="ID_48162464" MODIFIED="1716683834965" TEXT="das gleiche Aufruf-Pattern in AllocationCluster integrieren">
<arrowlink COLOR="#515b9a" DESTINATION="ID_910814489" ENDARROW="Default" ENDINCLINATION="167;-10;" ID="Arrow_ID_96021000" STARTARROW="None" STARTINCLINATION="168;8;"/>
<icon BUILTIN="hourglass"/>
</node>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1716677970109" ID="ID_282740712" MODIFIED="1716677984988" TEXT="Konflikt &#x2016; Design-Ziele nicht klar">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1716678004602" ID="ID_7759126" MODIFIED="1716678008509" TEXT="gew&#xfc;nscht">
<node CREATED="1716678013105" ID="ID_1544782146" MODIFIED="1716678171679" TEXT="ein reiner Funktor f&#xfc;r Dependency-Injection">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
man m&#246;chte ein reines Funktor-Objekt, das <i>irgendwie hintenrum verdrahtet ist.</i>&#160;Auf diesem ruft man nur noch den Funktionsoperator auf mit den konkreten Argumenten, denn der Zieltyp ist bereits festgelegt
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1716678038748" ID="ID_763364439" MODIFIED="1716678513794" TEXT="Front-End &#x2014; zum Erzeugen beliebiger Typen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...auch hier soll die Verdrahtung <i>verborgen bleiben; </i>jedoch ist man nicht auf einen Objekttyp festgelegt, und au&#223;erdem soll es die M&#246;glichkeit geben, esplizit eine <font face="Monospaced">destroy()</font>-Funktion aufzurufen, oder alternativ schon aus der Erzeugung ein <i>managing-handle </i>zu bekommen
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1716678081327" ID="ID_1023398550" MODIFIED="1716678667304" TEXT="Policy &#x2014; Steuern von Teilaspekten">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Speziell bei Containern treten verschiedene Nutzungsmuster und Variationen auf...
</p>
<ul>
<li>
man m&#246;chte das Erzeugen neuer Objekte komplett unterbinden
</li>
<li>
man m&#246;chte zum Erzeugen einen eingebetteten Custom-Allocator verwenden
</li>
<li>
man m&#246;chte Destuktoren aufrufen oder nicht aufrufen
</li>
<li>
man m&#246;chte beim Verwerfen eines Objekts die Allokation freigeben oder auch nicht und ggfs. auch blo&#223; mitz&#228;hlen
</li>
</ul>
</body>
</html></richcontent>
</node>
<node CREATED="1716678671271" ID="ID_1764893919" MODIFIED="1716678787519" TEXT="Standard Low-level-Allokator">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Das ist in etwa die Funktionalit&#228;t, die man von der Standard-Library bekommt, und die damit auch von STL-Containern genutzt werden kann; eigentlich braucht man hier nur die Bereitstellung (und Freigabe) von uninitialisiertem Speicher; das eigentliche Konstruieren und Zerst&#246;ren erledigen die <font face="Monospaced">std::allocator_traits</font>
</p>
</body>
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1716683768504" ID="ID_1462693245" MODIFIED="1716683781871" TEXT="Draft / Prototyping">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716683783293" ID="ID_910814489" MODIFIED="1716683827701" TEXT="Standard-Allocator in LinkedElements integrieren">
<linktarget COLOR="#515b9a" DESTINATION="ID_910814489" ENDARROW="Default" ENDINCLINATION="167;-10;" ID="Arrow_ID_96021000" SOURCE="ID_48162464" STARTARROW="None" STARTINCLINATION="168;8;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716683843917" ID="ID_157117808" MODIFIED="1716684087738" TEXT="Standard-Allocator f&#xfc;r AllocationCluster bereitstellen">
<linktarget COLOR="#664940" DESTINATION="ID_157117808" ENDARROW="Default" ENDINCLINATION="1249;67;" ID="Arrow_ID_572544135" SOURCE="ID_1456163487" STARTARROW="None" STARTINCLINATION="131;-1027;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
<node CREATED="1716677442605" ID="ID_1120140540" MODIFIED="1716677451141" TEXT="speziell...">
<node CREATED="1716677468353" ID="ID_1849931457" MODIFIED="1716677717812" TEXT="AllocationCluster (f&#xfc;r Node-Network)">
<arrowlink COLOR="#5e576b" DESTINATION="ID_688601712" ENDARROW="Default" ENDINCLINATION="-933;-99;" ID="Arrow_ID_1200230919" STARTARROW="None" STARTINCLINATION="-758;59;"/>
</node>
<node CREATED="1716677865819" ID="ID_884450390" MODIFIED="1716677938838" TEXT="BlockFlow (f&#xfc;r Scheduler-Activities)">
<arrowlink COLOR="#504f86" DESTINATION="ID_1478014419" ENDARROW="Default" ENDINCLINATION="-665;-48;" ID="Arrow_ID_1014939669" STARTARROW="None" STARTINCLINATION="-1064;85;"/>
</node>
</node>
</node>
<node CREATED="1696538097698" ID="ID_762902476" MODIFIED="1696538102051" TEXT="Concurrency">
@ -81623,7 +81702,16 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1715782747520" ID="ID_1770179360" MODIFIED="1715782759542" TEXT="node-basic-test: OK"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715782790810" ID="ID_1391251855" MODIFIED="1715782799529" TEXT="linked-elements-test: ">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1715815439855" ID="ID_1456163487" MODIFIED="1715815486736" TEXT="sollte LinkedElements umstellen auf Standard-konformen Allocator"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1715815439855" ID="ID_1456163487" MODIFIED="1716684137464" TEXT="sollte LinkedElements umstellen auf Standard-konformen Allocator">
<arrowlink COLOR="#664940" DESTINATION="ID_157117808" ENDARROW="Default" ENDINCLINATION="1249;67;" ID="Arrow_ID_572544135" STARTARROW="None" STARTINCLINATION="131;-1027;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1716684095508" ID="ID_1857326363" MODIFIED="1716684131661" TEXT="der mu&#xdf; dann die default-Policy ersetzen">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1716684105741" ID="ID_1677827906" MODIFIED="1716684129032" TEXT="also: Ownership + gegebenen Standard-Allocator als Schnittstelle">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1715815513228" ID="ID_1909349257" MODIFIED="1715815549523" TEXT="die NoOwnership-Policy wird dann zu einem speziellen Allocator"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1715782815501" ID="ID_845459708" MODIFIED="1715782818814" TEXT="Nodefactory">
@ -81700,9 +81788,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node COLOR="#338800" CREATED="1716563047722" ID="ID_848423419" MODIFIED="1716566615378" TEXT="Storage-Diagnose">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
mu&#223; hier leider eine schecklicke low-level-Trickserei machen; das ist die Konsequenz der Entscheidung, mit dem absolut minimalen Storage-Overhead zu arbeiten, und au&#223;erdem mu&#223; ich auch noch das Non-Copyable <i>aushebeln...</i>
@ -82144,9 +82230,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1680563454868" ID="ID_1187556686" MODIFIED="1680563459014" TEXT="Backbone"/>
<node CREATED="1680563460649" ID="ID_127710483" MODIFIED="1715624384997" TEXT="MemManagement">
<arrowlink COLOR="#454059" DESTINATION="ID_1595450559" ENDARROW="Default" ENDINCLINATION="-1036;-77;" ID="Arrow_ID_1704085390" STARTARROW="None" STARTINCLINATION="-161;430;"/>
<node CREATED="1715623566743" ID="ID_688601712" MODIFIED="1715624494222" TEXT="AllocationCluster">
<node CREATED="1715623566743" ID="ID_688601712" MODIFIED="1716677717812" TEXT="AllocationCluster">
<linktarget COLOR="#816f7b" DESTINATION="ID_688601712" ENDARROW="Default" ENDINCLINATION="95;-321;" ID="Arrow_ID_1440452458" SOURCE="ID_1219678116" STARTARROW="None" STARTINCLINATION="-521;38;"/>
<linktarget COLOR="#816f7b" DESTINATION="ID_688601712" ENDARROW="Default" ENDINCLINATION="95;-321;" ID="Arrow_ID_859179840" SOURCE="ID_303611553" STARTARROW="None" STARTINCLINATION="-264;24;"/>
<linktarget COLOR="#5e576b" DESTINATION="ID_688601712" ENDARROW="Default" ENDINCLINATION="-933;-99;" ID="Arrow_ID_1200230919" SOURCE="ID_1849931457" STARTARROW="None" STARTINCLINATION="-758;59;"/>
<node CREATED="1715786334834" ID="ID_885525745" MODIFIED="1715786341860" TEXT="Design / Systematik">
<node CREATED="1715786372102" ID="ID_1591071302" MODIFIED="1715786382355" TEXT="Aufwand f&#xfc;r Memory-Management wird geb&#xfc;ndelt"/>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1715786522984" ID="ID_1870113951" MODIFIED="1715786580201" TEXT="Konflikt: Performance &#x27f7; Sicherheit">
@ -121704,6 +121791,7 @@ std::cout &lt;&lt; tmpl.render({&quot;what&quot;, &quot;World&quot;}) &lt;&lt; s
<node CREATED="1688438172401" ID="ID_1302126473" MODIFIED="1688438176429" TEXT="Memory-Manager">
<node COLOR="#338800" CREATED="1693840789997" ID="ID_1478014419" MODIFIED="1693840887589" TEXT="BlockFlow (custom allocation scheme)">
<arrowlink COLOR="#578096" DESTINATION="ID_1810148055" ENDARROW="Default" ENDINCLINATION="-1144;102;" ID="Arrow_ID_1579502372" STARTARROW="None" STARTINCLINATION="549;39;"/>
<linktarget COLOR="#504f86" DESTINATION="ID_1478014419" ENDARROW="Default" ENDINCLINATION="-665;-48;" ID="Arrow_ID_1014939669" SOURCE="ID_884450390" STARTARROW="None" STARTINCLINATION="-1064;85;"/>
<icon BUILTIN="forward"/>
</node>
</node>