Invocation: change TestFrame to use a dedicated header

Change data layout to place a metadata record ''behind the'' payload data,
and add a checksum to allow for validating dummy calculations and also
detect data corruption on data modified after initial generation.

By virtue of a marker data word, the presence of a valid metadata record can be confirmed.
This commit is contained in:
Fischlurch 2024-11-18 23:55:30 +01:00
parent 4ca9eb8d46
commit 204e2f55d0
4 changed files with 200 additions and 93 deletions

View file

@ -33,7 +33,7 @@
#include <stdlib.h>
/**
/**
* storage for a Lumiera unique ID,
* based on a 128bit random number
*/

View file

@ -18,12 +18,13 @@
#include "lib/error.hpp"
#include "lib/random.hpp"
#include "lib/hash-standard.hpp"
#include "lib/hash-combine.hpp"
#include "steam/engine/testframe.hpp"
#include "lib/nocopy.hpp"
#include "lib/util.hpp"
#include <climits>
#include <cstring>
#include <memory>
#include <vector>
@ -33,10 +34,8 @@ namespace steam {
namespace engine {
namespace test {
using lib::HashVal;
using util::unConst;
using std::vector;
using std::memcpy;
using lib::rani;
/** @note using a random-congruential engine to generate the payload data */
using PseudoRandom = lib::RandomSequencer<std::minstd_rand>;
@ -69,14 +68,16 @@ namespace test {
HashVal dataSeed{drawSeed(lib::entropyGen)};
/** @internal helper for generating unique test frames.
* This "discriminator" is used as a random seed when filling the test frame data buffers.
* This »discriminator« is used as a random seed when filling the test frame data buffers.
* It is generated to be very likely different on adjacent frames of the same series,
* as well as to differ to all nearby neighbouring channels.
* @note the #dataSeed hash is limited by #SEQUENCE_SPREAD to prevent risky families;
* the extreme case would be dataSeed+family 0 (all frames would be equal then)
* @param seq the sequence number of the frame within the channel
* @param family the channel this frame belongs to
*/
uint64_t
generateDistinction(uint seq, uint family)
generateDiscriminator(uint seq, uint family)
{
// use the family as stepping
return (seq+1) * (dataSeed+family);
@ -99,6 +100,15 @@ namespace test {
}
};
/** @return a stable characteristic memory marker for the metadata record */
HashVal
stampHeader()
{
static const HashVal MARK = lib::entropyGen.hash()
| 0b1000'1000'1000'1000'1000'1000'1000'1000;
return MARK;
}
/** @internal build a PRNG starting from the referred fixed seed */
auto
buildDataGenFrom (uint64_t const& anchor)
@ -225,43 +235,68 @@ namespace test {
/* ===== TestFrame class ===== */
TestFrame::Meta::Meta (uint seq, uint family)
: _MARK_{stampHeader()}
, checksum{0}
, distinction{generateDiscriminator (seq,family)}
, stage{CREATED}
{ }
TestFrame::~TestFrame()
{
stage_ = DISCARDED;
header_.stage = DISCARDED;
}
TestFrame::TestFrame(uint seq, uint family)
: distinction_(generateDistinction (seq,family))
, stage_(CREATED)
TestFrame::TestFrame (uint seq, uint family)
: header_{seq,family}
{
ASSERT (0 < distinction_);
buildData();
ASSERT (0 < header_.distinction);
header_.checksum = buildData();
ENSURE (CREATED == header_.stage);
ENSURE (isPristine());
}
TestFrame::TestFrame (TestFrame const& o)
: distinction_(o.distinction_)
, stage_(CREATED)
: header_{o.header_}
{
memcpy (buffer_, o.buffer_, BUFFSIZ);
data() = o.data();
header_.stage = CREATED;
}
TestFrame&
TestFrame::operator= (TestFrame const& o)
{
if (DISCARDED == stage_)
throw new error::Logic ("target TestFrame is already dead");
if (not isAlive())
throw new error::Logic ("target TestFrame already dead or unaccessible");
if (not util::isSameAdr (this, o))
{
distinction_ = o.distinction_;
stage_ = CREATED;
memcpy (buffer_, o.buffer_, BUFFSIZ);
data() = o.data();
header_ = o.header_;
header_.stage = CREATED;
}
return *this;
}
TestFrame::Meta&
TestFrame::accessHeader()
{
return header_;
}
TestFrame::Meta const&
TestFrame::accessHeader() const
{
///////////////////////OOO detect if valid header present and else throw
return unConst(this)->accessHeader();
}
TestFrame::StageOfLife
TestFrame::currStage() const
{
///////////////////////OOO detect if valid header present and then access
}
/** @note performing an unchecked conversion of the given
* memory location to be accessed as TestFrame.
@ -301,47 +336,74 @@ namespace test {
return true;
}
HashVal
TestFrame::buildData()
{
auto gen = buildDataGenFrom (accessHeader().distinction);
for (uint i=0; i<BUFFSIZ; ++i)
data()[i] = char(gen.i(CHAR_MAX));
}
bool
TestFrame::verifyData() const
{
auto gen = buildDataGenFrom (distinction_);
auto gen = buildDataGenFrom (accessHeader().distinction);
for (uint i=0; i<BUFFSIZ; ++i)
if (data()[i] != char(gen.i(CHAR_MAX)))
return false;
return true;
}
void
TestFrame::buildData()
HashVal
TestFrame::computeChecksum() const
{
auto gen = buildDataGenFrom (distinction_);
for (uint i=0; i<BUFFSIZ; ++i)
data()[i] = char(gen.i(CHAR_MAX));
HashVal hash{0};
////////////////////////////////////////////OOO actually compute it
}
bool
TestFrame::hasValidChecksum() const
{
////////////////////////////////////////////OOO actually compute checksum and verify
}
bool
TestFrame::isAlive() const
{
return (CREATED == stage_)
|| (EMITTED == stage_);
return (CREATED == currStage())
|| (EMITTED == currStage());
}
bool
TestFrame::isDead() const
{
return (DISCARDED == stage_);
return (DISCARDED == currStage());
}
bool
TestFrame::isSane() const
{
return ( (CREATED == stage_)
||(EMITTED == stage_)
||(DISCARDED == stage_))
return ( (CREATED == currStage())
||(EMITTED == currStage())
||(DISCARDED == currStage()))
&& verifyData();
}
bool
TestFrame::isValid() const
{
return isSane()
and hasValidChecksum();
}
bool
TestFrame::isPristine() const
{
return isSane()
and hasValidChecksum();
}
}}} // namespace steam::engine::test

View file

@ -30,6 +30,7 @@ namespace steam {
namespace engine {
namespace test {
using lib::HashVal;
/**
* Mock data frame for simulated rendering.
@ -58,14 +59,24 @@ namespace test {
static constexpr size_t BUFFSIZ = 1024;
using _Arr = std::array<char,BUFFSIZ>;
uint64_t distinction_;
StageOfLife stage_;
struct Meta
{
HashVal _MARK_;
HashVal checksum;
uint64_t distinction;
StageOfLife stage;
Meta (uint seq, uint family);
};
/** inline storage buffer for the payload media data */
alignas(uint64_t)
std::byte buffer_[sizeof(_Arr)];
/** Metadata record located behind the data buffer */
Meta header_;
public:
/** discard all cached #testData and recalibrate data generation */
static void reseed();
@ -86,9 +97,11 @@ namespace test {
* an already destroyed TestFrame instance */
static bool isDead (void* memLocation);
bool isAlive() const;
bool isDead() const;
bool isSane() const;
bool isAlive() const;
bool isDead() const;
bool isSane() const;
bool isValid() const;
bool isPristine() const;
bool operator== (void* memLocation) const;
@ -102,7 +115,12 @@ namespace test {
private:
bool contentEquals (TestFrame const& o) const;
bool verifyData() const;
void buildData ();
HashVal buildData();
Meta& accessHeader();
Meta const& accessHeader() const;
StageOfLife currStage() const;
HashVal computeChecksum() const;
bool hasValidChecksum() const;
};

View file

@ -17766,9 +17766,7 @@
</html></richcontent>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1664546786666" ID="ID_418065847" MODIFIED="1664546893122" TEXT="links-Klick">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Ja, wir wollen das alte Blender-Modell: Selektion mit rechts, Aktion mit links
@ -18605,9 +18603,7 @@
<icon BUILTIN="button_ok"/>
<node CREATED="1664031831907" ID="ID_701574899" MODIFIED="1664031980972" TEXT="Problem: reaktiv getriggert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Bedingt durch das Aufrufschema k&#246;nnen wir nicht zu Beginn steuernd eingreifen, sondern wir k&#246;nnen nur erkennen, wenn das Sub-Widget (aus welchen Gr&#252;nden auch immer) den extension-constraint verletzt. Und wir bekommen keine direkten Wirkfaktoren in die Hand (weil sich die Ausdehnung aus einem komplexen Zusammenspiel von Font, Pixelgr&#246;&#223;e und Styles ergibt)
@ -18907,9 +18903,7 @@
</node>
<node COLOR="#33565a" CREATED="1664725271351" HGAP="38" ID="ID_1918462068" MODIFIED="1664727540441" TEXT="erf&#xfc;llt(cW)?" VSHIFT="-10">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
BEDINUNG: cW&#160;&gt; aktuelleWeite
@ -19247,9 +19241,7 @@
</node>
<node CREATED="1664836501374" ID="ID_915287836" MODIFIED="1672764716013" TEXT="Kein Problem: Layout-Handling-Code l&#xe4;uft vor dem n&#xe4;chsten DRAW">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -20064,9 +20056,7 @@
</node>
<node COLOR="#435e98" CREATED="1665972100310" ID="ID_1747925228" MODIFIED="1666285341589" TEXT="seltsam? in den bisherigen Experimenten war das nie ein Problem">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...denn ich ging von der Annahme aus, da&#223; dieser Code erst im nachfolgenden draw()-Event aufgerufen wird; und diese Annahme hatte sich bisher stets best&#228;tigt, obwohl im ctor von ElementBox direkt ein show_all() aufgerufen wird
@ -21315,9 +21305,7 @@
</node>
<node CREATED="1575221690053" ID="ID_391530319" MODIFIED="1575221756022" TEXT="genau diese Info aber brauche ich">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
denn der Display/Manager bzw Canvas ist zwar &quot;quasi global&quot;, aber eben nicht wirklich, denn er ist f&#252;r eine Timeline zust&#228;ndig. Also genau die Art Relation, f&#252;r die man typischerweise DI macht
@ -24059,9 +24047,7 @@
</node>
<node CREATED="1565273005475" ID="ID_1081606131" MODIFIED="1576282358075" TEXT="aber sinnvoll zum Triggern">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Es ist sinnvoll, die Feststellung einer &#196;nderung vom Berechnen der neuen Werte zu trennen.
@ -39574,9 +39560,7 @@
</node>
<node COLOR="#338800" CREATED="1621011086402" ID="ID_1715852739" MODIFIED="1621013328247" TEXT="dann m&#xfc;ssen diese aber auch auf das ClipWidget-Interface">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
letztlich kein Problem.
@ -41915,9 +41899,7 @@
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Wir nutzen explizit aus, da&#223; das Ergebnis durch truncating quantisiert wird (Integer-Division). Daher k&#246;nnen wir erst den ersten Dividenden (die Zeitspanne) aufteilen, und zwar erst mal in den Sekunden-Anteil, dann den Rest, und dann den Rest vom Rest
@ -43225,9 +43207,7 @@
<node CREATED="1670718042479" ID="ID_1099895360" MODIFIED="1670718073999" TEXT="&#x27f9; dd/dn &lt; 1e-9 wird gef&#xe4;rlich">
<node CREATED="1670718077402" ID="ID_1523825947" MODIFIED="1670718152194" TEXT="der Vorfaktor ist minimal 1.1 (bzw 2 f&#xfc;r ganze Pixel)">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
minimale Pixel-Zahl 1px. Mit 1/10 Band dann 1.1, mit 1px-Band 2
@ -44003,9 +43983,7 @@
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1668474155145" ID="ID_132764069" MODIFIED="1668474234849" TEXT="ein Beispiel mit Nenner nahe INT_MAX">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Rat poison = (MAXI-88)/(MAXI/7);
@ -45687,9 +45665,7 @@
</node>
<node CREATED="1541552832731" ID="ID_346770424" MODIFIED="1576282358021" TEXT="bricht die Subsidiarit&#xe4;t">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...denn dann m&#252;&#223;te das Attribut
@ -46019,9 +45995,7 @@
</node>
<node CREATED="1523019770144" ID="ID_435980488" MODIFIED="1557498707234">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
(GlobalCtx)-&gt;WindowLocator-&gt;<b>UIComponentAccessor</b>
@ -46219,9 +46193,7 @@
</node>
<node CREATED="1448078473068" ID="ID_510866826" MODIFIED="1576282358017" TEXT="zerst&#xf6;ren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
hei&#223;t: Element deregistriert sich am UI-Bus
@ -46334,9 +46306,7 @@
<icon BUILTIN="pencil"/>
<node CREATED="1448078811895" ID="ID_1266803050" MODIFIED="1518487921085">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
Nachricht an <i>irgend ein</i>&#160;Wurzel-Element
@ -56799,6 +56769,40 @@
</node>
<node COLOR="#338800" CREATED="1731900530433" ID="ID_1117088425" MODIFIED="1731900545903" TEXT="den Basis-Seed mit einem minimal-Spread aufbauen">
<icon BUILTIN="button_ok"/>
<node CREATED="1731943389399" ID="ID_39230986" MODIFIED="1731943552546">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Diskriminator-ID &#8788; (<font color="#592cc8">seq</font>+1) * (<font color="#6c433b">dataSeed</font>+<font color="#6f0ed0">family</font>)
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1731943561624" ID="ID_1209671030" MODIFIED="1731943647377">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Erl&#228;uterung: jede &#187;family&#171; hat ein eigenes<i>&#160;Stepping</i>
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1731943679360" ID="ID_1740781453" MODIFIED="1731943717151" TEXT="es kann trotzdem zu Kollisionen kommen &#x2014; das ist aber f&#xfc;r kleine seq-Nr unwahrscheinlich"/>
<node CREATED="1731943742648" ID="ID_594247384" MODIFIED="1731943827486" TEXT="gef&#xe4;hrlich w&#xe4;re DataSeed sehr klein oder nahe Max-uint">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...weil es dann passieren k&#246;nnte, da&#223; f&#252;r bestimmte Familien die Frames sich nicht mehr unterscheiden
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node COLOR="#338800" CREATED="1731900560669" ID="ID_553408936" MODIFIED="1731900581648" TEXT="diesen aber ansonsten aus dem default / oder entropy-Generator ziehen">
<icon BUILTIN="button_ok"/>
@ -56822,6 +56826,12 @@
<linktarget COLOR="#5b9aaa" DESTINATION="ID_1432722861" ENDARROW="Default" ENDINCLINATION="63;7;" ID="Arrow_ID_1569718697" SOURCE="ID_1990276915" STARTARROW="None" STARTINCLINATION="61;0;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731944016612" ID="ID_1328551493" MODIFIED="1731944033914" TEXT="definiere Metadaten-Header">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731944023419" ID="ID_799758026" MODIFIED="1731944033915" TEXT="lege diesen hinter die Nutzdaten">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node COLOR="#338800" CREATED="1728787025826" ID="ID_1972770219" MODIFIED="1730835694593" TEXT="Accessor und Iteration">
<icon BUILTIN="button_ok"/>
@ -56864,8 +56874,24 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731947552403" ID="ID_604836518" MODIFIED="1731947561332" TEXT="im Header hinterlegen">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731947702842" ID="ID_745455518" MODIFIED="1731947715463" TEXT="pr&#xfc;fen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1728786979373" ID="ID_772580400" MODIFIED="1728786987393" TEXT="Metadaten-Erkennung">
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731947576264" ID="ID_767046037" MODIFIED="1731947717471" TEXT="Header-Stamp">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731947640352" ID="ID_122461720" MODIFIED="1731947717470" TEXT="Header lokalisieren">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1731947651342" ID="ID_1504134040" MODIFIED="1731947717470" TEXT="Plausibilit&#xe4;tspr&#xfc;fung">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1728786979373" ID="ID_772580400" MODIFIED="1728786987393" TEXT="Metadaten-Erkennung"/>
<node CREATED="1728786988308" ID="ID_103079985" MODIFIED="1728786992576" TEXT="Pr&#xe4;dikate">
<node CREATED="1728779817892" ID="ID_882765451" MODIFIED="1728779971755" TEXT="isSane">
<richcontent TYPE="NOTE"><html>
@ -90423,8 +90449,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
irgendwie binden wir hier einen Handler ein, der &#187;hinten rum&#171; am Lib-Plugin h&#228;ngt und daf&#252;r einen (privaten) Datentyp konstruiert &#10233; <b>diese</b>&#160; Info mu&#223; in den Prototyp eingehen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<linktarget COLOR="#df0449" DESTINATION="ID_373306612" ENDARROW="Default" ENDINCLINATION="-44;-51;" ID="Arrow_ID_937144137" SOURCE="ID_1126512651" STARTARROW="None" STARTINCLINATION="151;7;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
@ -92295,14 +92320,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
wirft auch den internen Daten-Cache weg und re-seeded den Basis-Hash, auf dem die Distinction-ID dann aufbaut
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1731900805220" ID="ID_1253309363" MODIFIED="1731900819630" TEXT="diese reseed() zieht aus dem defaultGen"/>
<node CREATED="1731900821242" ID="ID_1140389439" MODIFIED="1731900831764" TEXT="den kann man somit vorher gezielt seeden"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1728781144210" ID="ID_51267004" MODIFIED="1728781989516" TEXT="Standard Generator-Sequenzen auf jeder Stufe sind unabh&#xe4;ngig hierarchisch">
<node COLOR="#338800" CREATED="1728781144210" ID="ID_51267004" MODIFIED="1731943356338" TEXT="Standard Generator-Sequenzen auf jeder Stufe sind unabh&#xe4;ngig hierarchisch">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92311,7 +92335,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</p>
</body>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1731943358292" ID="ID_619750163" MODIFIED="1731943374281" TEXT="lie&#xdf; sich mit dem neuen &#xbb;Baukasten&#xab; leicht realisieren">
<icon BUILTIN="ksmiletris"/>
</node>
</node>
</node>
</node>
@ -92826,9 +92853,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1728786385349" ID="ID_442258905" MODIFIED="1731890736163" TEXT="Umbau TestFrame">
<arrowlink COLOR="#713558" DESTINATION="ID_257931093" ENDARROW="Default" ENDINCLINATION="-2466;135;" ID="Arrow_ID_121875527" STARTARROW="None" STARTINCLINATION="-2154;-229;"/>
<linktarget COLOR="#911932" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="-554;-1251;" ID="Arrow_ID_1343565956" SOURCE="ID_127090859" STARTARROW="None" STARTINCLINATION="-195;12;"/>
<linktarget COLOR="#77313e" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="381;-48;" ID="Arrow_ID_1047269362" SOURCE="ID_936086670" STARTARROW="None" STARTINCLINATION="-36;80;"/>
<linktarget COLOR="#6f2328" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="366;-47;" ID="Arrow_ID_1067356199" SOURCE="ID_683548249" STARTARROW="None" STARTINCLINATION="5;52;"/>
<linktarget COLOR="#911932" DESTINATION="ID_442258905" ENDARROW="Default" ENDINCLINATION="-554;-1251;" ID="Arrow_ID_1343565956" SOURCE="ID_127090859" STARTARROW="None" STARTINCLINATION="-195;12;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1730900637026" ID="ID_1500320757" MODIFIED="1731890421828" TEXT="brauche Einflu&#xdf; auf den PRNG">
<richcontent TYPE="NOTE"><html>