2024-06-15 18:14:00 +02:00
|
|
|
|
/*
|
|
|
|
|
|
TestTracking(Test) - demonstrate test helpers for tracking automated clean-up
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2024, Hermann Vosseler <Ichthyostega@web.de>
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
|
|
|
|
|
/** @file test-tracking-test.cpp
|
|
|
|
|
|
** unit test \ref TestTracking_test
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
|
#include "lib/test/test-helper.hpp"
|
|
|
|
|
|
#include "lib/test/tracking-dummy.hpp"
|
|
|
|
|
|
#include "lib/test/tracking-allocator.hpp"
|
2024-06-16 19:31:16 +02:00
|
|
|
|
#include "lib/allocator-handle.hpp"
|
2024-06-15 18:14:00 +02:00
|
|
|
|
#include "lib/format-cout.hpp"
|
2024-06-15 23:52:13 +02:00
|
|
|
|
#include "lib/format-util.hpp"
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
using std::string;
|
|
|
|
|
|
using util::toString;
|
2024-06-15 23:52:13 +02:00
|
|
|
|
using util::join;
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************//**
|
|
|
|
|
|
* @test verify proper working of test helpers to track
|
|
|
|
|
|
* automated clean-up and memory deallocation.
|
|
|
|
|
|
* @see TestHelper_test
|
|
|
|
|
|
* @see tracking-dummy.hpp
|
|
|
|
|
|
* @see tracking-allocator.hpp
|
|
|
|
|
|
*/
|
|
|
|
|
|
class TestTracking_test : public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
|
|
|
|
|
demonstrate_logObject();
|
|
|
|
|
|
demonstrate_checkObject();
|
|
|
|
|
|
demonstrate_checkAllocator();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test capture object lifecycle events in the EventLog.
|
|
|
|
|
|
* @see EventLog_test
|
|
|
|
|
|
* @see LateBindInstance_test
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
demonstrate_logObject ()
|
|
|
|
|
|
{
|
|
|
|
|
|
auto& log = Tracker::log;
|
|
|
|
|
|
log.clear (this);
|
|
|
|
|
|
|
|
|
|
|
|
Tracker alpha; // (1) create α
|
|
|
|
|
|
auto randomAlpha = toString(alpha.val);
|
|
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event("ID",alpha.val); // (2) α has an random ID
|
2024-06-15 18:14:00 +02:00
|
|
|
|
{
|
|
|
|
|
|
Tracker beta{55}; // (3) create β
|
|
|
|
|
|
alpha = beta; // (4) assign α ≔ β
|
|
|
|
|
|
}
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event ("ID",alpha.val); // (5) thus α now also bears the ID 55 of β
|
2024-06-15 18:14:00 +02:00
|
|
|
|
Tracker gamma = move(alpha); // (6) create γ by move-defuncting α
|
|
|
|
|
|
{
|
|
|
|
|
|
Tracker delta(23); // (7) create δ with ID 23
|
|
|
|
|
|
delta = move(gamma); // (8) move-assign δ ⟵ γ
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event ("ID",delta.val); // (9) thus δ now bears the ID 55 (moved α ⟶ γ ⟶ δ)
|
2024-06-16 23:55:22 +02:00
|
|
|
|
CHECK (delta.val == 55);
|
2024-06-15 18:14:00 +02:00
|
|
|
|
}
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event("ID",alpha.val); // (X) and thus α is now a zombie object
|
2024-06-16 23:55:22 +02:00
|
|
|
|
CHECK (alpha.val == Tracker::DEFUNCT);
|
|
|
|
|
|
|
2024-06-15 18:14:00 +02:00
|
|
|
|
|
|
|
|
|
|
cout << "____Tracker-Log_______________\n"
|
|
|
|
|
|
<< util::join(Tracker::log, "\n")
|
|
|
|
|
|
<< "\n───╼━━━━━━━━━━━╾──────────────"<<endl;
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (log.verify("EventLogHeader").on("TestTracking_test")
|
|
|
|
|
|
.beforeCall("ctor").on(&alpha) // (1) create α
|
|
|
|
|
|
.beforeEvent("ID", randomAlpha) // (2) α has an random ID
|
|
|
|
|
|
.beforeCall("ctor").arg(55) // (3) create β
|
|
|
|
|
|
.beforeCall("assign-copy").on(&alpha).arg("Track{55}") // (4) assign α ≔ β
|
|
|
|
|
|
.beforeCall("dtor").arg(55)
|
|
|
|
|
|
.beforeEvent("ID", "55") // (5) thus α now also bears the ID 55 of β
|
|
|
|
|
|
.beforeCall("ctor-move").on(&gamma).arg("Track{55}") // (6) create γ by move-defuncting α
|
|
|
|
|
|
.beforeCall("ctor").arg(23) // (7) create δ with ID 23
|
|
|
|
|
|
.beforeCall("assign-move").arg("Track{55}") // (8) move-assign δ ⟵ γ
|
|
|
|
|
|
.beforeEvent("ID", "55") // (9) thus δ now bears the ID 55 (moved α ⟶ γ ⟶ δ)
|
|
|
|
|
|
.beforeCall("dtor").arg(55)
|
|
|
|
|
|
.beforeEvent("ID", toString(Tracker::DEFUNCT)) // (X) and thus α is now a zombie object
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-06-16 23:55:22 +02:00
|
|
|
|
|
2024-06-15 18:14:00 +02:00
|
|
|
|
/** @test dummy object with a tracking checksum.
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
demonstrate_checkObject ()
|
|
|
|
|
|
{
|
2024-06-15 23:52:13 +02:00
|
|
|
|
CHECK (Dummy::checksum() == 0);
|
|
|
|
|
|
{
|
|
|
|
|
|
Dummy dum1; // picks a random positive int by default...
|
|
|
|
|
|
CHECK (0 < dum1.getVal() and dum1.getVal() <= 100'000'000);
|
|
|
|
|
|
CHECK (Dummy::checksum() == dum1.getVal());
|
|
|
|
|
|
|
|
|
|
|
|
Dummy dum2{55};
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (dum2.getVal() == 55);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
CHECK (Dummy::checksum() == dum1.getVal() + 55);
|
|
|
|
|
|
|
|
|
|
|
|
Dummy dum3{move (dum2)};
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (dum3.getVal() == 55);
|
|
|
|
|
|
CHECK (dum2.getVal() == Dummy::DEFUNCT);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
|
|
|
|
|
dum3.setVal (23);
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (dum3.getVal() == 23);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
|
|
|
|
|
dum1 = move (dum3);
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (dum1.getVal() == 23 );
|
|
|
|
|
|
CHECK (dum2.getVal() == Dummy::DEFUNCT);
|
|
|
|
|
|
CHECK (dum3.getVal() == Dummy::DEFUNCT);
|
|
|
|
|
|
CHECK (Dummy::checksum() == 23 );
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
|
|
|
|
|
Dummy::activateCtorFailure (true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
Dummy kabooom;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (int v)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (0 < v and v <= 100'000'000);
|
|
|
|
|
|
CHECK (Dummy::checksum() == 23 + v);
|
|
|
|
|
|
Dummy::checksum() -= v;
|
|
|
|
|
|
}
|
|
|
|
|
|
Dummy::activateCtorFailure (false);
|
2025-02-16 21:10:06 +01:00
|
|
|
|
CHECK (dum1.getVal() == 23 );
|
|
|
|
|
|
CHECK (dum2.getVal() == Dummy::DEFUNCT);
|
|
|
|
|
|
CHECK (dum3.getVal() == Dummy::DEFUNCT);
|
|
|
|
|
|
CHECK (Dummy::checksum() == 23 );
|
2024-06-15 23:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
CHECK (Dummy::checksum() == 0);
|
2024-06-15 18:14:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-06-16 23:55:22 +02:00
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
/** @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
|
2024-06-16 23:55:22 +02:00
|
|
|
|
* - can use several distinct pools
|
|
|
|
|
|
* - swapping containers will move allocators alongside
|
2024-06-15 18:14:00 +02:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
2024-06-15 23:52:13 +02:00
|
|
|
|
demonstrate_checkAllocator()
|
2024-06-15 18:14:00 +02:00
|
|
|
|
{
|
2024-06-17 16:58:07 +02:00
|
|
|
|
// setup a common event-log for the tracking objects and -allocator
|
2024-06-15 23:52:13 +02:00
|
|
|
|
auto& log = TrackingAllocator::log;
|
|
|
|
|
|
Tracker::log.clear("Tracking-Allocator-Test");
|
|
|
|
|
|
Tracker::log.joinInto(log);
|
|
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
// everything is safe and sound initially....
|
2024-06-16 14:26:21 +02:00
|
|
|
|
CHECK (TrackingAllocator::checksum() == 0, "Testsuite is broken");
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count() == 0);
|
2024-06-16 19:31:16 +02:00
|
|
|
|
|
|
|
|
|
|
{ // Test-1 : raw allocations....
|
|
|
|
|
|
log.event("Test-1");
|
2024-06-16 14:26:21 +02:00
|
|
|
|
TrackingAllocator allo;
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count() == 1);
|
|
|
|
|
|
CHECK (TrackingAllocator::numAlloc() == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes() == 0);
|
|
|
|
|
|
|
|
|
|
|
|
void* mem = allo.allocate (55);
|
|
|
|
|
|
CHECK (TrackingAllocator::numAlloc() == 1);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes() == 55);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (allo.manages (mem));
|
2024-06-16 23:55:22 +02:00
|
|
|
|
CHECK (allo.getSize (mem) == 55); // individual registration recalls the allocation's size
|
2024-06-16 14:26:21 +02:00
|
|
|
|
HashVal memID = allo.getID (mem);
|
|
|
|
|
|
CHECK (0 < memID);
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum() == memID*55);
|
|
|
|
|
|
|
|
|
|
|
|
allo.deallocate (mem, 42); // note: passing a wrong number here is marked as ERROR in the log
|
|
|
|
|
|
CHECK (not allo.manages (mem));
|
|
|
|
|
|
CHECK (allo.getSize (mem) == 0);
|
|
|
|
|
|
CHECK (allo.getID (mem) == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count() == 1);
|
|
|
|
|
|
CHECK (TrackingAllocator::numAlloc() == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes() == 0);
|
|
|
|
|
|
}
|
2024-06-16 19:31:16 +02:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
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))
|
|
|
|
|
|
);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
CHECK (TrackingAllocator::checksum() == 0);
|
2024-06-16 19:31:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
2024-06-16 23:55:22 +02:00
|
|
|
|
// define a vector type to use the TrackingAllocator internally
|
|
|
|
|
|
using TrackVec = std::vector<Tracker, TrackAlloc<Tracker>>;
|
|
|
|
|
|
|
|
|
|
|
|
// the following pointers are used later to identify log entries...
|
|
|
|
|
|
Tracker *t1, *t2, *t3, *t4, *t5, *t6;
|
|
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
|
|
|
|
|
|
{ // Test-3 : use as STL allocator
|
|
|
|
|
|
log.event("Test-3");
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event("fill with 3 default instances");
|
2024-06-16 23:55:22 +02:00
|
|
|
|
TrackVec vec1(3);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
|
|
|
|
|
int v3 = vec1.back().val;
|
|
|
|
|
|
|
2024-06-16 23:55:22 +02:00
|
|
|
|
TrackVec vec2;
|
2024-06-16 19:31:16 +02:00
|
|
|
|
log.event("move last instance over into other vector");
|
2024-06-15 23:52:13 +02:00
|
|
|
|
vec2.emplace_back (move (vec1[2]));
|
2024-06-16 19:31:16 +02:00
|
|
|
|
CHECK (vec2.back().val == v3);
|
|
|
|
|
|
CHECK (vec1.back().val == Tracker::DEFUNCT);
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
2024-06-16 19:31:16 +02:00
|
|
|
|
// capture object locations for log verification
|
|
|
|
|
|
t1 = & vec1[0];
|
|
|
|
|
|
t2 = & vec1[1];
|
|
|
|
|
|
t3 = & vec1[2];
|
|
|
|
|
|
t4 = & vec2.front();
|
|
|
|
|
|
log.event("leave scope");
|
2024-06-15 23:52:13 +02:00
|
|
|
|
}
|
2024-06-16 19:31:16 +02:00
|
|
|
|
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)
|
|
|
|
|
|
);
|
2024-06-16 23:55:22 +02:00
|
|
|
|
CHECK (TrackingAllocator::checksum() == 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ // Test-4 : intermingled use of several pools
|
|
|
|
|
|
log.event("Test-4");
|
|
|
|
|
|
|
|
|
|
|
|
TrackAlloc<Tracker> allo1{"POOL-1"};
|
|
|
|
|
|
TrackAlloc<Tracker> allo2{"POOL-2"};
|
|
|
|
|
|
CHECK (allo1 != allo2);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count(GLOBAL) == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-1") == 1); // referred by allo1
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-2") == 1); // referred by allo2
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum ("POOL-1") == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum ("POOL-2") == 0);
|
|
|
|
|
|
|
|
|
|
|
|
TrackVec vec1{allo1};
|
|
|
|
|
|
TrackVec vec2{allo2};
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-1") == 2); // now also referred by the copy in the vectors
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-2") == 2);
|
|
|
|
|
|
|
|
|
|
|
|
log.event("reserve space in vectors");
|
|
|
|
|
|
vec1.reserve(20);
|
|
|
|
|
|
vec2.reserve(2);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-1") == 20*sizeof(Tracker));
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-2") == 2*sizeof(Tracker));
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes(GLOBAL) == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes() == 0);
|
|
|
|
|
|
|
|
|
|
|
|
log.event("create elements in vec1");
|
|
|
|
|
|
vec1.resize(5);
|
|
|
|
|
|
vec1.back().val = 11;
|
|
|
|
|
|
log.event("add element to vec2");
|
|
|
|
|
|
vec2.push_back (Tracker{22});
|
|
|
|
|
|
|
|
|
|
|
|
// capture object locations for log verification later
|
|
|
|
|
|
t1 = & vec1[0];
|
|
|
|
|
|
t2 = & vec1[1];
|
|
|
|
|
|
t3 = & vec1[2];
|
|
|
|
|
|
t4 = & vec1[3];
|
|
|
|
|
|
t5 = & vec1[4];
|
|
|
|
|
|
t6 = & vec2.front();
|
|
|
|
|
|
|
|
|
|
|
|
log.event ("swap vectors");
|
|
|
|
|
|
std::swap (vec1, vec2);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (vec1.back().val == 22);
|
|
|
|
|
|
CHECK (vec2.back().val == 11);
|
|
|
|
|
|
CHECK (vec1.size() == 1);
|
|
|
|
|
|
CHECK (vec2.size() == 5);
|
|
|
|
|
|
// the allocators were migrated alongside with the swap
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-1") == 20*sizeof(Tracker));
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-2") == 2*sizeof(Tracker));
|
|
|
|
|
|
// this can be demonstrated....
|
|
|
|
|
|
log.event ("clear the elements migrated to vec2");
|
|
|
|
|
|
vec2.clear();
|
|
|
|
|
|
vec2.shrink_to_fit();
|
|
|
|
|
|
CHECK (vec2.capacity() == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-1") == 0 );
|
|
|
|
|
|
CHECK (TrackingAllocator::numBytes("POOL-2") == 2*sizeof(Tracker));
|
|
|
|
|
|
CHECK (vec1.size() == 1);
|
|
|
|
|
|
CHECK (vec1.capacity() == 2); // unaffected
|
|
|
|
|
|
|
|
|
|
|
|
log.event ("leave scope");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (log.verifyEvent("Test-4")
|
|
|
|
|
|
.beforeEvent("reserve space in vectors")
|
|
|
|
|
|
.beforeCall("allocate").on("POOL-1").argPos(0, 20*sizeof(Tracker))
|
|
|
|
|
|
.beforeCall("allocate").on("POOL-2").argPos(0, 2*sizeof(Tracker))
|
|
|
|
|
|
|
|
|
|
|
|
.beforeEvent("create elements in vec1")
|
|
|
|
|
|
.beforeCall("ctor").on(t1)
|
|
|
|
|
|
.beforeCall("ctor").on(t2)
|
|
|
|
|
|
.beforeCall("ctor").on(t3)
|
|
|
|
|
|
.beforeCall("ctor").on(t4)
|
|
|
|
|
|
.beforeCall("ctor").on(t5)
|
|
|
|
|
|
|
|
|
|
|
|
.beforeEvent("add element to vec2")
|
|
|
|
|
|
.beforeCall("ctor").arg(22)
|
|
|
|
|
|
.beforeCall("ctor-move").on(t6).arg("Track{22}")
|
|
|
|
|
|
.beforeCall("dtor").arg(Tracker::DEFUNCT)
|
|
|
|
|
|
|
|
|
|
|
|
.beforeEvent("swap vectors")
|
|
|
|
|
|
.beforeEvent("clear the elements migrated to vec2")
|
|
|
|
|
|
.beforeCall("dtor").on(t1)
|
|
|
|
|
|
.beforeCall("dtor").on(t2)
|
|
|
|
|
|
.beforeCall("dtor").on(t3)
|
|
|
|
|
|
.beforeCall("dtor").on(t4)
|
|
|
|
|
|
.beforeCall("dtor").on(t5).arg(11)
|
|
|
|
|
|
.beforeCall("deallocate").on("POOL-1").argPos(0, 20*sizeof(Tracker))
|
|
|
|
|
|
|
|
|
|
|
|
.beforeEvent("leave scope")
|
|
|
|
|
|
.beforeCall("dtor").on(t6).arg(22)
|
|
|
|
|
|
.beforeCall("deallocate").on("POOL-2").argPos(0, 2*sizeof(Tracker))
|
|
|
|
|
|
);
|
|
|
|
|
|
// everything clean and all pools empty again...
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count(GLOBAL) == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-1") == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::use_count("POOL-2") == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum("POOL-1") == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum("POOL-2") == 0);
|
|
|
|
|
|
CHECK (TrackingAllocator::checksum(GLOBAL) == 0);
|
|
|
|
|
|
|
2024-06-15 23:52:13 +02:00
|
|
|
|
|
|
|
|
|
|
cout << "____Tracking-Allo-Log_________\n"
|
2024-06-18 17:20:23 +02:00
|
|
|
|
<< util::join(TrackingAllocator::log,"\n")
|
2024-06-15 23:52:13 +02:00
|
|
|
|
<< "\n───╼━━━━━━━━━━━━━━━━━╾────────"<<endl;
|
2024-06-15 18:14:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
LAUNCHER (TestTracking_test, "unit common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}}} // namespace lib::test::test
|
|
|
|
|
|
|