diff --git a/src/lib/several-builder.hpp b/src/lib/several-builder.hpp index a54036b87..fa0f8b75b 100644 --- a/src/lib/several-builder.hpp +++ b/src/lib/several-builder.hpp @@ -114,7 +114,7 @@ namespace lib { using BucketAlloT = typename AlloT::template rebind_traits; auto bucketAllo = adaptAllocator(); - try { BucketAlloT::construct (bucketAllo, bucket, storageBytes, spread); } + try { BucketAlloT::construct (bucketAllo, bucket, cnt*spread, spread); } catch(...) { AlloT::deallocate (baseAllocator(), loc, storageBytes); @@ -149,7 +149,7 @@ namespace lib { for (size_t idx=0; idxsubscript(idx)); } - size_t storageBytes = bucket->buffSiz; + size_t storageBytes = Bucket::requiredStorage (bucket->buffSiz); std::byte* loc = reinterpret_cast (bucket); AlloT::deallocate (baseAllocator(), loc, storageBytes); }; @@ -313,16 +313,16 @@ namespace lib { __ensureMark (VIRTUAL); return [factory](ArrayBucket* bucket){ unConst(factory).template destroy (bucket); }; } - if (is_same_v and is_Subclass()) - { - __ensureMark (ELEMENT); - return [factory](ArrayBucket* bucket){ unConst(factory).template destroy (bucket); }; - } if (is_trivially_destructible_v) { __ensureMark (TRIVIAL); return [factory](ArrayBucket* bucket){ unConst(factory).template destroy (bucket); }; } + if (is_same_v and is_Subclass()) + { + __ensureMark (ELEMENT); + return [factory](ArrayBucket* bucket){ unConst(factory).template destroy (bucket); }; + } throw err::Invalid{_Fmt{"Unsupported kind of destructor for element type %s."} % util::typeStr()}; } diff --git a/src/lib/several.hpp b/src/lib/several.hpp index f17cd9f0f..da57eed7e 100644 --- a/src/lib/several.hpp +++ b/src/lib/several.hpp @@ -48,14 +48,12 @@ ** random access through references to a interface type. It can only be created ** and populated through a builder, and is immutable during lifetime, while it ** can hold non-const element data. The actual implementation data types and the - ** allocator framework used are _not exposed in the front-end's type signature._ + ** employed allocator framework are _not exposed in the front-end's type signature._ ** The container is single-ownership (move-asignable); some additional metadata - ** and the data storage reside in an `ArrayBucket`, managed by the allocator. + ** and the data storage reside within an `ArrayBucket`, managed by the allocator. ** In its simplest form, this storage is heap allocated and automatically deleted. ** - ** @todo as of 2016, this concept seems very questionable: do we _really_ want - ** to abstract over random access, or do we _actually_ want for-iteration?? - ** @warning WIP-WIP-WIP in rework 5/2025 + ** @warning WIP-WIP in rework 6/2025 ** @see several-builder.hpp */ @@ -98,7 +96,7 @@ namespace lib { static size_t - requiredStorage (size_t cnt, size_t spread) + requiredStorage (size_t cnt, size_t spread =1) { return sizeof(ArrayBucket) - sizeof(storage) + cnt * spread; @@ -113,6 +111,7 @@ namespace lib { std::byte* elm = storage; size_t off = idx * spread; elm += off; + ENSURE (storage <= elm and elm < storage+buffSiz); return * std::launder (reinterpret_cast (elm)); } @@ -152,8 +151,15 @@ namespace lib { ERROR_LOG_AND_IGNORE (progress, "clean-up Several data") /// Move-Assignment allowed... - Several (Several&&) =default; - Several& operator= (Several&&) =default; + Several (Several&& rr) + { + std::swap (data_, rr.data_); + } + Several& operator= (Several&& rr) + { + std::swap (data_, rr.data_); + return *this; + } size_t size() const @@ -174,8 +180,8 @@ namespace lib { return data_->subscript (idx); } - I& front() { return operator[] (data_? data_->size_-1 : 0); } - I& back() { return operator[] (0); } + I& front() { return operator[] (0); } + I& back() { return operator[] (data_? data_->cnt-1 : 0); } using iterator = I*; using const_iterator = I const*; diff --git a/tests/library/several-builder-test.cpp b/tests/library/several-builder-test.cpp index 3545d1011..71cf2600c 100644 --- a/tests/library/several-builder-test.cpp +++ b/tests/library/several-builder-test.cpp @@ -117,7 +117,7 @@ namespace test{ /** @test TODO demonstrate basic behaviour - * @todo WIP 5/24 🔁 define ⟶ implement + * @todo WIP 6/24 ✔ define ⟶ 🔁 implement */ void simpleUsage() @@ -131,7 +131,7 @@ namespace test{ /** @test TODO various ways to build an populate the container - * @todo WIP 5/24 🔁 define ⟶ implement + * @todo WIP 6/24 🔁 define ⟶ implement */ void check_Builder() @@ -140,7 +140,7 @@ namespace test{ /** @test TODO proper handling of exceptions during population - * @todo WIP 5/24 🔁 define ⟶ implement + * @todo WIP 6/24 🔁 define ⟶ implement */ void check_ErrorHandling() @@ -149,7 +149,7 @@ namespace test{ /** @test TODO verify access operations on the actual container - * @todo WIP 5/24 🔁 define ⟶ implement + * @todo WIP 6/24 🔁 define ⟶ implement */ void check_ElementAccess() @@ -158,7 +158,7 @@ namespace test{ /** @test TODO demonstrate integration with a custom allocator - * @todo WIP 5/24 🔁 define ⟶ implement + * @todo WIP 6/24 🔁 define ⟶ implement */ void check_CustomAllocator() diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index e6e91681a..393cf8fc3 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81711,19 +81711,28 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + - - + + + + + + + + + + + @@ -83041,14 +83050,80 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - - + + + + + + + + + + + + + + + + + + +

+ ...denn die default-Impl kopiert skalare Typen lediglich; hier müssen wir sie aber wirklich austauschen, damit nur eine Instanz den aktiven Pointer hält... +

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

+ storageBytes wird nur in der Factory benötigt und ist die Größe der gesamten Allokation incl Admin-Overhead +

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

+ ....und das wird praktisch immer greifen, wenn Element-Typ und Interface-Typ identisch sind; es steht zu befürchten daß deshalb der triviale destruktur praktisch nie zum Tragen kommt. Anders herum bestünde auch keine Gefahr, daß ein erstes Element, das auch ein Subtyp sein könnte, eine Entscheidung für TRIVIAL fällen würde, denn der ELEMENT-Fall fordert ja grade, daß alle Elemente den gleichen Typ haben; also wäre eine solche Festlegung auch in diesem Fall sogar vorteilhaft, da sie den Destruktor-Aufruf einspart +

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