From 08e0f52e6182a27437a9613d219dc1fb926898af Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 25 May 2024 20:01:23 +0200 Subject: [PATCH] Library: low-level implementation internals covered ...including overflow into new extents, alignment padding and chaining and invocation of destructors. --- src/lib/allocation-cluster.hpp | 5 --- tests/library/allocation-cluster-test.cpp | 49 ++++++++++++++++------- wiki/thinkPad.ichthyo.mm | 43 +++++++++++--------- 3 files changed, 59 insertions(+), 38 deletions(-) diff --git a/src/lib/allocation-cluster.hpp b/src/lib/allocation-cluster.hpp index 43df8f2a3..ac9c92337 100644 --- a/src/lib/allocation-cluster.hpp +++ b/src/lib/allocation-cluster.hpp @@ -28,11 +28,6 @@ ** created within a single build process and is replaced or released ** as a whole. AllocationCluster implements memory management to ** support this usage pattern. - ** - ** @warning in rework 5/2024 — with the goal to simplify the logic, - ** remove all thread safety and make the implementation - ** usable as standard conformant allocator for STL. - ** ** @see allocation-cluster-test.cpp ** @see builder::ToolFactory ** @see linked-elements.hpp diff --git a/tests/library/allocation-cluster-test.cpp b/tests/library/allocation-cluster-test.cpp index 921d00693..e2ecb72e7 100644 --- a/tests/library/allocation-cluster-test.cpp +++ b/tests/library/allocation-cluster-test.cpp @@ -37,14 +37,12 @@ #include #include #include -//#include -//using boost::lexical_cast; +using ::Test; using lib::explore; using lib::test::showSizeof; using util::getAddr; using util::isnil; -using ::Test; using std::numeric_limits; using std::function; @@ -65,7 +63,7 @@ namespace test { const size_t BLOCKSIZ = 256; ///< @warning actually defined in allocation-cluster.cpp - long checksum = 0; // validate proper pairing of ctor/dtor calls + int64_t checksum = 0; // validate proper pairing of ctor/dtor calls template class Dummy @@ -85,7 +83,7 @@ namespace test { checksum -= explore(content_).resultSum(); } - char getID() { return content_[0]; } + uint getID() { return content_[0]; } }; @@ -189,13 +187,14 @@ namespace test { } + /** @test cover some tricky aspects of the low-level allocator * @remark due to the expected leverage of AllocationCluster, * an optimised low-level approach was taken on various aspects of storage management; * the additional metadata overhead is a power of two, exploiting contextual knowledge * about layout; moreover, a special usage-mode allows to skip invocation of destructors. * To document these machinations, change to internal data is explicitly verified here. - * @todo WIP 5/24 🔁 define ⟶ 🔁 implement + * @todo WIP 5/24 ✔ define ⟶ ✔ implement */ void verifyInternals() @@ -252,7 +251,8 @@ namespace test { // existing storage unaffected CHECK (i1 == i1pre); CHECK (i2 == 55555); - CHECK (slot(0) == 0); + CHECK (slot(0) == 0); // no administrative data yet... + CHECK (slot(1) == 0); // alignment is handled properly char& c1 = clu.create ('X'); @@ -296,7 +296,7 @@ namespace test { markSum = checksum; CHECK (checksum == 4+4); CHECK (alignof(Dummy<2>) == alignof(char)); - CHECK (posOffset() - pp == sizeof(Dummy<2>)); + CHECK (posOffset() - pp == sizeof(Dummy<2>)); // for disposable objects only the object storage itself plus alignment // allocate a similar object, // but this time also enrolling the destructor @@ -314,21 +314,42 @@ namespace test { // any other object with non-trivial destructor.... string rands = lib::test::randStr(9); pp = posOffset(); - string& s1 = clu.create (rands); -SHOW_EXPR(pp) -SHOW_EXPR(posOffset()) -SHOW_EXPR(size_t(&s1)) + string& s1 = clu.create (rands); // a string that fits into the small-string optimisation + CHECK (s1 == rands); + CHECK (posOffset() - pp >= sizeof(string) + 2*sizeof(void*)); CHECK (size_t(&s1) - slot(1) == 2*sizeof(void*)); // again the Destructor frame is placed immediately before the object auto dtor2 = (Dtor*)slot(1); // and it has been prepended to the destructors-list in current extent -SHOW_EXPR(size_t(dtor2->next)) CHECK (dtor2->next == dtor); // with the destructor of o2 hooked up behind CHECK (dtor->next == nullptr); + + // provoke overflow into a new extent + // by placing an object that does not fit + // into the residual space in current one + auto& o3 = clu.create> (3); + CHECK (clu.numExtents() == 3); // a third extent has been opened to accommodate this object + CHECK (checksum == markSum + 8+8 + uchar(223*3)); + auto dtor3 = (Dtor*)slot(1); + CHECK (dtor3->next == nullptr); // Destructors are chained for each extent separately + CHECK (dtor3 != dtor2); + CHECK (dtor2->next == dtor); // the destructor chain from previous extent is also still valid + CHECK (dtor->next == nullptr); + + CHECK (i1 == i1pre); // all data is intact (no corruption) + CHECK (s1 == rands); + CHECK (i2 == 55555); + CHECK (c1 == 'X'); + CHECK (c2 == 'U'); + CHECK (i3 == 42); + CHECK (o1.getID() == 4); + CHECK (o2.getID() == 8); + CHECK (o3.getID() == 3); } - CHECK (checksum == markSum); + CHECK (checksum == markSum); // only the destructor of the "disposable" object o1 was not invoked } + /** @test TODO demonstrate use as Standard-Allocator * @todo WIP 5/24 🔁 define ⟶ implement */ diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index e00fd6639..1a291ed56 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -81637,8 +81637,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81651,8 +81651,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81666,8 +81666,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81759,8 +81759,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81836,7 +81836,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -81870,9 +81871,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + @@ -81895,8 +81896,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -81909,6 +81910,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + + @@ -81929,11 +81934,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + - + @@ -81964,8 +81969,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + +