Now able to reap the rewards: since all that convoluted and tangled old ''state tracking'' has been resolved and replaced by dedicated and self-contained diagnostic subclasses, the old dummy BufferProvider implementation can be detached, using a similar yet very simple fake implementation. For context: the `HeapMemBufferStore` is part of the default configuration and thus automatically used whenever a unit test needs a `BufferProvider`. This default implementation is not optimised for speed, and actually never releases any memory, which allows to verify proper handling of buffer memory allocation.
160 lines
4.7 KiB
C++
160 lines
4.7 KiB
C++
/*
|
||
DIAGNOSTIC-BUFFER-PROVIDER.hpp - helper for testing against the BufferProvider interface
|
||
|
||
Copyright (C)
|
||
2011,2026 Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**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.
|
||
|
||
*/
|
||
|
||
/** @file diagnostic-buffer-provider.hpp
|
||
** A facility for writing unit-tests targeting the BufferProvider interface.
|
||
**
|
||
** @see buffer-provider-protocol-test.cpp
|
||
*/
|
||
|
||
#ifndef VAULT_MEM_DIAGNOSTIC_BUFFR_PROVIDER_H
|
||
#define VAULT_MEM_DIAGNOSTIC_BUFFR_PROVIDER_H
|
||
|
||
|
||
#include "lib/error.hpp"
|
||
#include "lib/util.hpp"
|
||
#include "vault/mem/type-handler.hpp" ///////////////OOO warum?
|
||
#include "vault/mem/naive-buffer-setup.hpp"
|
||
#include "lib/iter-adapter-stl.hpp"
|
||
#include "lib/result.hpp"
|
||
#include "lib/nocopy.hpp"
|
||
|
||
#include <memory>
|
||
#include <vector>
|
||
|
||
|
||
namespace vault {
|
||
namespace mem {
|
||
namespace err = lumiera::error;
|
||
|
||
class HeapMemBufferStore; //////////////////////////////OOO fällt dann weg nach dem Umbau
|
||
class BufferDiagnostic;
|
||
|
||
namespace diagn {// state descriptors for diagnostics....
|
||
|
||
/** represent the status of one allocation */
|
||
struct Block
|
||
{
|
||
HashVal typeKey{0};
|
||
HashVal stateKey{0};
|
||
size_t buffSize{0};
|
||
Buff* storage{nullptr};
|
||
Buff* accessMemory() const { return storage; }
|
||
|
||
Block (metadata::Key, Buff* mem);
|
||
operator HashVal() const { return storage? stateKey:typeKey; }
|
||
|
||
template<typename BU>
|
||
BU const& accessAs() const;
|
||
};
|
||
|
||
|
||
class StateReg
|
||
: util::NonCopyable
|
||
{
|
||
using Registry = std::vector<Block>;
|
||
Registry reg_;
|
||
|
||
public:
|
||
/* ========= Information API ========= */
|
||
using Result = lib::Result<Block const&>;
|
||
Result operator[] (size_t seqNr) const;
|
||
Result byHandle (HashVal handle) const;
|
||
bool contains (HashVal handle) const;
|
||
auto each() const;
|
||
size_t cnt() const;
|
||
|
||
/* ========= Accounting API ========= */
|
||
void record (Block);
|
||
};
|
||
|
||
|
||
inline auto
|
||
StateReg::each() const
|
||
{
|
||
return lib::iter_stl::eachElm (reg_);
|
||
}
|
||
|
||
template<typename BU>
|
||
inline BU const&
|
||
Block::accessAs() const
|
||
{
|
||
if (not storage)
|
||
throw err::Logic ("buffer was never actually locked for access by clients"
|
||
, LERR_(LIFECYCLE));
|
||
return *reinterpret_cast<BU const*> (storage);
|
||
}
|
||
|
||
}//(End)diagnostic descriptors.
|
||
|
||
|
||
|
||
/********************************************************************//**
|
||
* Helper for unit tests: Buffer provider that tracks state transitions.
|
||
* This is a variant of the _naive_ heap based BufferProvider implementation,
|
||
* with additional tracking hooks to record the IDs and further information
|
||
* of all allocations encountered at a state transition.
|
||
*
|
||
* Test code should keep track of the BufferProvider instance used, and may
|
||
* attach through a special [diagnostics access](\ref watch(BufferProvider&)),
|
||
* to extract the recorded information while or after the allocated buffers
|
||
* are used. Since the underlying "naive" implementation does not actually
|
||
* discard any allocated memory block, it is possible to look into memory
|
||
* contents after invoking the test subject.
|
||
*/
|
||
class DiagnosticBufferProvider
|
||
: public NaiveBufferSetup
|
||
{
|
||
class InstrumentedStageProxy;
|
||
struct BlockTracker;
|
||
std::unique_ptr<BlockTracker> tracker_;
|
||
|
||
public:
|
||
~DiagnosticBufferProvider();
|
||
DiagnosticBufferProvider();
|
||
|
||
private:
|
||
/// „backdoor“ to watch instrumentation from tests
|
||
friend class BufferDiagnostic;
|
||
};
|
||
|
||
|
||
/** Accessor-proxy to investigate transactions */
|
||
class BufferDiagnostic
|
||
: util::MoveOnly
|
||
{
|
||
DiagnosticBufferProvider& dbp_;
|
||
public:
|
||
BufferDiagnostic (DiagnosticBufferProvider&);
|
||
|
||
bool was_created (HashVal);
|
||
bool was_emitted (HashVal);
|
||
bool was_released (HashVal);
|
||
bool is_in_use (HashVal);
|
||
bool was_used (HashVal);
|
||
Buff* accessMemory(HashVal);
|
||
bool all_buffers_released();
|
||
diagn::StateReg const& created;
|
||
diagn::StateReg const& emitted;
|
||
diagn::StateReg const& released;
|
||
};
|
||
|
||
inline BufferDiagnostic
|
||
watch (BufferProvider& thePro)
|
||
{
|
||
return BufferDiagnostic{static_cast<DiagnosticBufferProvider&> (thePro)};
|
||
}
|
||
|
||
|
||
}} // namespace vault::mem
|
||
#endif
|