From 802fef9b7ce2d60a93943c6da10bbd4f6ebf5848 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 4 Jun 2024 23:24:11 +0200 Subject: [PATCH] Library: work out Skeleton for memory-handling strategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - the basic decision is to implement ''realloc'' similar to `std::vector` - however the situation is complicated by the desire to allow arbitrary element types - ⟹ must build a strategy based on the properties of the target type - the completely dynamic growth is only possibly for trivially-movable types - can introduce a dedicated ''element type'' though, and store a trampolin handler --- src/lib/several-builder.hpp | 53 ++++++- wiki/thinkPad.ichthyo.mm | 267 +++++++++++++++++++++++++++++++----- 2 files changed, 281 insertions(+), 39 deletions(-) diff --git a/src/lib/several-builder.hpp b/src/lib/several-builder.hpp index 3b2401a8f..61867a8c2 100644 --- a/src/lib/several-builder.hpp +++ b/src/lib/several-builder.hpp @@ -47,6 +47,7 @@ #include "lib/iter-explorer.hpp" #include "lib/util.hpp" +#include #include #include #include @@ -69,13 +70,59 @@ namespace lib { UNIMPLEMENTED ("adjust memory allocation"); ///////////////////////////OOO Problem Objekte verschieben } }; + + using std::is_trivially_move_constructible_v; + using std::is_trivially_destructible_v; + using std::has_virtual_destructor_v; + using std::is_same_v; + using lib::meta::is_Subclass; + + template + struct MemStrategy + { + bool disposable :1 ; + bool wild_move :1 ; + + template + bool + canDestroy() + { + return disposable + or (is_trivially_destructible_v and is_trivially_destructible_v) + or (has_virtual_destructor_v and is_Subclass()) + or (is_same_v and is_Subclass()); + } + + template + bool + canDynGrow() + { + return is_same_v + or (is_trivially_move_constructible_v and wild_move); + } + + auto + getDeleter() + { + if constexpr (disposable or + (is_trivially_destructible_v and is_trivially_destructible_v)) + return nullptr; + if constexpr (has_virtual_destructor_v) + return nullptr; + else + return nullptr; + } + }; } /** * Wrap a vector holding objects of a subtype and * provide array-like access using the interface type. */ - template + template + ,class E =I ///< a subclass element element type (relevant when not trivially movable and destructible) + ,class POL =HeapOwn ///< Allocator policy + > class SeveralBuilder : Several , POL @@ -121,7 +168,7 @@ namespace lib { adjustStorage (size_t cnt, size_t spread) { if (cnt*spread > storageSiz_) - {// need more storage.. + { // need more storage... Col::data_ = static_cast (POL::realloc (Col::data_, storageSiz_, cnt*spread)); storageSiz_ = cnt*spread; } @@ -130,7 +177,7 @@ namespace lib { adjustSpread (spread); if (cnt*spread < storageSiz_) - {// attempt to shrink storage + { // attempt to shrink storage Col::data_ = static_cast (POL::realloc (Col::data_, storageSiz_, cnt*spread)); storageSiz_ = cnt*spread; } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 59ea1f6b8..57253f371 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81444,16 +81444,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...man verwendet nur speziell im produktiven Einsatz im Node-Graph  einen besonderen Allocator, der zwar den Destruktor aufruft, aber den Speicher nicht freigibt; alloziert wird immer in einen kompakten Block hinein, der dann auf der Basis der Prozeß-Kenntnis als Ganzes verworfen und neu verwendet wird.

- -
+
@@ -81680,16 +81677,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

Konsequenz: man kann einen einzigen Typ Several<X> anschreiben

- -
+
@@ -81750,42 +81744,33 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...und zwar vor allem durch den AllocationCluster mit einer festen Extent-Size. Vorhersehbar werden die Extents meist zu groß sein...

- -
+
- - - +

...und was noch besser ist: die Storage liegt kompakt

- -
+
- - - +

...weil wir durch den Connectivity-Descriptor bereits eine gefährlich komplexes Stück Metaprogramming haben, mit dem Risiko kombinatorischer Explosion

- -
+
@@ -81820,16 +81805,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

diese Funktion würde eine Exception werfen, wen das ArrayBucket eben doch ownership-managed ist. Ansonsten erzeugt sie eine neue Instanz mit Verweis auf das gemeinsam nutzbare Bucket

- -
+
@@ -81851,16 +81833,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...weil ich den Zieltyp zum Cast nicht dynamisch konstruieren kann

- -
+
@@ -81885,8 +81864,224 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Same as std::move unless the type's move constructor could throw and the type is copyable, in which case an lvalue-reference is returned instead. +

+ +
+ +
+ + + + +

+ __and_<__not_<is_nothrow_move_constructible<_Tp>> +

+

+       , is_copy_constructible<_Tp>> +

+ +
+ + + + + + + + + + + + + + + + + + + + + + +

+ sonst: _M_realloc_insert +

+ +
+ + + + + + + + + + + + + + + + +

+ die C-Funktion realloc() kann zwar scheinbar „zaubern“, ist aber tatsächlich auf Hilfe vom Allokator angewiesen, insofern dieser sich intern gewisse zusätzliche Reserven sichert. Und wenn seine Resevern nicht reichen, dann wird sofort woanders alloziert und alles per memmove()  umkopiert.... +

+ + +
+
+ + + + +

+ Tatsächlich kann std::vector() dasselbe besser machen, da er ggfs move-Konstruktoren aufrufen und außerdem als zusätzliche Heuristik die aktuelle Größe des Vektors heranziehen kann, um eine angemessene Reserve bereitzustellen; außerdem ist die Größe der Reserve direkt auf das API herausgeführt. +

+ + +
+
+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +