Library: extract the basic setup for a tuple-zipping iterator
Indeed the solution worked out yesterday could be extracted and turned generic. Some in-depth testing is necessary though, and possibly some qualifications to allow pass-through of references... Moreover, last days I started collecting notes regarding problem solving patterns, which I tend to use frequently, but which might not be obvious and thus can easily be forgotten. In fact, I had encountered several cases, where I did invent some roughly similar solution repeatedly, having forgotten about already settled matters. Hopefully the habit of collecting notes and hints at a central location serves to remedy
This commit is contained in:
parent
b6bdcc068d
commit
f0eeabb29e
6 changed files with 155 additions and 38 deletions
|
|
@ -38,7 +38,8 @@ visualisation::
|
|||
into a relevant test, but commented-out there.
|
||||
+
|
||||
- generate Graphviz diagrams: 'lib/dot-gen.hpp' provides a simple DSL. See 'test-chain-load-test.cpp'
|
||||
- generate Gnuplot scripts: use the Text-Template engine to fill in data, possibly from a data table
|
||||
- generate Gnuplot scripts: use the xref:texttemplate[Text-Template] engine to fill in data, possibly
|
||||
from a generated data table
|
||||
|
||||
* '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
|
||||
|
|
@ -147,8 +148,11 @@ Formatting
|
|||
* the templated front-end passes-through most basic types and types with string-conversion
|
||||
* all invocations are strictly error safe (never throw) and can thus be used from catch-handlers
|
||||
|
||||
- use the *Text-Template* engine. See 'text-template-test.cpp'. Can be used with simple map bindings,
|
||||
but also from a `lib::GenNode` tree, or with a custom defined `DataSource` template
|
||||
- use the anchor:texttemplate[lib/text-template]*Text-Template* engine. See 'text-template-test.cpp'.
|
||||
Can be used with simple map bindings, or even a _definition string_ `"x=42, y=why-not?"`, but can also
|
||||
draw data o from a `lib::GenNode` tree, or even from a custom defined `DataSource` template.
|
||||
Supports placeholders, conditionals and simple loops (and that's it --
|
||||
because there are way more capable solutions _out there_ ☺)
|
||||
|
||||
|
||||
Language constructs
|
||||
|
|
@ -166,7 +170,7 @@ build-from-anything::
|
|||
|
||||
- prevent shadowing of _automatically generated copy operations._
|
||||
See https://issues.lumiera.org/ticket/963[#963]. Based on the ``disable if'' SFINAE technique.
|
||||
A ready-made templated typedef `lib::metadisable_if_self` can be found in 'lib/meta/util.hpp'
|
||||
A ready-made templated typedef `lib::meta::disable_if_self` can be found in 'lib/meta/util.hpp'
|
||||
|
||||
|
||||
Variadics
|
||||
|
|
@ -179,7 +183,7 @@ pick and manipulate individually::
|
|||
- but sometimes it is easier to use the tried and true technique of the Loki-Typelists, which
|
||||
can be programmed recursively, similar to LISP. The »bridge« is to unpack the variadic argument pack
|
||||
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...
|
||||
see https://issues.lumiera.org/ticket/987[#987], use `lib::meta::TySeq` from 'variadic-helper.hpp' as workaround...)
|
||||
+
|
||||
apply functor to each tuple element::
|
||||
A common trick is to use `std::apply` in combination with a _fold-expression_
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ Developer HOWTOs
|
|||
================
|
||||
|
||||
//MENU: title Dev HOWTOs
|
||||
//MENU: prepend child crackNuts
|
||||
|
||||
|
||||
This section contains a loose collection of instructions, recipes, tutorials and
|
||||
|
|
@ -9,8 +10,10 @@ similar usefull pieces of information targeted at Lumiera developers. See also
|
|||
|
||||
- the general link:{l}/project/faq.html[Lumiera FAQ]
|
||||
- the link:{ldoc}/user/index.html[User documentation]
|
||||
- link::{ldoc}/technical/code/index.html[Codebase organisation]
|
||||
|
||||
== Notepad
|
||||
- a link:crackNuts.html[collection] of solution ideas
|
||||
- link:DebugGdbPretty.html[Python pretty printers for GDB]
|
||||
- link:HashFunctions.html[Notes regarding standard hash functions]
|
||||
|
||||
|
|
|
|||
|
|
@ -977,7 +977,8 @@ namespace lib {
|
|||
/** convenience function to iterate "each number" */
|
||||
template<typename INT>
|
||||
inline NumIter<INT>
|
||||
eachNum (INT start, INT end)
|
||||
eachNum (INT start = std::numeric_limits<INT>::min()
|
||||
,INT end = std::numeric_limits<INT>::max())
|
||||
{
|
||||
return NumIter<INT> (start, end);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@
|
|||
#define LIB_ITER_ZIP_H
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/iter-adapter.hpp"
|
||||
#include "lib/iter-explorer.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
//#include <deque>
|
||||
//#include <utility>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -38,7 +38,59 @@ namespace lib {
|
|||
// using util::unConst;
|
||||
|
||||
namespace iter {
|
||||
/** */
|
||||
|
||||
/** construction-helper: apply IterExplorer builder packaged tuple */
|
||||
template<typename...ITS>
|
||||
auto
|
||||
buildIterTuple (ITS&& ...iters)
|
||||
{
|
||||
return make_tuple (lib::explore (std::forward<ITS> (iters)) ...);
|
||||
}
|
||||
|
||||
template<class ITUP>
|
||||
class ProductCore
|
||||
{
|
||||
ITUP iters_;
|
||||
|
||||
public:
|
||||
ProductCore(ITUP&& iterTup)
|
||||
: iters_{move (iterTup)}
|
||||
{ }
|
||||
|
||||
ProductCore() = default;
|
||||
// default copy acceptable
|
||||
|
||||
friend bool
|
||||
operator== (ProductCore const& cor1, ProductCore const& cor2)
|
||||
{
|
||||
return cor1.iters_ == cor2.iters_;
|
||||
}
|
||||
|
||||
|
||||
/* === »state core« protocol API === */
|
||||
|
||||
bool
|
||||
checkPoint() const
|
||||
{
|
||||
bool active{true};
|
||||
meta::forEach (iters_ // optimiser can unroll and short-circuit
|
||||
,[&](auto& it){ active = active and bool(it); });
|
||||
return active;
|
||||
}
|
||||
|
||||
ITUP&
|
||||
yield() const ///< exposing the iterator-tuple itself as »product«
|
||||
{
|
||||
return util::unConst(iters_);
|
||||
}
|
||||
|
||||
void
|
||||
iterNext()
|
||||
{
|
||||
meta::forEach (iters_
|
||||
,[](auto& it){ ++it; });
|
||||
}
|
||||
};
|
||||
} // namespace lib::iter
|
||||
|
||||
|
||||
|
|
@ -46,7 +98,35 @@ namespace lib {
|
|||
/** */
|
||||
|
||||
|
||||
/** convenience free function to build an iterable sequence */
|
||||
/**
|
||||
* Build a tuple-combining iterator builder
|
||||
* @param iters an arbitrary sequence of _iterable entities_
|
||||
* @return an IterExplorer to yield result tuples on iteration
|
||||
* @remark IterExplorer is both a »Lumiera Forward Itertor« and a _Pipeline Builder_
|
||||
* - as Lumiera iterator, it can be used directly in _for-each_ and _while_ loops
|
||||
* - result components can be picked up conveniently through _structural bindings_ for tuples
|
||||
* - using the builder API, results can be postprocessed (apply a function), filtered, searched, reduced...
|
||||
*/
|
||||
template<class...ITS>
|
||||
inline auto
|
||||
zip (ITS&& ...iters)
|
||||
{
|
||||
auto access_result = [](auto& it){ return *it; };
|
||||
auto tuple_results = [&](auto& it){ return meta::mapEach (*it, access_result); };
|
||||
//
|
||||
auto core = iter::ProductCore{iter::buildIterTuple (std::forward<ITS> (iters)...)};
|
||||
//
|
||||
return explore (std::move(core))
|
||||
.transform (tuple_results);
|
||||
}
|
||||
|
||||
/** tuple-combining iterator prefixed by index sequence */
|
||||
template<class...ITS>
|
||||
inline auto
|
||||
izip (ITS&& ...iters)
|
||||
{
|
||||
return zip (eachNum<size_t>(), std::forward<ITS>(iters)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -84,6 +85,7 @@ namespace test{
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
simpleUsage();
|
||||
test_Fixture();
|
||||
demo_mapToTuple();
|
||||
demo_construction();
|
||||
|
|
@ -91,6 +93,26 @@ namespace test{
|
|||
}
|
||||
|
||||
|
||||
/** @test demonstrate combined iteration */
|
||||
void
|
||||
simpleUsage()
|
||||
{
|
||||
auto a = std::array{1u,2u,3u};
|
||||
auto v = std::vector{{2l,3l}};
|
||||
|
||||
for (auto [u,f] : zip(a,v))
|
||||
CHECK (u + 1 == f);
|
||||
|
||||
auto it = izip(v);
|
||||
CHECK (it);
|
||||
SHOW_EXPR(*it)
|
||||
++it;
|
||||
SHOW_EXPR(*it)
|
||||
CHECK (it);
|
||||
++it;
|
||||
CHECK (not it);
|
||||
}
|
||||
|
||||
/** @test demonstrate how the test Fixture is used */
|
||||
void
|
||||
test_Fixture()
|
||||
|
|
@ -120,7 +142,7 @@ namespace test{
|
|||
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)};
|
||||
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; });
|
||||
|
|
@ -139,11 +161,11 @@ namespace test{
|
|||
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
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -200,7 +222,7 @@ namespace test{
|
|||
ITup&
|
||||
yield() const
|
||||
{
|
||||
return unConst(iters_); // ◁─────────────── note: we expose the iterator-touple itself as »product«
|
||||
return unConst(iters_); // ◁─────────────── note: we expose the iterator-tuple itself as »product«
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -52752,8 +52752,7 @@
|
|||
das heißt, der erste erschöpfte Iterator terminiert die gesamte Sequenz
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1732154580080" ID="ID_336146444" MODIFIED="1732154642685" TEXT="wichtige Variante: zip-with-index">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -52763,8 +52762,7 @@
|
|||
damit man auch die Fälle erschlagen kann, in denen irgendwo eine Index-Variable gebraucht wird; oft ist das nämlich der einzige Grund, dann doch eine klassische For-Iteration zu machen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1732154647647" ID="ID_232099852" MODIFIED="1732154650378" TEXT="Technologie">
|
||||
|
|
@ -52811,8 +52809,7 @@
|
|||
stelle fest: ich <b>darf kein Quell-Tupel</b> konstruieren
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</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;"/>
|
||||
|
|
@ -52831,8 +52828,7 @@
|
|||
Es ist eigentlich nur eine Verpackung für std::apply, welches man mit dem gleichen Aufruf-Aufwand stets auch direkt aufrufen könnte. Hinzu kommt, daß nun die Argument-Ordnung auf dem API entweder links-rum oder rechts-rum nicht paßt und verwirrend ist
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1732234715777" ID="ID_1569189170" MODIFIED="1732234822377" TEXT="braucht abar auch gar nicht den Indirektions-Trick">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -52891,8 +52887,7 @@
|
|||
...und damit sind nämlich beide Ansätze letzlich wieder versöhnt. Das war die wichtige Einsicht beim zweiten Design-Anlauf. Beim ersten Anlauf wollte ich »brav« sein und Werte liefern, und das ganze Design wurde dadurch extrem undurchschaubar und wackelig, denn natürlich wurde beim ersten Kontakt mit der Realität klar, daß man dann smart-Pointer durch die Gegend schiebt.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</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>
|
||||
|
|
@ -52939,8 +52934,7 @@
|
|||
(ob dieserer test portabel ist....)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
|
|
@ -52952,18 +52946,34 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235208972" ID="ID_1764687143" MODIFIED="1732235216084" TEXT="nun in eine Klasse extrahieren">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1732235208972" ID="ID_1764687143" MODIFIED="1732308740170" TEXT="nun in Library-Code extrahieren">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732299521810" ID="ID_185815307" MODIFIED="1732299541201" TEXT="schlank halten: es genügt die ProductCore">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732299561444" ID="ID_1140916206" MODIFIED="1732299624657" TEXT="dazu eine free-function iter::buildIterTuple(its...)">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1732308743486" ID="ID_1261102696" MODIFIED="1732308787453" TEXT="Prüfen und erweitern auf das Durchreichen von Referenzen">
|
||||
<linktarget COLOR="#b36e78" DESTINATION="ID_1261102696" ENDARROW="Default" ENDINCLINATION="243;11;" ID="Arrow_ID_1182778536" SOURCE="ID_1663970369" STARTARROW="None" STARTINCLINATION="212;14;"/>
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1732235272468" ID="ID_1892180908" MODIFIED="1732235318053" TEXT="gründlich testen">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
<node COLOR="#338800" CREATED="1732308670586" ID="ID_351914878" MODIFIED="1732308678431" TEXT="einfaches Demo-Beispiel">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1732308679924" ID="ID_762659981" MODIFIED="1732308713186" TEXT="sollte eine For-Schleife zeigen"/>
|
||||
<node COLOR="#435e98" CREATED="1732308687234" ID="ID_981998183" MODIFIED="1732308713186" TEXT="sollte direkten Gebrauch als Iterator sichtbar machen"/>
|
||||
</node>
|
||||
<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">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1732235434406" ID="ID_1663970369" MODIFIED="1732308796716" TEXT="Durchgriff auf die Quellen per Referenz">
|
||||
<arrowlink COLOR="#b36e78" DESTINATION="ID_1261102696" ENDARROW="Default" ENDINCLINATION="243;11;" ID="Arrow_ID_1182778536" STARTARROW="None" STARTINCLINATION="212;14;"/>
|
||||
<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">
|
||||
|
|
@ -93132,8 +93142,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
OutputSlotProtocol_test
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<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>
|
||||
|
|
@ -93146,8 +93155,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<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>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1732224312319" ID="ID_1805320851" MODIFIED="1732224425810" TEXT="Hypothesen...">
|
||||
|
|
@ -93166,8 +93174,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue