diff --git a/src/lib/several.hpp b/src/lib/several.hpp index 6424be073..2ccdcb1d4 100644 --- a/src/lib/several.hpp +++ b/src/lib/several.hpp @@ -158,7 +158,7 @@ namespace lib { * Typically the return type is an interface, * and the Implementation wraps some datastructure * holding subclasses. - * @warning in rework 5/2025 + * @note may only be populated through SeveralBuilder */ template class Several @@ -169,9 +169,9 @@ namespace lib { Bucket data_{nullptr}; - Several() =default; ///< may only be created through SeveralBuilder - public: + Several() =default; ///< usually to be created through SeveralBuilder + ~Several() noexcept try { if (data_) data_->destroy(); } ERROR_LOG_AND_IGNORE (progress, "clean-up Several data") diff --git a/tests/library/several-builder-test.cpp b/tests/library/several-builder-test.cpp index a47538e71..b407e6683 100644 --- a/tests/library/several-builder-test.cpp +++ b/tests/library/several-builder-test.cpp @@ -551,7 +551,10 @@ namespace test{ } + /** @test TODO demonstrate integration with a custom allocator + * - use the TrackingAllocator to verify balanced handling + * of the underlying raw memory allocations * @todo WIP 6/24 šŸ” define ⟶ šŸ” implement */ void @@ -559,36 +562,47 @@ namespace test{ { CHECK (0 == Dummy::checksum()); CHECK (0 == TrackingAllocator::checksum()); -SHOW_EXPR(TrackingAllocator::numAlloc()); -SHOW_EXPR(TrackingAllocator::numBytes()); -SHOW_EXPR(TrackingAllocator::use_count()); - auto& log = TrackingAllocator::log; - log.clear("Several-Builder-Test"); + + Several elms; + size_t expectedAlloc; + CHECK (0 == TrackingAllocator::numAlloc()); + CHECK (0 == TrackingAllocator::use_count()); { auto builder = makeSeveral() - .withAllocator(); -SHOW_TYPE(decltype(builder)) -SHOW_EXPR(builder.size()) -SHOW_EXPR(builder.capacity()) - builder.fillElm(55); -SHOW_EXPR(builder.size()) -SHOW_EXPR(builder.capacity()) - -SHOW_EXPR(TrackingAllocator::numAlloc()); -SHOW_EXPR(TrackingAllocator::numBytes()); -SHOW_EXPR(TrackingAllocator::use_count()); -SHOW_EXPR(TrackingAllocator::checksum()); + .withAllocator() + .fillElm(55); + + size_t elmSiz = sizeof(Dummy); + size_t buffSiz = elmSiz * builder.capacity(); + size_t headerSiz = sizeof(ArrayBucket); + expectedAlloc = headerSiz + buffSiz; + + CHECK (TrackingAllocator::numBytes() == expectedAlloc); + CHECK (TrackingAllocator::numAlloc() == 1); + CHECK (TrackingAllocator::use_count()== 2); // one instance in the builder, one in the deleter + CHECK (TrackingAllocator::checksum() > 0); + + elms = builder.build(); } + CHECK (elms.size() == 55); + CHECK (TrackingAllocator::numBytes() == expectedAlloc); + CHECK (TrackingAllocator::numAlloc() == 1); + CHECK (TrackingAllocator::use_count()== 1); // only one allocator instance in the deleter left + + auto others = move(elms); + CHECK (elms.size() == 0); + CHECK (others.size() == 55); + CHECK (TrackingAllocator::numBytes() == expectedAlloc); + CHECK (TrackingAllocator::numAlloc() == 1); + CHECK (TrackingAllocator::use_count()== 1); + + others = move(Several{}); // automatically triggers de-allocation + CHECK (others.size() == 0); + CHECK (0 == Dummy::checksum()); -SHOW_EXPR(TrackingAllocator::numAlloc()); -SHOW_EXPR(TrackingAllocator::numBytes()); -SHOW_EXPR(TrackingAllocator::use_count()); -SHOW_EXPR(TrackingAllocator::checksum()); - - cout << "____Tracking-Allo-Log_________\n" - << util::join(TrackingAllocator::log,"\n") - << "\n───╼━━━━━━━━━━━━━━━━━╾────────"< - - + + @@ -83507,7 +83507,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -83523,7 +83523,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -83563,8 +83563,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -83626,6 +83626,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +
@@ -83693,7 +83697,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -83971,9 +83975,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + @@ -83983,8 +83987,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
-
- + + @@ -83994,13 +83998,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + - - - +

denn dort rufen wir den Destruktor-Funktor explizit auf, anstatt den Destruktor von ArrayBucket aufzurufe @@ -84011,9 +84014,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...denn auch am Ende bleibt ein use-cnt übrig, obwohl doch in diesem Fall letztlich der Destruktor des Funktors aufgerufen werden sollte, wenngleich auch bereits nach der de-Allokation (!) @@ -84024,9 +84025,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

...deshalb habe ich da so sonderbar darum herum gecodet. Ich dachte mir, kein Problem, ArrayBucket ist ja sowiso ein POD. Und dann bin ich »eingeknickt« und habe doch eine std::function genommen. Und deren Destruktor muß aufgerufen werden @@ -84042,9 +84041,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

weil vor jeder regulären Änderung der Checksumme auch ein Log-Aufruf steht. Und die Log-Einträge sehen allesamt korrekt und balanaciert aus @@ -84062,9 +84059,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - +

  • @@ -84080,9 +84075,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...fälschlicherweise der laufende Allokations-Counter verwendet @@ -84108,9 +84101,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    - - - +

    ...konkret, ich plane einen Satz an Steuer-Flags, und auf dieser Basis dann die Belegung weiterer Storage; im einfachsten Fall gibt es keinen Spread, keinen Deleter und einen Standard-Offset; es muß dann nur die Element-Zahl und Kapazität gespeichert werden. @@ -84135,6 +84126,43 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + +

      +
    • + provoziere mehrere re-Allokationen +
    • +
    • + prüfe die use-counts für die eingebetteten Allokator-Instanzen +
    • +
    • + move-Asignments räumen auch sauber auf +
    • +
    + +
    + +
    + + + + + + + + + + + + + + + + + +