From db4fbde201ad2c23de496f3fc866360581ddf583 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 27 May 2024 21:21:03 +0200 Subject: [PATCH] Library: adapt further `AllocationCluster` tests ...especially demonstrate that destructors can optionally be invoked or not invoked... --- src/lib/allocation-cluster.hpp | 14 +++++++---- src/lib/allocator-handle.hpp | 7 +++++- tests/library/allocation-cluster-test.cpp | 29 +++++++++++++++++++---- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/lib/allocation-cluster.hpp b/src/lib/allocation-cluster.hpp index cdb69aae9..ae76f1336 100644 --- a/src/lib/allocation-cluster.hpp +++ b/src/lib/allocation-cluster.hpp @@ -24,10 +24,14 @@ ** Memory management for the low-level model (render nodes network). ** The model is organised into temporal segments, which are considered ** to be structurally constant and uniform. The objects within each - ** segment are strongly interconnected, and thus each segment is - ** created within a single build process and is replaced or released - ** as a whole. AllocationCluster implements memory management to - ** support this usage pattern. + ** segment are strongly interconnected, and thus each segment is created + ** within a single build process and is replaced or released as a whole. + ** AllocationCluster implements memory management to support this usage + ** pattern. Optionally it is even possible to skip invocation of object + ** destructors, making de-allocation highly efficient (typically the + ** memory pages are already cache-cold when about to discarded). + ** @warning deliberately *not threadsafe*. + ** @remark confine usage to a single thread or use thread-local clusters. ** @see allocation-cluster-test.cpp ** @see builder::ToolFactory ** @see linked-elements.hpp @@ -58,7 +62,7 @@ namespace lib { * is to bulk-allocate memory, and to avoid invoking destructors (and thus to access * a lot of _cache-cold memory pages_ on clean-up). A Stdlib compliant #Allocator * is provided for use with STL containers. The actual allocation uses heap memory - * in _extents_ of hard-wired size, by the accompanying StorageManager. + * in _extents_ of hard-wired size, maintained by the accompanying StorageManager. * @warning use #createDisposable whenever possible, but be sure to understand * the ramifications of _not invoking_ an object's destructor. */ diff --git a/src/lib/allocator-handle.hpp b/src/lib/allocator-handle.hpp index 3efeb6841..6bbfa3d79 100644 --- a/src/lib/allocator-handle.hpp +++ b/src/lib/allocator-handle.hpp @@ -117,7 +117,12 @@ namespace lib { construct (typename ALOT::allocator_type& allo, ARGS&& ...args) { auto loc = ALOT::allocate (allo, 1); - ALOT::construct (allo, loc, std::forward(args)...); + try { ALOT::construct (allo, loc, std::forward(args)...); } + catch(...) + { + ALOT::deallocate (allo, loc, 1); + throw; + } return loc; } diff --git a/tests/library/allocation-cluster-test.cpp b/tests/library/allocation-cluster-test.cpp index e2ecb72e7..030b5ca1f 100644 --- a/tests/library/allocation-cluster-test.cpp +++ b/tests/library/allocation-cluster-test.cpp @@ -143,8 +143,8 @@ namespace test { virtual void run (Arg) { -// simpleUsage(); -// checkLifecycle(); + simpleUsage(); + checkLifecycle(); verifyInternals(); use_as_Allocator(); } @@ -154,25 +154,31 @@ namespace test { simpleUsage() { AllocationCluster clu; + CHECK (0 == clu.numExtents()); char c1(123), c2(45); Dummy<66>& ref1 = clu.create> (); Dummy<77>& ref2 = clu.create> (c1); Dummy<77>& ref3 = clu.create> (c2); -// TRACE (test, "%s", showSizeof(rX).c_str());///////////////////////OOO - //returned references actually point at the objects we created CHECK (1 ==ref1.getID()); CHECK (123==ref2.getID()); CHECK (45 ==ref3.getID()); - CHECK (1 == clu.numExtents()); + CHECK (0 < clu.numExtents()); // now use objects and just let them go; } + /** @test Allocation cluster grows when adding objects, + * but discards all objects at once when going out of scope, + * optionally also invoking (or not invoking) destructors. + * @remark no destructors are invoked for any objects allocated + * through the `createDisposable(args...)` interface, + * or for allocations though the standard allocator adapter. + */ void checkLifecycle() { @@ -184,6 +190,19 @@ namespace test { CHECK (0!=checksum); } CHECK (0==checksum); + + int64_t allSum; + {// can also be used without invoking any destructors + AllocationCluster clu; + for (uint i=0; i>(); + + CHECK (clu.numExtents() == NUM_OBJECTS); + CHECK (checksum == NUM_OBJECTS * 223); + allSum = checksum; + }// Memory discarded here without invoking any destructor.... + CHECK (allSum == checksum); + checksum = 0; }