Library: build adaptor for automated unique-ownership
This adaptor works in concert with the generic allocator building blocks (prospective ''Concepts'') and automatically registers a either static or dynamic back-link to the factory for clean-up. Use this wrapper fore more in-depth test of the new `TrackingAllocator` and verify proper behaviour through the `EventLog`
This commit is contained in:
parent
be3cf61111
commit
10edc31eac
6 changed files with 372 additions and 50 deletions
|
|
@ -164,6 +164,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
|
||||
/** create new element using the embedded allocator */
|
||||
template<class TY, typename...ARGS>
|
||||
TY*
|
||||
|
|
@ -198,6 +199,92 @@ namespace lib {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Metafunction: probe if the given base factory is possibly monostate */
|
||||
template<class FAC>
|
||||
struct is_Stateless
|
||||
: std::__and_< std::is_empty<FAC>
|
||||
, std::is_default_constructible<FAC>
|
||||
>
|
||||
{ };
|
||||
template<class FAC>
|
||||
auto is_Stateless_v = is_Stateless<FAC>{};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to use a _generic factory_ \a FAC for
|
||||
* creating managed object instances with unique ownership.
|
||||
* Generated objects are attached to a `std::unique_ptr` handle,
|
||||
* which enforces scoped ownership and destroys automatically.
|
||||
* The factory can either be stateless (≙monostate) or tied
|
||||
* to a distinct, statefull allocator or manager backend.
|
||||
* In the latter case, this adapter must be created with
|
||||
* appropriate wiring and each generated `unique_ptr` handle
|
||||
* will also carry a back-reference to the manager instance.
|
||||
*/
|
||||
template<class FAC>
|
||||
class OwnUniqueAdapter
|
||||
: protected FAC
|
||||
{
|
||||
template<typename TY>
|
||||
static void
|
||||
dispose (TY* elm) ///< @internal callback for unique_ptr using stateless FAC
|
||||
{
|
||||
FAC factory;
|
||||
factory.dispose (elm);
|
||||
};
|
||||
|
||||
template<typename TY>
|
||||
struct StatefulDeleter ///< @internal callback for unique_ptr using statefull FAC
|
||||
: protected FAC
|
||||
{
|
||||
void
|
||||
operator() (TY* elm)
|
||||
{
|
||||
FAC::dispose (elm);
|
||||
}
|
||||
|
||||
StatefulDeleter (FAC const& anchor)
|
||||
: FAC{anchor}
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
OwnUniqueAdapter (FAC const& factory)
|
||||
: FAC{factory}
|
||||
{ }
|
||||
using FAC::FAC;
|
||||
|
||||
/**
|
||||
* Factory function: generate object with scoped ownership and automated clean-up.
|
||||
*/
|
||||
template<class TY, typename...ARGS>
|
||||
auto
|
||||
make_unique (ARGS&& ...args)
|
||||
{
|
||||
if constexpr (is_Stateless_v<FAC>)
|
||||
{
|
||||
using Handle = std::unique_ptr<TY, void(TY*)>;
|
||||
return Handle{FAC::template create<TY> (std::forward<ARGS> (args)...)
|
||||
, &OwnUniqueAdapter::dispose
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
using Handle = std::unique_ptr<TY, StatefulDeleter<TY>>;
|
||||
return Handle{FAC::template create<TY> (std::forward<ARGS> (args)...)
|
||||
, StatefulDeleter<TY>{*this}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -364,6 +364,14 @@ namespace test{
|
|||
*/
|
||||
EventLog& event (string classifier, string text);
|
||||
|
||||
template<typename...ELMS>
|
||||
EventLog&
|
||||
event (string classifier, ELMS const& ...initialiser)
|
||||
{
|
||||
log ("event", ArgSeq{"ID="+classifier}, collectStr<ArgSeq> (initialiser...));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Log occurrence of a function call with no arguments.
|
||||
* @param target the object or scope on which the function is invoked
|
||||
* @param function name of the function being invoked
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
TrackingAllocator - test dummy objects for tracking ctor/dtor calls
|
||||
TrackingAllocator - custom allocator for memory management diagnostics
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -23,6 +23,18 @@
|
|||
|
||||
/** @file tracking-allocator.cpp
|
||||
** Implementation of the common storage backend for the tracking test allocator.
|
||||
** - PoolRegistry maintains a common hashtable with all MemoryPool instances;
|
||||
** when using the standard accessors, registration and pool creating happens
|
||||
** automatically.
|
||||
** - in this setup, the pool with ID="GLOBAL" is just one further pool, which
|
||||
** will be established when a front-end function is used with the default
|
||||
** pool-ID (i.e. without explicit pool specification). Note however, that
|
||||
** such a factory is still statefull (since it embeds a shared-ownership
|
||||
** smart-pointer)
|
||||
** - each MemoryPool contains a hashtable, where each active allocation is
|
||||
** stored, using the storage-location as hashtable key. Each such entry
|
||||
** gets a further consecutive internal ID, which is visible in the EventLog
|
||||
** - ////////////////////OOO Mutex locking
|
||||
**
|
||||
** @see tracking-allocator.hpp
|
||||
** @see TestTracking_test#demonstrate_checkAllocator()
|
||||
|
|
@ -30,28 +42,24 @@
|
|||
*/
|
||||
|
||||
|
||||
//#include "lib/test/test-helper.hpp"
|
||||
#include "lib/test/tracking-allocator.hpp"
|
||||
//#include "lib/format-string.hpp"
|
||||
//#include "lib/format-cout.hpp"
|
||||
//#include "lib/unique-malloc-owner.hpp"
|
||||
#include "lib/uninitialised-storage.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/depend.hpp"
|
||||
#include "lib/uninitialised-storage.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
//#include <string>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
//using util::_Fmt;
|
||||
using std::string;
|
||||
using std::make_shared;
|
||||
using std::make_pair;
|
||||
//using std::string;
|
||||
using util::contains;
|
||||
using util::joinDash;
|
||||
using util::showAddr;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
|
@ -101,6 +109,8 @@ namespace test{
|
|||
HashVal getChecksum() const;
|
||||
size_t getAllocationCnt() const;
|
||||
size_t calcAllocSize() const;
|
||||
|
||||
Literal getPoolID() const { return poolID_; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -176,19 +186,30 @@ namespace test{
|
|||
{ }
|
||||
|
||||
|
||||
void*
|
||||
TrackingAllocator::allocate (size_t cnt)
|
||||
/**
|
||||
* Allot a memory block with size \a bytes.
|
||||
* This allocation is recorded in the associated MemoryPool
|
||||
* and proper deallocation can thus be verified.
|
||||
* @return a `void*` to the start of the bare memory location
|
||||
*/
|
||||
TrackingAllocator::Location
|
||||
TrackingAllocator::allocate (size_t bytes)
|
||||
{
|
||||
ENSURE (mem_);
|
||||
return mem_->addAlloc (cnt)
|
||||
return mem_->addAlloc (bytes)
|
||||
.buff.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discard and forget an allocation created through this allocator.
|
||||
* The \a bytes argument serves as sanity check (since the actual allocation
|
||||
* size is recorded anyway); a mismatch is logged as error, yet silently ignored.
|
||||
*/
|
||||
void
|
||||
TrackingAllocator::deallocate (Location loc, size_t cnt) noexcept
|
||||
TrackingAllocator::deallocate (Location loc, size_t bytes) noexcept
|
||||
{
|
||||
ENSURE (mem_);
|
||||
mem_->discardAlloc (loc, cnt);
|
||||
mem_->discardAlloc (loc, bytes);
|
||||
}
|
||||
|
||||
MemoryPool::Allocation&
|
||||
|
|
@ -199,7 +220,7 @@ namespace test{
|
|||
Location loc = newAlloc.buff.front();
|
||||
ASSERT (not contains (allocs_, loc));
|
||||
newAlloc.entryID = ++entryNr_;
|
||||
logAlloc (poolID_, "allocate", entryNr_, bytes, showAddr(loc));
|
||||
logAlloc (poolID_, "allocate", bytes, entryNr_, showAddr(loc));
|
||||
checksum_ += entryNr_ * bytes;
|
||||
return allocs_.emplace (loc, move(newAlloc))
|
||||
.first->second;
|
||||
|
|
@ -213,9 +234,10 @@ namespace test{
|
|||
auto& entry = allocs_[loc];
|
||||
ASSERT (entry.buff);
|
||||
ASSERT (entry.buff.front() == loc);
|
||||
if (entry.buff.size() != bytes) // *deliberately* tolerating wrong data
|
||||
logAlarm ("SizeMismatch", entry.entryID, bytes, showAddr(loc)); // but log as incident to support diagnostics
|
||||
logAlloc (poolID_, "deallocate", entry.entryID, bytes, showAddr(loc));
|
||||
if (entry.buff.size() != bytes) // *deliberately* tolerating wrong data, but log incident to support diagnostics
|
||||
logAlarm ("SizeMismatch", bytes, "≠", entry.buff.size(), entry.entryID, showAddr(loc));
|
||||
|
||||
logAlloc (poolID_, "deallocate", bytes, entry.entryID, bytes, showAddr(loc));
|
||||
checksum_ -= entryNr_ * bytes; // Note: using the given size (if wrong ⟿ checksum mismatch)
|
||||
allocs_.erase(loc);
|
||||
}
|
||||
|
|
@ -295,6 +317,7 @@ namespace test{
|
|||
bool
|
||||
TrackingAllocator::manages (Location memLoc) const
|
||||
{
|
||||
ENSURE (mem_);
|
||||
return bool(mem_->findAlloc (memLoc));
|
||||
}
|
||||
|
||||
|
|
@ -302,6 +325,7 @@ namespace test{
|
|||
size_t
|
||||
TrackingAllocator::getSize(Location memLoc) const
|
||||
{
|
||||
ENSURE (mem_);
|
||||
auto* entry = mem_->findAlloc (memLoc);
|
||||
return entry? entry->buff.size()
|
||||
: 0;
|
||||
|
|
@ -311,11 +335,20 @@ namespace test{
|
|||
HashVal
|
||||
TrackingAllocator::getID (Location memLoc) const
|
||||
{
|
||||
ENSURE (mem_);
|
||||
auto* entry = mem_->findAlloc (memLoc);
|
||||
return entry? entry->entryID
|
||||
: 0;
|
||||
}
|
||||
|
||||
Literal
|
||||
TrackingAllocator::poolID() const
|
||||
{
|
||||
ENSURE (mem_);
|
||||
return mem_->getPoolID();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
TRACKING-ALLOCATOR.hpp - test dummy objects for tracking ctor/dtor calls
|
||||
TRACKING-ALLOCATOR.hpp - custom allocator for memory management diagnostics
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2023, Hermann Vosseler <Ichthyostega@web.de>
|
||||
2024, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -25,6 +25,25 @@
|
|||
** unittest helper code: a custom allocator to track memory usage.
|
||||
** By registering each allocation and deallocation, correct memory handling
|
||||
** can be verified and memory usage can be investigated in practice.
|
||||
** \par TrackingAllocator
|
||||
** The foundation is to allow raw memory allocations, which are attached
|
||||
** and tracked within some memory pool, allowing to investigate the number
|
||||
** of allocations, number of currently allotted bytes and a checksum.
|
||||
** Moreover, all relevant actions are logged into an lib::test::EventLog.
|
||||
** By default a common global MemoryPool is used, while it is possible
|
||||
** to carry out all those operations also on a dedicated pool; the user
|
||||
** visible »allocators« are actually shared-ownership smart-handles.
|
||||
** \par TrackingFactory
|
||||
** Built on top is a standard factory to create and destroy arbitrary
|
||||
** object instances, with the corresponding allocations attached to
|
||||
** the underlying MemoryPool
|
||||
** \par C++ standard allocator adapter
|
||||
** A variation of this is the TrackAlloc<TY> template, which can be
|
||||
** used as custom allocator adapter within STL containers
|
||||
** @remark these classes also work in concert with the building blocks
|
||||
** from allocator-handle.hpp; notably it is possible to create
|
||||
** a OwnUniqueAdapter front-end for fabricating `unique_ptr`
|
||||
** @see TestTracking_test
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -32,15 +51,14 @@
|
|||
#define LIB_TEST_TRACKING_ALLOCATOR_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/hash-value.h"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/test/event-log.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
|
||||
//#include <cstddef>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
using std::byte;
|
||||
|
||||
|
|
@ -60,6 +78,12 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Generic low-level allocator attached to tracking MemoryPool.
|
||||
* Effectively this is a shared handle front-end to the MemoryPool, and
|
||||
* new distinct pools are generated (and discarded) on demand, keyed by a pool-ID.
|
||||
* A global (singleton) pool is used when no pool-ID is explicitly given.
|
||||
*/
|
||||
class TrackingAllocator
|
||||
{
|
||||
PoolHandle mem_;
|
||||
|
|
@ -96,6 +120,7 @@ namespace test {
|
|||
bool manages (Location) const;
|
||||
size_t getSize(Location) const;
|
||||
HashVal getID (Location) const;
|
||||
Literal poolID () const;
|
||||
|
||||
static HashVal checksum (Literal pool =GLOBAL);
|
||||
static size_t use_count (Literal pool =GLOBAL);
|
||||
|
|
@ -106,6 +131,14 @@ namespace test {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* C++ standard compliant _custom allocator adapter_
|
||||
* backed by the TrackingAllocator and the MemoryPool denoted at construction.
|
||||
* TrackAlloc adapters can be default constructed (thereby using the GLOBAL pool),
|
||||
* or created with a designated pool-ID or copy/move constructed from any other
|
||||
* TrackAlloc adapter (then using the same backing pool)
|
||||
* @tparam TY the type of intended product object, to determine the size
|
||||
*/
|
||||
template<typename TY>
|
||||
class TrackAlloc
|
||||
: public TrackingAllocator
|
||||
|
|
@ -129,6 +162,61 @@ namespace test {
|
|||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generic object factory backed by TrackingAllocator.
|
||||
*/
|
||||
class TrackingFactory
|
||||
: public TrackingAllocator
|
||||
{
|
||||
public:
|
||||
using TrackingAllocator::TrackingAllocator;
|
||||
|
||||
/** attach to the given TrackingAllocator and MemoryPool */
|
||||
TrackingFactory (TrackingAllocator const& anchor)
|
||||
: TrackingAllocator{anchor}
|
||||
{ }
|
||||
|
||||
/** create new element with an allocation registered in the backing MemoryPool */
|
||||
template<class TY, typename...ARGS>
|
||||
TY*
|
||||
create (ARGS&& ...args)
|
||||
{
|
||||
Location loc = allocate(sizeof(TY));
|
||||
log.call (poolID(),"create-"+util::typeStr<TY>(), std::forward<ARGS> (args)...);
|
||||
try {
|
||||
return new(loc) TY (std::forward<ARGS> (args)...);
|
||||
}
|
||||
catch (std::exception& mishap)
|
||||
{
|
||||
log.error (util::_Fmt{"CtorFail: type=%s, problem:%s"} % util::typeStr<TY>() % mishap.what());
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
log.error ("CtorFail: unknown cause");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/** destroy the given element and discard the associated memory and registration */
|
||||
template<class TY>
|
||||
void
|
||||
dispose (TY* elm) noexcept
|
||||
{
|
||||
if (not elm)
|
||||
{
|
||||
log.warn("dispose(nullptr)");
|
||||
return;
|
||||
}
|
||||
log.call (poolID(),"destroy-"+util::typeStr<TY>());
|
||||
elm->~TY();
|
||||
deallocate(elm, sizeof(TY));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* C++ standard allocator API : allot raw memory for \a cnt elements of type \a TY
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/test/tracking-dummy.hpp"
|
||||
#include "lib/test/tracking-allocator.hpp"
|
||||
#include "lib/allocator-handle.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"///////////////////////TODO
|
||||
|
|
@ -76,19 +77,19 @@ namespace test{
|
|||
Tracker alpha; // (1) create α
|
||||
auto randomAlpha = toString(alpha.val);
|
||||
|
||||
log.note("type=ID",alpha.val); // (2) α has an random ID
|
||||
log.event("ID",alpha.val); // (2) α has an random ID
|
||||
{
|
||||
Tracker beta{55}; // (3) create β
|
||||
alpha = beta; // (4) assign α ≔ β
|
||||
}
|
||||
log.note("type=ID",alpha.val); // (5) thus α now also bears the ID 55 of β
|
||||
log.event ("ID",alpha.val); // (5) thus α now also bears the ID 55 of β
|
||||
Tracker gamma = move(alpha); // (6) create γ by move-defuncting α
|
||||
{
|
||||
Tracker delta(23); // (7) create δ with ID 23
|
||||
delta = move(gamma); // (8) move-assign δ ⟵ γ
|
||||
log.note("type=ID",delta.val); // (9) thus δ now bears the ID 55 (moved α ⟶ γ ⟶ δ)
|
||||
log.event ("ID",delta.val); // (9) thus δ now bears the ID 55 (moved α ⟶ γ ⟶ δ)
|
||||
}
|
||||
log.note("type=ID",alpha.val); // (X) and thus α is now a zombie object
|
||||
log.event("ID",alpha.val); // (X) and thus α is now a zombie object
|
||||
|
||||
cout << "____Tracker-Log_______________\n"
|
||||
<< util::join(Tracker::log, "\n")
|
||||
|
|
@ -159,7 +160,11 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test custom allocator to track memory handling.
|
||||
/** @test custom allocator to track memory handling
|
||||
* - use the base allocator to perform raw memory allocation
|
||||
* - demonstrate checksum and diagnostic functions
|
||||
* - use a standard adapter to create objects with `unique_ptr`
|
||||
* - use as _custom allocator_ within STL containers
|
||||
*/
|
||||
void
|
||||
demonstrate_checkAllocator()
|
||||
|
|
@ -169,9 +174,12 @@ namespace test{
|
|||
Tracker::log.clear("Tracking-Allocator-Test");
|
||||
Tracker::log.joinInto(log);
|
||||
|
||||
// everything is safe and sound initially....
|
||||
CHECK (TrackingAllocator::checksum() == 0, "Testsuite is broken");
|
||||
CHECK (TrackingAllocator::use_count() == 0);
|
||||
{
|
||||
|
||||
{ // Test-1 : raw allocations....
|
||||
log.event("Test-1");
|
||||
TrackingAllocator allo;
|
||||
CHECK (TrackingAllocator::use_count() == 1);
|
||||
CHECK (TrackingAllocator::numAlloc() == 0);
|
||||
|
|
@ -195,35 +203,109 @@ namespace test{
|
|||
CHECK (TrackingAllocator::numAlloc() == 0);
|
||||
CHECK (TrackingAllocator::numBytes() == 0);
|
||||
}
|
||||
|
||||
CHECK (log.verify("EventLogHeader").on("Tracking-Allocator-Test")
|
||||
.before("logJoin")
|
||||
.beforeEvent("Test-1")
|
||||
.beforeCall("allocate").on(GLOBAL).argPos(0, 55)
|
||||
.beforeEvent("error", "SizeMismatch-42-≠-55")
|
||||
.beforeCall("deallocate").on(GLOBAL).argPos(0, 42)
|
||||
);
|
||||
CHECK (TrackingAllocator::checksum() == 0);
|
||||
{
|
||||
|
||||
|
||||
{ // Test-2 : attach scoped-ownership-front-End
|
||||
log.event("Test-2");
|
||||
|
||||
allo::OwnUniqueAdapter<TrackingFactory> uniFab;
|
||||
CHECK (sizeof(uniFab) == sizeof(TrackingFactory));
|
||||
CHECK (sizeof(uniFab) == sizeof(std::shared_ptr<byte>));
|
||||
CHECK (not allo::is_Stateless_v<decltype(uniFab)>);
|
||||
|
||||
CHECK (TrackingAllocator::use_count() == 1);
|
||||
CHECK (TrackingAllocator::numAlloc() == 0);
|
||||
CHECK (TrackingAllocator::numBytes() == 0);
|
||||
{
|
||||
log.event("fabricate unique");
|
||||
auto uniqueHandle = uniFab.make_unique<Tracker> (77);
|
||||
CHECK (uniqueHandle);
|
||||
CHECK (uniqueHandle->val == 77);
|
||||
CHECK (TrackingAllocator::use_count() == 2);
|
||||
CHECK (TrackingAllocator::numAlloc() == 1);
|
||||
CHECK (TrackingAllocator::numBytes() == sizeof(Tracker));
|
||||
|
||||
// all the default tracking allocators indeed attach to the same pool
|
||||
TrackingAllocator allo;
|
||||
void* mem = uniqueHandle.get();
|
||||
CHECK (allo.manages (mem));
|
||||
HashVal memID = allo.getID (mem);
|
||||
CHECK (0 < memID);
|
||||
CHECK (TrackingAllocator::checksum() == memID*sizeof(Tracker));
|
||||
|
||||
}// and it's gone...
|
||||
CHECK (TrackingAllocator::use_count() == 1);
|
||||
CHECK (TrackingAllocator::numAlloc() == 0);
|
||||
CHECK (TrackingAllocator::numBytes() == 0);
|
||||
}
|
||||
|
||||
CHECK (log.verifyEvent("Test-2")
|
||||
.beforeEvent("fabricate unique")
|
||||
.beforeCall("allocate").on(GLOBAL).argPos(0, sizeof(Tracker))
|
||||
.beforeCall("create-Tracker").on(GLOBAL).arg(77)
|
||||
.beforeCall("ctor").on("Tracker").arg(77)
|
||||
.beforeCall("destroy-Tracker").on(GLOBAL)
|
||||
.beforeCall("dtor").on("Tracker").arg(77)
|
||||
.beforeCall("deallocate").on(GLOBAL).argPos(0, sizeof(Tracker))
|
||||
);
|
||||
CHECK (TrackingAllocator::checksum() == 0);
|
||||
|
||||
|
||||
Tracker *t1, *t2, *t3, *t4;
|
||||
|
||||
{ // Test-3 : use as STL allocator
|
||||
log.event("Test-3");
|
||||
using SpyVec = std::vector<Tracker, TrackAlloc<Tracker>>;
|
||||
|
||||
log.event("fill with 3 default instances");
|
||||
SpyVec vec1(3);
|
||||
|
||||
int v3 = vec1.back().val;
|
||||
SHOW_EXPR(v3);
|
||||
SHOW_EXPR(join(vec1))
|
||||
|
||||
SpyVec vec2;
|
||||
log.event("move last instance over into other vector");
|
||||
vec2.emplace_back (move (vec1[2]));
|
||||
SHOW_EXPR(join(vec1))
|
||||
SHOW_EXPR(join(vec2))
|
||||
CHECK (vec2.back().val == v3);
|
||||
CHECK (vec1.back().val == Tracker::DEFUNCT);
|
||||
|
||||
// capture object locations for log verification
|
||||
t1 = & vec1[0];
|
||||
t2 = & vec1[1];
|
||||
t3 = & vec1[2];
|
||||
t4 = & vec2.front();
|
||||
log.event("leave scope");
|
||||
}
|
||||
CHECK (TrackingAllocator::checksum() == 0);
|
||||
CHECK (log.verifyEvent("Test-3")
|
||||
.beforeEvent("fill with 3 default instances")
|
||||
.beforeCall("allocate").on(GLOBAL)
|
||||
.beforeCall("ctor").on(t1)
|
||||
.beforeCall("ctor").on(t2)
|
||||
.beforeCall("ctor").on(t3)
|
||||
.beforeEvent("move last instance over into other vector")
|
||||
.beforeCall("allocate").on(GLOBAL)
|
||||
.beforeCall("ctor-move").on(t4)
|
||||
.beforeEvent("leave scope")
|
||||
.beforeCall("dtor").on(t4)
|
||||
.beforeCall("deallocate").on(GLOBAL)
|
||||
.beforeCall("dtor").on(t1) // (problematic test? order may be implementation dependent)
|
||||
.beforeCall("dtor").on(t2)
|
||||
.beforeCall("dtor").on(t3)
|
||||
.beforeCall("deallocate").on(GLOBAL)
|
||||
);
|
||||
|
||||
cout << "____Tracking-Allo-Log_________\n"
|
||||
<< util::join(Tracker::log, "\n")
|
||||
<< "\n───╼━━━━━━━━━━━━━━━━━╾────────"<<endl;
|
||||
|
||||
CHECK (log.verify("EventLogHeader").on("Tracking-Allocator-Test")
|
||||
.before("logJoin")
|
||||
.beforeCall("allocate").on(GLOBAL).argPos(1, 55)
|
||||
.beforeEvent("error", "SizeMismatch")
|
||||
.beforeCall("deallocate").on(GLOBAL).argPos(1, 42)
|
||||
);
|
||||
CHECK (TrackingAllocator::checksum() == 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -65275,6 +65275,21 @@
|
|||
<linktarget COLOR="#404f66" DESTINATION="ID_157117808" ENDARROW="Default" ENDINCLINATION="1249;67;" ID="Arrow_ID_572544135" SOURCE="ID_1456163487" STARTARROW="None" STARTINCLINATION="131;-1027;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718552461838" ID="ID_319484344" MODIFIED="1718552666111" TEXT="Adapter für scoped-ownership">
|
||||
<linktarget COLOR="#3990cc" DESTINATION="ID_319484344" ENDARROW="Default" ENDINCLINATION="-1632;137;" ID="Arrow_ID_1213960786" SOURCE="ID_1140313787" STARTARROW="None" STARTINCLINATION="-841;-62;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1718552522494" ID="ID_637514128" MODIFIED="1718552611704" TEXT="setzt auf einer generischen Factory auf">
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1718552573095" ID="ID_319925749" MODIFIED="1718552579783" TEXT="erwarte create<TY>"/>
|
||||
<node CREATED="1718552580605" ID="ID_1436913446" MODIFIED="1718552587793" TEXT="erwarte dispose<TY>"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718552529548" ID="ID_112910187" MODIFIED="1718552609395" TEXT="compile-Time-Unterscheidung: ist diese Factory ein Monostate?">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718552590368" ID="ID_559291391" MODIFIED="1718552609397" TEXT="erzeugt und verpackt in korrekt parametrisierten unique_ptr">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -83557,7 +83572,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#435e98" CREATED="1718486592101" ID="ID_121488607" MODIFIED="1718486605209" TEXT="throw from ctor"/>
|
||||
<node COLOR="#435e98" CREATED="1718486596443" ID="ID_1250015263" MODIFIED="1718486605209" TEXT="verify checksum"/>
|
||||
</node>
|
||||
<node CREATED="1718462887129" ID="ID_1322153003" MODIFIED="1718462969529" TEXT="demonstrate_checkAllocator">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1718462887129" ID="ID_1322153003" MODIFIED="1718558813469" TEXT="demonstrate_checkAllocator">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1718544835454" ID="ID_264718265" MODIFIED="1718544844296" TEXT="Basis-Allocator testen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1718544845477" ID="ID_1456085342" MODIFIED="1718544875735" STYLE="fork" TEXT="Roh-Allokation belegen und freigeben"/>
|
||||
|
|
@ -83584,6 +83600,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718552444472" ID="ID_1140313787" MODIFIED="1718558761295" TEXT="unique-ownership-Front-End">
|
||||
<arrowlink COLOR="#3990cc" DESTINATION="ID_319484344" ENDARROW="Default" ENDINCLINATION="-1632;137;" ID="Arrow_ID_1213960786" STARTARROW="None" STARTINCLINATION="-841;-62;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1718492999206" ID="ID_94881308" MODIFIED="1718503992073" TEXT="Vector an den globalen Pool ankoppeln">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
|
|
@ -83596,17 +83616,21 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#338800" CREATED="1718503970700" ID="ID_134542786" MODIFIED="1718503977643" TEXT="ein Dummy-Objekt verschieben">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718493068940" ID="ID_943352942" MODIFIED="1718504000321" TEXT="Statistiken prüfen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1718493068940" ID="ID_943352942" MODIFIED="1718558764756" TEXT="Statistiken prüfen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718503984658" ID="ID_700056398" MODIFIED="1718504040854" TEXT="Checksumme plausibel">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1718503984658" ID="ID_700056398" MODIFIED="1718558766576" TEXT="Checksumme plausibel">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1718504012333" ID="ID_1666449875" MODIFIED="1718504029760" TEXT="Log auswerten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1718504043109" ID="ID_755264460" MODIFIED="1718504064399" TEXT="1.Wurf ⟶ sieht korrekt aus">
|
||||
<node COLOR="#338800" CREATED="1718504012333" ID="ID_1666449875" MODIFIED="1718558768532" TEXT="Log auswerten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1718504043109" ID="ID_755264460" MODIFIED="1718558774779" TEXT="1.Wurf ⟶ sieht korrekt aus">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1718558776143" ID="ID_1507755954" MODIFIED="1718558789645" TEXT="weitere Tests in Abschnitte heruntergebrochen"/>
|
||||
<node COLOR="#435e98" CREATED="1718558790449" ID="ID_1151700316" MODIFIED="1718558806413" TEXT="auch einzelne Instanzen verifiziert">
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue