Library: investigate how a »zip iterator« can be built

Basically I am sick of writing for-loops in those cases
where the actual iteration is based on one or several data sources,
and I just need some damn index counter. Nothing against for-loops
in general — they have their valid uses — sometimes a for-loop is KISS

But in these typical cases, an iterator-based solution would be a
one-liner, when also exploiting the structured bindings of C++17

''I must admit that I want this for a loooooong time —''
...but always got intimidated again when thinking through the fine points.
Basically it „should be dead simple“ — as they say

Well — — it ''is'' simple, after getting the nasty aspects of tuple binding
and reference data types out of the way. Yesterday, while writing those
`TestFrame` test cases (which are again an example where you want to iterate
over two word sequences simultaneously and just compare them), I noticed that
last year I learned about the `std::apply`-to-fold-expression trick, and
that this solution pattern could be adapted to construct a tuple directly,
thereby circumventing most of the problems related to ''perfect forwarding''

So now we have a new util function `mapEach` (defined in `tuple-helper.hpp`)
and I have learned how to make this application completely generic.

As a second step, I implemented a proof-of-concept in `IterZip_test`,
which indeed was not really challenging, because the `IterExplorer`
is so very sophisticated by now and handles most cases with transparent
type-driven adaptors. A lot of work went into `IterExplorer` over the years,
and this pays off now.

The solution works as follows:
 * apply the `lib::explore()` constructor function to the varargs
 * package the resulting `IterExplorer` instantiations into a tuple
 * build a »state core« implementation which just lifts out the three
   iterator primitives onto this ''product type'' (i.e. the tuple)
 * wrap it in yet another `IterExplorer`
 * add a transformer function on top to extract a value-tuple for each ''yield'

As expected, works out-of-the-box, with all conceivable variants and wild
mixes of iterators, const, pointers, references, you name it....

PS: I changed the rendering of unsigned types in diagnostic output
    to use the short notation, e.g. `uint` instead of `unsigned int`.
    This dramatically improves the legibility of verification strings.
This commit is contained in:
Fischlurch 2024-11-21 23:30:07 +01:00
parent dcbde6d163
commit b6bdcc068d
11 changed files with 785 additions and 79 deletions

View file

@ -7,17 +7,17 @@ Some nasty problems are recurring time and again. Maybe a trick could be found s
in the net, and a library function was created to settle this damn topic once and for all.
Maybe even a nice test and demo is provided. And then the whole story will be forgotten.
_Sounds familiar?_ => ☹☻☺ ~[red]#then please leave a note here...#~
_Sounds familiar?_ => ☹☻☺👻 ~[red]#... then please consider to leave some traces here ...#~
Methods
-------
Mathematics
~~~~~~~~~~~
- some basic descriptive statistics computation are defined in 'lib/stat/statistic.hpp'
- some basic descriptive statistics computations are defined in 'lib/stat/statistic.hpp'
- the simple case for _linear regression_ is also implemented there
- Gnuplot provides also common statistics functions, which may come in handy when the
goal is anyway to create a visualisation (-> see <<investigation,below>>)
goal is anyway to create a visualisation (-> see <<_investigation,below>>)
@ -43,6 +43,50 @@ visualisation::
* 'lib/gnuplot-gen.hpp' provides some pre-canned scripts for statistics plots
* used by the 'stress-test-rig.cpp', in combination with 'data.hpp' to collect measurement results
Testing
~~~~~~~
verify structured data::
build a diagnostic output which shows the nesting
- use configuration by template parameters and use simple numbers or strings as part components
- render the output and compare it with `""_expect` (the `ExpectStr` -> see 'lib/test/test-helper.hpp')
- break the expect-string into parts with indentation, by exploiting the C _string gaps_
However, this works only up to a certain degree of complexity.
A completely different approach is to transform the structured result-data into an ETD (`GenNode` tree)
and then directly compare it to an ETD that is created in the test fixture with the DSL notation (`MakeRec()`)
verify floating point data::
+
- either use approximate comparison
* `almostEqual()` -> see 'lib/test/test-helper.hpp'
* 'util-quant.hpp' has also an `almostEqual(a,b, ulp)`
* [yellow-background]#TODO 2024# should be sorted out -> https://issues.lumiera.org/ticket/1360[#1360]
- or render the floating point with the diagnostic-output functions, which deliberately employ
a built-in rounding to some sensible amount of places (which in most cases helps to weed-out the
``number dust'')
- simply match it against an `ExpectStr` -- which implicitly converts to string, thereby
also applying the aforementioned implicit rounding
+
-> See also <<_formatting,about formatting>> below; in a nutshell, `#include 'lib/format-output.hpp'`
verify fluctuating values::
A first attempt should be made to bring them into some regular band. This can be achieved by
automatically calibrating the measurement function (e.g. do a timing calibration beforehand).
Then the actual value can be matched by the `isLimited(l, val, u)` notation (see 'lib/uitl.hpp')
test with random numbers::
+
- Control the seed! Invoke the seedRand() function once in each test instance.
This draws an actually random number as seed and re-seeds the `lib::defaultGen`. The seed is written to the log.
- But the seed can be set to a fixed value with the `--seed` parameter of the test runner.
This is how you reproduce a broken test case.
- Moreover, be sure either to draw all random values from the `defaultGen` or to build a well organised
tree of PRNG instances, which seed from each other. This is especially valuable when the test starts
several threads; each thread should use its own generator then (yet this can be handled sloppy if
the _quality_ of the random number actually does not matter!)
Common Tasks
@ -51,6 +95,44 @@ Data handling
~~~~~~~~~~~~~
persistent data set::
use the `lib::stat::DataTable` ('data.hpp') with CSV rendering -> see 'data-csv-test.cpp'
structured data::
represent it as Lumiera ETD, that is as a tree of `GenNode` elements.
+
- be sure to understand the _essential idea:_ the receiver should act based on _knowledge_
about the structure -- not by _introspection and case-switching_
- however -- for the exceptional case that you _absolutely must discover_ the structure,
then use the visitor feature. This has the benefit of concentrating the logic at one place.
- can represent the notion of a nested scope, with iteration
- provides a convenient DSL notation, especially for testing, which helps to explain
the expected structure visually .
- also useful as output format, both for debugging and because it can be matched against
an expected structure, which is generated with the DSL notation.
- [yellow-background]#(planned)# will be able to map this from/to JSON easily.
Iterating
~~~~~~~~~
Lumiera iterators::
They are designed for convenient usage with low boilerplate (even while this means wasting
some CPU cycles or memory). They are deliberately much simpler than STL iterators, can be
iterated only once, can be bool checked for iteration end, and can be used both in a for-each
construct and in while-loops.
IterExplorer::
The function `lib::explore(IT)` builds on top of these features and is meant to basically
iterate anything that is iterable -- so use it to abstract away the details.
+
- can be filtered and transformed
- can be reduced or collected into a vector
- can be used to build complex layered search- and evaluation schemes
STL-adaptors::
A set of convenience functions like `eachElm(CON)` -- available in 'iter-adapter-stl.hpp'.
Also allows to iterate _each key_ or _value_, and to take snapshots
IterSource::
This is a special Lumiera iterator implementation which delegates through a virtual (OO) interface.
Thus the source of the data can be abstracted away and switched transparently at runtime.
Especially relevant for APIs, to produce a data sequence once and without coupling to details;
even the production-state can be hooked up into the IterSource instance (with a smart-ptr).
This allows e.g. to send a Diff to the UI through the UI-Bus, while the actual generation
and application both happen demand-driven or _lazy..._
Formatting
@ -87,8 +169,8 @@ build-from-anything::
A ready-made templated typedef `lib::metadisable_if_self` can be found in 'lib/meta/util.hpp'
Varargs
~~~~~~~
Variadics
~~~~~~~~~
pick and manipulate individually::
The key trick is to define an _index sequence template,_ which can then be matched against
a processing template for a single argument; and the latter can have partial specialisations
@ -99,11 +181,12 @@ pick and manipulate individually::
into the `lib::meta::Types<ARGS...>` ([yellow-background]#⚠ still broken in 2024#
see https://issues.lumiera.org/ticket/987[#987], use `lib::meta::TySeq` from 'variadic-helper.hpp' as workaround...
+
apply functor to each::
apply functor to each tuple element::
A common trick is to use `std::apply` in combination with a _fold-expression_
+
- provided as `lib::meta::forEach` in 'lib/meta/util.hpp
- provided as `lib::meta::forEach` in 'lib/meta/tuple-helper.hpp
- The design of the `DataTable` with CSV-Formatting is based on this technique, see 'lib/stat/data.hpp'
- 'lib/iter-zip.hpp' uses this to construct a tuple-of-iterators
- 'test-rand-ontology.cpp' uses this in `manipulateFrame()` to accept an arbitrary number of input chains
+
unpack iterator into tuple::

View file

@ -160,7 +160,7 @@ namespace util {
_RangeIter(IT&& srcIter)
: iter(std::forward<IT>(srcIter))
{ }
_RangeIter(IT const& srcIter)
_RangeIter(IT const& srcIter) // note: copy here
: iter(srcIter)
{ }
@ -170,7 +170,9 @@ namespace util {
/**
* enumerate a collection's contents, separated by delimiter.
* @param coll something that is standard-iterable
* @param coll something that is standard- or Lumiera-iterable
* @note Lumiera-iterator is copied when given by ref, otherwise moved,
* while in all other cases the source container is taken by const&
* @return all contents converted to string and joined into
* a single string, with separators interspersed.
* @remarks based `ostringstream`; additionally, we use our
@ -191,7 +193,7 @@ namespace util {
join (CON&& coll, string const& delim =", ")
{
using Coll = typename lib::meta::Strip<CON>::TypePlain;
_RangeIter<Coll> range(std::forward<CON>(coll));
_RangeIter<Coll> range(std::forward<CON>(coll)); // copies when CON is reference
auto strings = stringify (std::move (range.iter));
if (!strings) return "";

View file

@ -936,7 +936,7 @@ namespace lib {
bool
isValid () const
{
return (i_!= INT()) && (i_ < e_); // NOTE: use comparison to detect iteration end
return i_ < e_; // NOTE: use comparison to detect iteration end
}
bool

View file

@ -517,8 +517,8 @@ namespace lib {
BaseAdapter(SRC const& src) : SRC{src} { }
BaseAdapter(SRC && src) : SRC{forward<SRC> (src)} { }
void expandChildren() { }
size_t depth() const { return 0; }
void expandChildren() { } ///< collaboration: recurse into nested scope
size_t depth() const { return 0; } ///< collaboration: number of nested scopes
};

54
src/lib/iter-zip.hpp Normal file
View file

@ -0,0 +1,54 @@
/*
ITER-ZIP.hpp - join several iterators into a iterator-of-tuples
Copyright (C)
2024, 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 iter-zip.hpp
** Iterator builder to combine several iterables into a tuple sequence.
**
** @see IterZip_test
** @see iter-explorer.hpp
**
*/
#ifndef LIB_ITER_ZIP_H
#define LIB_ITER_ZIP_H
#include "lib/error.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/meta/tuple-helper.hpp"
//#include "lib/util.hpp"
//#include <deque>
//#include <utility>
namespace lib {
// using util::unConst;
namespace iter {
/** */
} // namespace lib::iter
/** */
/** convenience free function to build an iterable sequence */
} // namespace lib
#endif /*LIB_ITER_ZIP_H*/

View file

@ -48,6 +48,7 @@
#include "lib/meta/util.hpp"
#include <tuple>
#include <utility>
namespace util { // forward declaration
@ -61,24 +62,76 @@ namespace util { // forward declaration
namespace lib {
namespace meta {
/** trait to detect tuple types */
template<typename T>
struct is_Tuple
: std::false_type
{ };
template<typename...TYPES>
struct is_Tuple<std::tuple<TYPES...>>
: std::true_type
{ };
template<typename...TYPES>
struct is_Tuple<const std::tuple<TYPES...>>
: std::true_type
{ };
template<class TUP>
using enable_if_Tuple = lib::meta::enable_if<lib::meta::is_Tuple<std::remove_reference_t<TUP>>>;
template<class TUP>
using disable_if_Tuple = lib::meta::disable_if<lib::meta::is_Tuple<std::remove_reference_t<TUP>>>;
/**
* Helper: perform some arbitrary operation on each element of a tuple.
* Tuple iteration: perform some arbitrary operation on each element of a tuple.
* @note the given functor must be generic, since each position of the tuple
* may hold a data element of different type.
* @remark credits to David Vandevoorde (member of C++ committee) for using
* std::apply to unpack the tuple's contents into an argument pack and
* then employ a fold expression with the comma operator.
*/
template<class FUN, typename...ELMS>
void forEach (std::tuple<ELMS...>&& tuple, FUN fun)
template<class TUP, class FUN, typename = enable_if_Tuple<TUP>>
void
forEach (TUP&& tuple, FUN fun)
{
std::apply ([&fun](auto&... elms)
{
(fun(elms), ...);
}
,tuple);
std::apply ([&fun](auto&&... elms)
{
(fun (std::forward<decltype(elms)> (elms)), ...);
}
,std::forward<TUP> (tuple));
}
/**
* Apply some arbitrary function onto all elements of a tuple.
* @return a new tuple constructed from the results of this function
* @note the functor must be generic and able to work with all element types
* @warning pay attention to references; the function can take arguments by-ref
* and manipulate them (side-effect), and it may return references,
* which will be placed as such into the result tuple; furthermore,
* the argument tuple can also be taken as reference...
* @remark The tuple constructor invocation is preceded by a regular argument evaluation,
* which has unspecified evaluation order (even in C++17); _no assumptions_ can be
* made regarding the order the functor will see the source tuple elements.
* Notably this differs from #forEach, where a fold-expression with comma-operator
* is used, which is guaranteed to evaluate from left to right.
*/
template<class TUP, class FUN, typename = enable_if_Tuple<TUP>>
auto
mapEach (TUP&& tuple, FUN fun)
{
return std::apply ([&fun](auto&&... elms)
{ //..construct the type explicitly (make_tuple would decay fun result types)
using Tuple = std::tuple<decltype(fun (std::forward<decltype(elms)> (elms))) ...>;
return Tuple (fun (std::forward<decltype(elms)> (elms)) ...);
}
,std::forward<TUP> (tuple));
}
namespace { // rebinding helper to create std::tuple from a type sequence
@ -153,17 +206,6 @@ namespace meta {
};
/** trait to detect tuple types */
template<typename T>
struct is_Tuple
: std::false_type
{ };
template<typename...TYPES>
struct is_Tuple<std::tuple<TYPES...>>
: std::true_type
{ };

View file

@ -356,6 +356,11 @@ return: 0
END
PLANNED "Tuple-zipped iterators" IterZip_test <<END
return: 0
END
TEST "Iterable type detection" IterableClassification_test <<END
out: can_STL_ForEach<LongVector> : Yes
out: can_STL_ForEach<TimeSet> : Yes

View file

@ -184,11 +184,11 @@ namespace test{
};
/** Diagnostic helper: join all the elements from a _copy_ of the iterator */
/** Diagnostic helper: join all the elements from the iterator */
template<class II>
inline string
materialise (II&& ii)
{
{ // note: copy here when given by-ref
return util::join (std::forward<II> (ii), "-");
}

View file

@ -0,0 +1,266 @@
/*
IterZip(Test) - verify the iterator-combining iterator
Copyright (C)
2024, 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 iter-stack-test.cpp
** unit test \ref IterZip_test
*/
#include "lib/test/run.hpp"
#include "lib/iter-zip.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/test/diagnostic-output.hpp"/////////////TODO
#include "lib/format-util.hpp"
#include "lib/util.hpp"
#include <array>
namespace lib {
namespace test{
// using ::Test;
// using util::isnil;
// using LERR_(ITER_EXHAUST);
using lib::meta::forEach;
using lib::meta::mapEach;
using std::make_tuple;
using std::tuple;
using std::get;
namespace {// Test Fixture ...
auto num5() { return NumIter{0,5}; }
template<uint N, uint S=0>
auto numS() { return explore(num5()).transform([](int i){ return i*N + S; }); }
auto num31(){ return numS<3,1>(); }
auto num32(){ return numS<3,2>(); }
auto num33(){ return numS<3,3>(); }
auto hexed = [](int i){ return util::showHash(i,1); };
/** Diagnostic helper: join all the elements from the iterator */
template<class II>
inline string
materialise (II&& ii)
{
return util::join (std::forward<II> (ii), "-");
}
}
/////////////////////////////////////////
/////////////////////////////////////////
#define TYPE(_EXPR_) showType<decltype(_EXPR_)>()
/*********************************************************************************//**
* @test demonstrate construction and verify behaviour of a combined-iterator builder.
* - construction from arbitrary arguments by tuple-mapping a builder function
*
* @see IterExplorer
* @see IterExplorer_test
*/
class IterZip_test : public Test
{
virtual void
run (Arg)
{
test_Fixture();
demo_mapToTuple();
demo_construction();
UNIMPLEMENTED ("nebbich.");
}
/** @test demonstrate how the test Fixture is used */
void
test_Fixture()
{
CHECK (materialise (num5() ) == "0-1-2-3-4"_expect);
CHECK (materialise (num31() ) == "1-4-7-10-13"_expect);
CHECK (materialise (num33() ) == "3-6-9-12-15"_expect);
CHECK (materialise (num32()
.transform(hexed)
) == "02-05-08-0B-0E"_expect);
}
/** @test demonstrate to apply a function to tuple contents */
void
demo_mapToTuple()
{
auto t1 = make_tuple (41u, 0.61803, '6');
CHECK (t1 == "«tuple<uint, double, char>»──(41,0.61803,6)"_expect );
auto t1f = mapEach (t1, [](auto v){ return v+1; });
CHECK (t1f == "«tuple<uint, double, int>»──(42,1.61803,55)"_expect ); // ASCII('6') ≙ 54 promoted to int
auto t1ff = mapEach (t1, [](auto& v){ v += 1; return v; });
CHECK (t1ff == "«tuple<uint, double, char>»──(42,1.61803,7)"_expect );
CHECK (t1f == "«tuple<uint, double, int>»──(42,1.61803,55)"_expect );
CHECK (t1 == "«tuple<uint, double, char>»──(42,1.61803,7)"_expect ); // src-tuple t1 affected by side-effect
// tuple may hold a reference....
tuple<char, char&> t2{get<2>(t1),get<2>(t1ff)};
CHECK (t2 == "«tuple<char, char&>»──(7,7)"_expect );
auto t2f = mapEach (t2, [](auto& v){ v -= 1; return v; });
CHECK (t2f == "«tuple<char, char>»──(6,6)"_expect ); // function-result is value, thus res-tuple holds values
CHECK (t2 == "«tuple<char, char&>»──(6,6)"_expect); // ...but src-tuple t2 was affected by side-effect
CHECK (t1ff == "«tuple<uint, double, char>»──(42,1.61803,6)"_expect ); // ...which in turn holds a ref, so value in t1ff changed
CHECK (t1 == "«tuple<uint, double, char>»──(42,1.61803,7)"_expect ); // ...while the other one was picked by value => t1 unchanged
// function may return references....
auto refr = [](auto&& v) -> decltype(auto) { return v; };
int five = 5;
CHECK (TYPE (refr(five)) == "int&"_expect);
CHECK (TYPE (refr(5 )) == "int&"_expect);
auto t2r = mapEach (t2, refr);
CHECK (t2r == "«tuple<char&, char&>»──(6,6)"_expect ); // function yields references, which are placed into res-tuple
forEach (t2r, [](auto& v){ v +=23; });
CHECK (t2r == "«tuple<char&, char&>»──(M,M)"_expect ); // apply operation with side-effect to the last res-tuple t2r
CHECK (t2 == "«tuple<char, char&>»──(M,M)"_expect ); // the referred src-tuple t2 is also affected
CHECK (t2f == "«tuple<char, char>»──(6,6)"_expect ); // (while previously constructed t2f holds values unaffected)
CHECK (t1 == "«tuple<uint, double, char>»──(42,1.61803,7)"_expect ); // the first elm in t2 was bound by value, so no side-effect
CHECK (t1ff =="«tuple<uint, double, char>»──(42,1.61803,M)"_expect ); // but the second elm in t2 was bound by ref to t1ff
}
template<typename...ITS>
auto
buildIterTuple (ITS&& ...iters)
{
return make_tuple (lib::explore (std::forward<ITS> (iters)) ...);
}
/** @test demonstrate how a tuple-zipping iterator can be constructed */
void
demo_construction()
{
// let's start with the basics...
// We can use lib::explore() to construct a suitable iterator,
// and thus we can apply it to each var-arg and place the results into a tuple
auto arry = std::array{3u,2u,1u};
auto iTup = buildIterTuple (num5(), arry);
CHECK (TYPE(iTup) == "tuple<IterExplorer<iter_explorer::BaseAdapter<NumIter<int> > >, "
"IterExplorer<iter_explorer::BaseAdapter<iter_explorer::StlRange<array<uint, 3ul>&> > > >"_expect);
// and we can use them as iterators...
auto iterate_it = [](auto& it){ ++it; };
auto access_val = [](auto& it){ return *it; };
forEach (iTup, iterate_it);
auto vTup = mapEach (iTup, access_val);
CHECK (vTup == "«tuple<int, uint>»──(1,2)"_expect);
using ITup = decltype(iTup);
// Next step: define a »product iterator«
// by mapping down each of the base operations onto the tuple elements
struct ProductCore
{
ITup iters_;
ProductCore(ITup&& iterTup)
: iters_{move (iterTup)}
{ }
/* === »state core« protocol API === */
bool
checkPoint() const
{
bool active{true}; // note: optimiser can unroll this
forEach (iters_, [&](auto& it){ active = active and bool(it); });
return active;
}
ITup&
yield() const
{
return unConst(iters_); // ◁─────────────── note: we expose the iterator-touple itself as »product«
}
void
iterNext()
{
forEach (iters_, [](auto& it){ ++it; });
}
};
// ....and now we're essentially set!
// use library building blocks to construct a tuple-iter-explorer...
auto ii = explore (ProductCore{buildIterTuple (num5(), arry)})
.transform ([&](ITup& iTup){ return mapEach (iTup, access_val); })
;
// hold onto your hat!!!
CHECK (TYPE(ii) == "IterExplorer<"
"IterableDecorator<"
"tuple<int, uint>, " // ◁──────────────────────────────── this is the overall result type
"CheckedCore<"
"iter_explorer::Transformer<" // ◁──────────────────────────────── the top-layer is a Transformer (to access the value from each src-iter)
"iter_explorer::BaseAdapter<"
"IterableDecorator<" // ◁──────────────────────────── the product-iterator we constructed
"tuple<" // ◁──────────────────────────── ....exposing the iterator-tuple as „result“
"IterExplorer<" // ◁───────────────────────────────── the first source iterator (directly wrapping NumIter)
"iter_explorer::BaseAdapter<NumIter<int> > >, "
"IterExplorer<" // ◁───────────────────────────────── the second source iterator (based on a STL collection)
"iter_explorer::BaseAdapter<"
"iter_explorer::StlRange<array<uint, 3ul>&> "
"> "
"> "
">, "
"CheckedCore<" // ◁──────────────────────────── ....and using the given ProductCore as »state core«
"IterZip_test::demo_construction()::ProductCore> > >, "
"tuple<int, uint> " // ◁──────────────────────────────── back to top-layer: result-type of the Transformer
"> "
"> "
"> "
">"_expect);
// ....
// This is indeed a valid iterator,
// that can be iterated for three steps
// (limited by the shorter sequence from the array)
// (first value from num5(), second from the array)
CHECK (materialise (ii) == "«tuple<int, uint>»──(0,3)-"
"«tuple<int, uint>»──(1,2)-"
"«tuple<int, uint>»──(2,1)"_expect);
}
/*
SHOW_EXPR
(materialise (
num32().transform(hexed)
)
)
*/
};
LAUNCHER (IterZip_test, "unit common");
}} // namespace lib::test

View file

@ -393,7 +393,7 @@ for} tail...
TextTemplate t3{" 1 ${if a} 2 ${if b} 3 ${else} ${b} ${endif b} 4 ${else}${if a} 5 ${else} ${a} ${endif a}${endif a} 6 "};
CHECK (t3.render("a=2,b=3") == " 1 2 3 4 6 "_expect ); // ^^^^^ Note can never be true here
CHECK (t3.render("a=2,b=0") == " 1 2 0 4 6 "_expect );
CHECK (t3.render("a=0,b=3") == " 1 0 6 "_expect ); // thus if a ≙ false we see only 1 §{a} 6
CHECK (t3.render("a=0,b=3") == " 1 0 6 "_expect ); // thus if a ≙ false we see only 1 ${a} 6
CHECK (t3.render("a=0,b=0") == " 1 0 6 "_expect );
}

View file

@ -18826,9 +18826,7 @@
</node>
<node CREATED="1664312590502" ID="ID_694110716" MODIFIED="1664312697424" TEXT="definitiv: keine erneute Layout-Berechnung und Allokation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
ersichtlich aus Trace-Meldungen, welche ich zur Analyse in den get_preferred_*-Funktionen und beim Setzen der Allokation hatte. Auch auf dem Kind-Elementen sehe ich keine erneuten Aufrufe
@ -19097,9 +19095,7 @@
<icon BUILTIN="broken-line"/>
<node COLOR="#435e98" CREATED="1664834459501" ID="ID_1315620982" MODIFIED="1664834529415" TEXT="war nur ein Klammerungs-Fehler">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
Assignment-Operatoren binden weniger stark als Wertevergleiche, daher ist er immer nach dem ersten Reduktionsschritt ausgestiegen
@ -19562,9 +19558,7 @@
</node>
<node CREATED="1665873885491" ID="ID_131672642" MODIFIED="1665873982614" TEXT="f&#xfc;r Pivot-Content">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...wobei das eigentlich nur f&#252;r den <i>einfachen Use-Case </i>relevant ist; denn im Falle eines komplexen Content-Containers wird die Steuerung, in welche der Container ohnehin eingebunden sein mu&#223; (z.B. der Clip-Controller) wohl auf direktem Wege agieren, ohne durch das ElementBox-Widget zu gehen
@ -19992,9 +19986,7 @@
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
0000001052: INFO: steam-dispatcher.cpp:301: worker_2: processCommands: +++ dispatch Command(&quot;test_fake_injectSequence_1&quot;) {exec}
@ -20782,9 +20774,7 @@
<node CREATED="1569800105842" ID="ID_403274133" MODIFIED="1569800125569" TEXT="w&#xfc;nschenswert w&#xe4;re, den konkreten Zieltyp zu entkoppeln"/>
<node CREATED="1569800749930" ID="ID_1631103689" MODIFIED="1576282358094" TEXT="w&#xfc;nschenswer w&#xe4;re aber auch Quer-Beweglichkeit">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
von Element-Typ A nach Element-Typ B...
@ -22463,9 +22453,7 @@
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1480120294912" HGAP="31" ID="ID_1734639851" MODIFIED="1557498707225" VSHIFT="23">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
grunds&#228;tzliches
@ -25747,9 +25735,7 @@
<node CREATED="1540507009225" ID="ID_104172694" MODIFIED="1557498707227" TEXT="Kinder werden vor Members zerst&#xf6;rt"/>
<node CREATED="1540507040165" ID="ID_1123333647" MODIFIED="1557498707227">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
<u>Fazit</u>: DisplayFrame kann sich auf Parent verlassen
@ -37769,9 +37755,7 @@
<linktarget COLOR="#6c97d3" DESTINATION="ID_937435961" ENDARROW="Default" ENDINCLINATION="144;280;" ID="Arrow_ID_1259911083" SOURCE="ID_369222912" STARTARROW="None" STARTINCLINATION="-332;20;"/>
<node CREATED="1614545300952" ID="ID_1467191869" MODIFIED="1614545455246" TEXT="L&#xf6;sung-1: per &#xdc;bersetzungs-Service direkt manipulieren">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
das bedeutet:<br />
@ -40963,9 +40947,7 @@
</node>
<node CREATED="1667610216018" ID="ID_399148751" MODIFIED="1667610253025" TEXT="insofern ist das hier auch eine sportliche Herausforderung">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...einmal wirklich sicheren Code schreiben...
@ -42637,9 +42619,7 @@
</node>
<node CREATED="1670617402798" ID="ID_30984099" MODIFIED="1670618258486">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
eindeutig: <b>wrap-around</b>&#160;in der relativen &#196;nderung
@ -43559,9 +43539,7 @@
</node>
<node CREATED="1671287277817" ID="ID_1856370622" MODIFIED="1671287319670" TEXT="aber offensichtlich in dieser Situation">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
es w&#228;re schon &#252;berraschend, wenn der Scrollbalken pl&#246;tzlich nicht mehr reagiert....
@ -43970,9 +43948,7 @@
<icon BUILTIN="forward"/>
<node CREATED="1668703944877" ID="ID_676279711" MODIFIED="1668704058851" TEXT="auf Effekt der re-Quantisierung abstellen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<ul>
<li>
@ -45616,9 +45592,7 @@
</node>
<node CREATED="1541775187418" ID="ID_1058458763" MODIFIED="1576282358020" TEXT="Frage: Reproduzierbarkeit irrelevant?">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<head/>
<body>
<p>
...es kommt (vielleicht) &#252;berhaupt nicht darauf an,
@ -45879,9 +45853,7 @@
</node>
<node CREATED="1523019770144" ID="ID_385008471" MODIFIED="1557498707234">
<richcontent TYPE="NODE"><html>
<head>
</head>
<head/>
<body>
<p>
(GlobalCtx)-&gt;WindowLocator-&gt;<b>UIComponentAccessor</b>
@ -52769,6 +52741,236 @@
</node>
</node>
</node>
<node CREATED="1732154493179" ID="ID_1329557703" MODIFIED="1732154500718" TEXT="iter-zip">
<node CREATED="1732154503106" ID="ID_852276140" MODIFIED="1732154521492" TEXT="N Iteratoren in Tupel zusammenf&#xfc;hren">
<node CREATED="1732154525721" ID="ID_161696884" MODIFIED="1732154540166" TEXT="zum Verbinden mehrerer Datenquellen"/>
<node CREATED="1732154540893" ID="ID_1426555488" MODIFIED="1732154577823" TEXT="es gilt die kleinst-m&#xf6;gliche Gesamtsequenz">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das hei&#223;t, der erste ersch&#246;pfte Iterator terminiert die gesamte Sequenz
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1732154580080" ID="ID_336146444" MODIFIED="1732154642685" TEXT="wichtige Variante: zip-with-index">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
damit man auch die F&#228;lle erschlagen kann, in denen irgendwo eine Index-Variable gebraucht wird; oft ist das n&#228;mlich der einzige Grund, dann doch eine klassische For-Iteration zu machen
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1732154647647" ID="ID_232099852" MODIFIED="1732154650378" TEXT="Technologie">
<node CREATED="1732154651158" ID="ID_660736150" MODIFIED="1732154675895" TEXT="komplexes Konstrukt aus variadischen Templates"/>
<node CREATED="1732154676675" ID="ID_515540198" MODIFIED="1732154705046" TEXT="beruht auf Tuples, std::apply und dem IterExplorer als Builder"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1732154713702" ID="ID_1753947869" MODIFIED="1732154721829" TEXT="per Experiment schrittweise aufbauen">
<icon BUILTIN="pencil"/>
<node CREATED="1732154727348" ID="ID_1216046809" MODIFIED="1732154731240" TEXT="IterZip_test"/>
<node COLOR="#338800" CREATED="1732207603752" ID="ID_1484345238" MODIFIED="1732220052298" TEXT="Anforderung: Funktion auf Tupel anwenden">
<icon BUILTIN="button_ok"/>
<node CREATED="1732207627754" ID="ID_1652254138" MODIFIED="1732207631076" TEXT="sollte gehen...."/>
<node CREATED="1732207631631" ID="ID_1627692250" MODIFIED="1732207639059" TEXT="ist aber &#xfc;berraschend trickreich im Detail"/>
<node CREATED="1732207656021" ID="ID_239336325" MODIFIED="1732207680094" TEXT="mu&#xdf; &#xfc;berall perfect-forwarding einf&#xfc;hren">
<node CREATED="1732207683833" ID="ID_410737614" MODIFIED="1732207689141" TEXT="auch auf die Funktions-Argumente"/>
<node CREATED="1732207704615" ID="ID_136259188" MODIFIED="1732207746785" TEXT="auto&amp;&amp;... elms &#x27fc; fun (forward&lt;decltype(elms)&gt; (elms)) ...">
<font NAME="Monospaced" SIZE="10"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1732207762039" ID="ID_1456671988" MODIFIED="1732220042510" TEXT="Problem: R&#xfc;ckgabewert der Funktion">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1732207772990" ID="ID_1470710997" MODIFIED="1732207779577" TEXT="std::make_tuple macht ein decay()"/>
<node CREATED="1732207780261" ID="ID_1005625769" MODIFIED="1732207798438" TEXT="std::forward_as_tuple erzeugt &#xfc;berall R|L-Referenzen"/>
<node COLOR="#435e98" CREATED="1732220024861" ID="ID_1608709580" MODIFIED="1732220040329" TEXT="mu&#xdf; also explizit den Ergebnis-Tupel-Typ konstruieren">
<icon BUILTIN="yes"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1732220073140" ID="ID_1314042362" MODIFIED="1732235218812" TEXT="Iteratoren-Tupel konstruieren">
<icon BUILTIN="pencil"/>
<node CREATED="1732220106650" ID="ID_230100123" MODIFIED="1732220117095" TEXT="lib::explore() sollte die eigentliche (schwere) Arbeit machen"/>
<node CREATED="1732220131993" ID="ID_1112527704" MODIFIED="1732234616020" TEXT="hoffe, da&#xdf; das mit perfect-forwarding funktioniert">
<arrowlink COLOR="#d41f46" DESTINATION="ID_1711720667" ENDARROW="Default" ENDINCLINATION="-179;-10;" ID="Arrow_ID_880963824" STARTARROW="None" STARTINCLINATION="176;10;"/>
</node>
<node COLOR="#338800" CREATED="1732220149904" ID="ID_734335248" MODIFIED="1732235197250" TEXT="im Testfall explizit durchspielen">
<icon BUILTIN="button_ok"/>
<node CREATED="1732220193074" ID="ID_322908141" MODIFIED="1732220195869" TEXT="demo_construction()"/>
<node CREATED="1732220196361" ID="ID_1154553759" MODIFIED="1732220205672" TEXT="schrittweise mit lokalen Klassen aufbauen...">
<node COLOR="#435e98" CREATED="1732220420635" ID="ID_665925849" MODIFIED="1732234993815" TEXT="Builder f&#xfc;r das Iteratoren-Tupel">
<node CREATED="1732234471735" ID="ID_1749059928" MODIFIED="1732234491522">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
stelle fest: ich <b>darf kein Quell-Tupel</b>&#160;konstruieren
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1732234492677" ID="ID_1711720667" MODIFIED="1732234609138" TEXT="weil dann das Thema perfect-forwarding dazwischen liegt">
<linktarget COLOR="#d41f46" DESTINATION="ID_1711720667" ENDARROW="Default" ENDINCLINATION="-179;-10;" ID="Arrow_ID_880963824" SOURCE="ID_1112527704" STARTARROW="None" STARTINCLINATION="176;10;"/>
</node>
<node CREATED="1732234626323" ID="ID_987261541" MODIFIED="1732234641012" TEXT="der Tupel-Konstruktor &#xbb;materialsiert&#xab; dann praktisch immer eine Kopie"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732234650247" ID="ID_1807559774" MODIFIED="1732234984331" TEXT="brauche also eine dedizierte Funktion buildIterTuple&lt;ARGS....&gt;">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#5b280f" CREATED="1732234686810" ID="ID_1016277466" MODIFIED="1732234699400" TEXT="k&#xf6;nnte man auch als generisches Util extrahieren">
<icon BUILTIN="button_cancel"/>
</node>
<node CREATED="1732234700409" ID="ID_1071100462" MODIFIED="1732234887753" TEXT="nein: ist aus diversen Gr&#xfc;nden ungl&#xfc;cklich">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Es ist eigentlich nur eine Verpackung f&#252;r std::apply, welches man mit dem gleichen Aufruf-Aufwand stets auch direkt aufrufen k&#246;nnte. Hinzu kommt, da&#223; nun die Argument-Ordnung auf dem API entweder links-rum oder rechts-rum nicht pa&#223;t und verwirrend ist
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1732234715777" ID="ID_1569189170" MODIFIED="1732234822377" TEXT="braucht abar auch gar nicht den Indirektions-Trick">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
der spezielle Trick mit dem inneren Lambda ist nur f&#252;r ein Tupel notwendig, um die Tupel-Elemente flexibel aber korrekt wieder in die Hand zu bekommen (alternativ mu&#223;te man vor C++17 mit einem Index-Seq-Iterator arbeiten, was sehr undurchsichtig ist)
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#e0daaa" COLOR="#54207a" CREATED="1732234889375" ID="ID_1286476344" MODIFIED="1732234957940" TEXT="insofern war forEach und mapEach nur eine sinnvolle Finger&#xfc;bung">
<icon BUILTIN="smiley-angry"/>
</node>
<node BACKGROUND_COLOR="#dae0aa" COLOR="#2b4871" CREATED="1732234910836" ID="ID_641389884" MODIFIED="1732234976379" TEXT="und hat einen Bug entdeckt">
<icon BUILTIN="smiley-oh"/>
</node>
</node>
</node>
<node CREATED="1732220486306" ID="ID_1365741784" MODIFIED="1732220498253" TEXT="darauf aufbauende StateCore">
<node COLOR="#435e98" CREATED="1732235006036" ID="ID_1047395328" MODIFIED="1732235081898" TEXT="Problem: Konstruktor und Typ-Deduktion">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#6e1370" CREATED="1732235022069" ID="ID_79338843" MODIFIED="1732235075381" TEXT="ja das leidige Problem mit Katze und Schwanz">
<icon BUILTIN="smiley-angry"/>
</node>
<node COLOR="#435e98" CREATED="1732235026957" ID="ID_340250680" MODIFIED="1732235048697" TEXT="hilft nur: builderTuple als free-Function vorschalten">
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1732220525941" ID="ID_1741213182" MODIFIED="1732233792633" TEXT="exponiert das Iteratoren-Tupel">
<arrowlink COLOR="#fdfbda" DESTINATION="ID_214181349" ENDARROW="Default" ENDINCLINATION="-24;-16;" ID="Arrow_ID_568621399" STARTARROW="None" STARTINCLINATION="-144;12;"/>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1732220536045" ID="ID_1165298197" MODIFIED="1732220565132" TEXT="implementiert die Produkt-Operationen durch Delegieren"/>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1732221642486" ID="ID_1450873226" MODIFIED="1732233711887" TEXT="neues Problem: expander-Kollaborations-API weitergeben">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1732221665403" ID="ID_421112241" MODIFIED="1732221694417" TEXT="bisher wurde dieses auf dem BaseAdapter terminiert"/>
<node CREATED="1732221701598" ID="ID_776445249" MODIFIED="1732221710825" TEXT="ich brauche also einen anderen Base-Adapter"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732221711745" ID="ID_1004997061" MODIFIED="1732233705544" TEXT="&#x27f9; den untersten InterExplorer-Layer mu&#xdf; ich explizit konstruieren">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node CREATED="1732233745033" ID="ID_214181349" MODIFIED="1732233786889" TEXT="daraus das Value-Tuple per Transformer erzeugen">
<linktarget COLOR="#fdfbda" DESTINATION="ID_214181349" ENDARROW="Default" ENDINCLINATION="-24;-16;" ID="Arrow_ID_568621399" SOURCE="ID_1741213182" STARTARROW="None" STARTINCLINATION="-144;12;"/>
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#990033" CREATED="1732233814628" ID="ID_1179162924" MODIFIED="1732233837028" TEXT="ist das ineffizient? Nein!">
<icon BUILTIN="help"/>
<node CREATED="1732233846981" ID="ID_1798367169" MODIFIED="1732233860677" TEXT="und zwar deshalb weil alle Iteratoren per Referenz liefern"/>
<node CREATED="1732234159618" ID="ID_778779021" MODIFIED="1732234307409" TEXT="...hat aber zur Konsequenz, da&#xdf; der Transformer ggfs ein Zwischenergebnis materialisiert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...und damit sind n&#228;mlich beide Ans&#228;tze letzlich wieder vers&#246;hnt. Das war die wichtige Einsicht beim zweiten Design-Anlauf. Beim ersten Anlauf wollte ich &#187;brav&#171; sein und Werte liefern, und das ganze Design wurde dadurch extrem undurchschaubar und wackelig, denn nat&#252;rlich wurde beim ersten Kontakt mit der Realit&#228;t klar, da&#223; man dann smart-Pointer durch die Gegend schiebt.
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1732233861279" ID="ID_1970755076" MODIFIED="1732234153457" TEXT="das ist ein ganz zentrales Element in meinem Design">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
....aber auch der Punkt, an dem es immer wieder gef&#228;hrlich wird.
</p>
<p>
<b>Warum ist das so wichtig</b>?
</p>
<p>
<u>Antwort</u>: weil <i>nur dadurch</i>&#160;ein Iterator durch eine Abstraktions-Barriere hindurch arbeiten kann. Der Aufbau eines komplexen Such-Algorithmus erfolgt meist in mehreren Layern, und man m&#246;chte eben nicht, da&#223; irgendwo von unten Werte geliefert werden m&#252;ssen, die dann oben &#187;passen&#171;. Sondern man m&#246;chte mehrere (oft virtuelle) Funktionsaufrufe aufeinander mappen. Und nicht zuletzt dadurch kann man geziehlt einzelne Werte in einem anderen Implementierungs-Realm zur Manipulation exponieren. Denn tats&#228;chlich ist ein solcher IterExplorer eine <b>View in eine State-Core</b>
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1732234325771" ID="ID_1993168197" MODIFIED="1732234454948" TEXT="normalerweise liegen im Wert-Tupel im ItemWrapper stets Referenzen">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Im Normalfall liefert schon der Quell-Iterator eine Referenz (oder const-Referenz). Und die wird dann durch das Value-Tuple durchgemappt und zeigt eigentlich in die State-Core oder einen unterliegenden Container. Wenn aber an irgend einer Stelle tats&#228;chlich ein Wert geliefert werden mu&#223;, so wird das auf diesem Level stets abgefedert, und die stabile Storage f&#252;r den Wert liegt dann im Iterator selber (im ItemWrapper)
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1732235101418" ID="ID_1293064302" MODIFIED="1732235109330" TEXT="erzeugten Typ ausgeben und analysieren">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1732235110393" ID="ID_862638498" MODIFIED="1732235133794" TEXT="oh weh">
<icon BUILTIN="smily_bad"/>
</node>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1732235118688" ID="ID_1779616765" MODIFIED="1732235137022" TEXT="ja ... alles sauber">
<icon BUILTIN="ksmiletris"/>
</node>
<node COLOR="#891569" CREATED="1732235143421" ID="ID_492860011" MODIFIED="1732235191567">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
(ob dieserer test portabel ist....)
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="clanbomber"/>
</node>
</node>
<node COLOR="#338800" CREATED="1732235200691" ID="ID_1709342851" MODIFIED="1732235204957" TEXT="Iteration FUNKTIONIERT">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235208972" ID="ID_1764687143" MODIFIED="1732235216084" TEXT="nun in eine Klasse extrahieren">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1732235272468" ID="ID_1892180908" MODIFIED="1732235318053" TEXT="gr&#xfc;ndlich testen">
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235323997" ID="ID_1085200650" MODIFIED="1732235555231" TEXT="Iteratoren verschiedenen Typs">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235343138" ID="ID_1943784376" MODIFIED="1732235555231" TEXT="per structured Binding verarbeiten">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235434406" ID="ID_1663970369" MODIFIED="1732235555231" TEXT="Durchgriff auf die Quellen per Referenz">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235523602" ID="ID_1940842867" MODIFIED="1732235555232" TEXT="Durchgriff auf Child-Expander im Quell-Iterator">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1535891065189" FOLDED="true" ID="ID_1233342893" MODIFIED="1695502596556" TEXT="Iterator-Monade">
<richcontent TYPE="NOTE"><html>
<head/>
@ -92905,7 +93107,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732122224270" ID="ID_1520955122" MODIFIED="1732122384309" TEXT="brauche Zugang zu den Daten in passendem Format">
<node COLOR="#338800" CREATED="1732122224270" ID="ID_1520955122" MODIFIED="1732224156616" TEXT="brauche Zugang zu den Daten in passendem Format">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -92913,9 +93115,61 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Im Datenblock liegt lediglich eine Sequenz von 1014 Bytes &#8212; man m&#246;chte darauf jedoch flexibel aber getypt zugreifen k&#246;nnen
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1732224177306" ID="ID_479494498" MODIFIED="1732224249981" TEXT="drei Buffer-Provider-Tests scheitern">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
TrackingHeapBlockProvider_test
</p>
<p>
BufferProviderProtocol_test
</p>
<p>
OutputSlotProtocol_test
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="flag-yellow"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1732224193493" ID="ID_279656548" MODIFIED="1732224303644" TEXT="hat wohl alles etws mit der Verifikation von TestFrame zu tun">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
<font face="Monospaced" size="1">0000000515: INFO: testframe.cpp:168: thread_1: getFrame: Growing channel #0 of test frames 0 -&gt; 1 elements. </font>
</p>
<p>
<font face="Monospaced" size="1">0000000516: CHECK: buffer-provider-protocol-test.cpp:107: thread_1: verifySimpleUsage: (</font><font face="Monospaced" size="1" color="#a70202">testData(0) == checker.accessMemory (0)</font><font face="Monospaced" size="1">) </font>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1732224312319" ID="ID_1805320851" MODIFIED="1732224425810" TEXT="Hypothesen...">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<ul>
<li>
k&#246;nnte daran liegen, da&#223; ich f&#252;r testData die Argumente verkehrt herum verdrahtet hatte; da alle drei Tests direkt mit testData arbeiten und selber etwas in den Speicher legen, mu&#223; sich dort diese Verdrehung auch irgendwo im Code niedergeschlagen haben. Ist nat&#252;rlich jetzt nicht einfach zu finden, ohne diese Custom_Allocatoren zu verstehen....
</li>
<li>
es k&#246;nnte aber auch am anderen Memory-Layout liegen....
</li>
<li>
oder am zus&#228;tzlichen Header-Check, der&#160;&#160;nun stattfindet
</li>
</ul>
</body>
</html>
</richcontent>
<icon BUILTIN="hourglass"/>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1732112455819" ID="ID_1055009498" MODIFIED="1732112465158" TEXT="sp&#xe4;ter nachr&#xfc;stbar: Lifecycle">
<icon BUILTIN="hourglass"/>