diff --git a/src/lib/iter-zip.hpp b/src/lib/iter-zip.hpp
index 7291c0fe1..25e2786ce 100644
--- a/src/lib/iter-zip.hpp
+++ b/src/lib/iter-zip.hpp
@@ -27,16 +27,12 @@
#include "lib/iter-adapter.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/meta/tuple-helper.hpp"
-#include "lib/util.hpp"
-//#include
#include
namespace lib {
-// using util::unConst;
-
namespace iter {
/** construction-helper: apply IterExplorer builder packaged tuple */
@@ -71,11 +67,9 @@ namespace lib {
bool
checkPoint() const
- {
- bool active{true};
- meta::forEach (iters_ // optimiser can unroll and short-circuit
- ,[&](auto& it){ active = active and bool(it); });
- return active;
+ { //note: short-circuit
+ return std::apply ([](auto&... its) { return (bool(its) and ...); }
+ , iters_);
}
ITUP&
diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests
index 2533b0d01..dcb1d0da9 100644
--- a/tests/12metaprogramming.tests
+++ b/tests/12metaprogramming.tests
@@ -356,7 +356,7 @@ return: 0
END
-PLANNED "Tuple-zipped iterators" IterZip_test <()
@@ -77,7 +72,10 @@ namespace test{
/*********************************************************************************//**
* @test demonstrate construction and verify behaviour of a combined-iterator builder.
* - construction from arbitrary arguments by tuple-mapping a builder function
- *
+ * - defining the operation on the product type by lifting individual operations
+ * - use the library building blocks to construct a zip-iter-builder
+ * - iterate a mix of source iterators and containers
+ * - apply additional processing logic by pipelining
* @see IterExplorer
* @see IterExplorer_test
*/
@@ -94,7 +92,7 @@ namespace test{
verify_iteration();
verify_references();
- UNIMPLEMENTED ("nebbich.");
+ verify_pipelining();
}
@@ -308,9 +306,72 @@ namespace test{
"«tuple»──(2,7,8,9)-"
"«tuple»──(3,10,11,12)-"
"«tuple»──(4,13,14,15)"_expect);
+
+
+ auto s6 = std::array{1,1,2,3,5,8};
+ auto s3 = {3,2,1};
+ auto s0 = eachNum(5u,5u);
+ CHECK (TYPE(s6) == "array"_expect );
+ CHECK (TYPE(s3) == "initializer_list"_expect );
+ CHECK (TYPE(s0) == "NumIter"_expect );
+
+ CHECK (materialise (
+ zip (s6,s6,s6,eachNum('a'))
+ )
+ == "«tuple»──(1,1,1,a)-"
+ "«tuple»──(1,1,1,b)-"
+ "«tuple»──(2,2,2,c)-"
+ "«tuple»──(3,3,3,d)-"
+ "«tuple»──(5,5,5,e)-"
+ "«tuple»──(8,8,8,f)"_expect);
+
+ CHECK (materialise (
+ zip (s6,s3,s6,eachNum('a'))
+ )
+ == "«tuple»──(1,3,1,a)-"
+ "«tuple»──(1,2,1,b)-"
+ "«tuple»──(2,1,2,c)"_expect);
+
+ CHECK (isnil (s0));
+ CHECK (materialise (
+ zip (s0,s3,s6,eachNum('a'))
+ )
+ == ""_expect);
+
+ CHECK (materialise (
+ zip (eachNum('a'),eachNum(-1),s0,s0)
+ )
+ == ""_expect);
+
+ CHECK (materialise (
+ zip (eachNum('a'),eachNum(-1),s3,s0)
+ )
+ == ""_expect);
+
+ CHECK (materialise (
+ zip (eachNum('a'),eachNum(-1),s3,s3)
+ )
+ == "«tuple»──(a,-1,3,3)-"
+ "«tuple»──(b,0,2,2)-"
+ "«tuple»──(c,1,1,1)"_expect);
+
+ // a wild mix of data sources,
+ // including infinite and virtual ones....
+ CHECK (materialise (
+ izip (s6 // a STL container given by reference
+ ,explore(s6).filter([](int i){ return i%2; }) // IterExplorer pipeline with filtering
+ ,numS<17,170>().transform(hexed) // IterExplorer pipeline with transformer and object value result
+ ,eachNum((1+sqrt(5))/2) // a Lumiera iterator which happens to be almost inexhaustible
+ ,explore(s3).asIterSource() // an IterSource, which is a virtual (OO) iterator interface
+ )
+ )
+ == "«tuple»──(0,1,1,AA,1.618034,3)-"
+ "«tuple»──(1,1,1,BB,2.618034,2)-"
+ "«tuple»──(2,2,3,CC,3.618034,1)"_expect);
}
+
/** @test verify pass-through of references */
void
verify_references()
@@ -318,7 +379,7 @@ namespace test{
auto vec = std::vector{1,5};
auto arr = std::array{2,3};
- // Case-1
+ // Case-1 ------
auto i1 = izip (vec,arr);
CHECK (*i1 == "«tuple»──(0,1,2)"_expect ); // initial state points to the first elements, prefixed with index≡0
@@ -328,7 +389,7 @@ namespace test{
CHECK (join(vec) == "5, 5"_expect ); // manipulation indeed flipped the first element in the vector
CHECK (join(arr) == "2, 3"_expect ); // (while the array remains unaffected)
- // Case-1
+ // Case-2 ------
auto i2 = izip (explore(vec).transform([](uint v){ return v-1; }) // this time the first iterator is a pipeline with a transformer
,arr); // while the second one is again a direct iteration of the array
@@ -343,6 +404,33 @@ namespace test{
CHECK (join(vec) == "5, 5"_expect ); // ...which is in fact true for the vector, due to the transformer
CHECK (join(arr) == "9, 3"_expect ); // ...while the array could be reached through the reference
}
+
+
+
+
+ /** @test the result is actually an IterExplorer pipeline builder,
+ * which can be used to attach further processing
+ */
+ void
+ verify_pipelining()
+ {
+SHOW_EXPR
+ (materialise (
+ zip (num31(), num32(), num33())
+ . transform([](auto& it){ auto [a,b,c] = *it;
+ return a+b+c;
+ })
+ )
+ )
+SHOW_EXPR
+ (materialise (
+ zip (num31(), num32(), num33())
+ . filter ([](auto& it){ auto [a,b,c] = *it;
+ return not ((a+b+c) % 2);
+ })
+ )
+ )
+ }
/*
SHOW_EXPR
(materialise (
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 68e9dbcc1..ecd08c3d2 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -19017,9 +19017,7 @@
-
-
-
+
premature optimisation??
@@ -19485,9 +19483,7 @@
-
-
-
+
...es würde sich um irgendwelche ausgefallenen Use-Cases handeln, und das direkte Anheften der Kind-Widgets würde dann Overhead sparen, gegenüber einem Canvas; weiterer Vorteil wäre der direkte push-back für die Allokation von Screen-Extension (was allerdings im Falle eines size-constrained Widget dann wieder ein Nachteil wäre)
@@ -19811,9 +19807,7 @@
-
-
-
+
...wobei der Datentyp dieser Verhältniszahlen noch wählbar ist
@@ -20383,9 +20377,7 @@
-
-
-
+
Frage ist, wie viel des Verhaltens programmieren wir selber explizit aus,
@@ -21137,9 +21129,7 @@
-
-
-
+
...und nicht hierarchisch! Letzten Endes geht es nur darum, Widgets an einen gemeinsamen Canvas zu heften
@@ -22890,9 +22880,7 @@
-
-
-
+
theoretisch könnte man eine Timeline ohne Sequenz
@@ -25458,9 +25446,7 @@
-
-
-
+
...nachdem erstmals ein size-request gesetzt wurde, hat sich die tatsächliche Höhe des Widget noch nicht verändert (das wird erst mit dem nachfolgenden resize-event vollzogen). Aber der size-request spiegelt sich sofort in der desired_height wieder. Wir müssen also die Ermittlung der "aktuellen" Höhe darauf aufbauen, damit die schon vorgenommenen Anpassungen nicht nochmal im Delta landen
@@ -37999,9 +37985,7 @@
-
-
-
+
...insofern sie genau an die Struktur anbaut, welche ich schon zur Lösung der Querbeziehungen für das Layout genutzt habe
@@ -40759,9 +40743,7 @@
-
-
-
+
Die µ-Ticks hatten wir seinerzeit gewählt, weil sie einerseits hinreichend genau sind, andererseits sehr einfach zu implementieren, und dennoch die Darstellung extrem großer Zeitspannen ermöglichen
@@ -42121,9 +42103,7 @@
-
-
-
+
ich habe ja ganz bewußt Time::MAX == INT_MAX/3 genommen
@@ -42956,9 +42936,7 @@
-
-
-
+
das geht in Floating-Point aber eben grade nicht in Integer-Bruchrechnung; ein ULP ist der »maximal giftige Bruch«
@@ -43600,9 +43578,7 @@
-
-
-
+
erfordert Analyse aller relevanten Code-Pfade
@@ -43909,9 +43885,7 @@
-
-
-
+
...und zwar in dem Fall, in dem der Nenner nur knapp über der Schwelle LIM_HAZARD liegt; dann findet nämlich fast keine Reduktion der Größenordnung statt
@@ -44207,9 +44181,7 @@
-
-
-
+
parsing '1/250sec' resulted in 0:00:00.003 instead of 0:00:00.004
@@ -52787,8 +52759,8 @@
-
-
+
+
@@ -52923,13 +52895,13 @@
-
-
+
+
-
+
-
-
+
+
@@ -52957,10 +52929,10 @@
Bestenfalls eliminiert der Optimiser ohnehin alle Indirektionen, aber auch alle Kopien. Wenn das aber nicht geht, weil es von irgendwo noch einen Zugriff geben könnte, dann sitzt man auf einem Speicherzugriff, wo andernfalls direkt ein Register verwendet werden könnte. Und wenn dann auch noch die Referenz non-const ist, versaut man sich leicht internen State und wundert sich dann... Nee, nee! Wenn man wirklich Seiteneffekte über Referenzen möchte, dann soll man sich das bitte explizit auscoden, aber nicht eine Library-Funktion kreativ nutzen
-
-
+
-
+
+
@@ -52972,8 +52944,8 @@
-
-
+
+
@@ -52987,8 +52959,7 @@
Das heißt: in dem Moment wo wir die transformer-Funktion tatsächlich installieren, packen wir sie in ein std::function-Objekt mit einer neu synthetisierten Signatur. Diese ist (der Intention nach) paßgenau, d.h. sie nimmt den yield des vorgelagerten Iterators als Input
-
-
+
@@ -53003,8 +52974,7 @@
function<VAL(InType)> trafo_;
-
-
+
@@ -53017,8 +52987,7 @@
viele Jahre später habe ich dann den NumIter definiert, und das ist vielleicht das erste Beispiel, bei dem dieses neue Konzept wirklich ausgereitzt wurde. Ich habe so dunkel in Erinnerung, daß es dann nicht funktioniert hat, und ich deshalb „einfach“ das const in die eingebetteten Ergebnis-Typdefinitionen gepackt habe. Was ja nicht falsch war, aber der Weg des geringsten Wiederstandes
-
-
+
@@ -53029,8 +52998,7 @@
Und das ist mir zunehmend wichtiger geworden, vor allem nach meinen Erfahrungen mit dem monadischen IterExplorer v1. Grade weil man manchmal wirklich nur Values bieten kann, muß diese Hintertür offen bleiben. Andererseits wäre es ein gefährlicher Fehlschluß, daß eine Type-def »reference« hier „in Wirkklichkeit“ meint, das was der Iterator liefert. Der Schluß liegt nahe, und deshalb bin ich ihm hier auch verfallen. Aber wenn man mit derartigem Konzept-Mapping erst mal anfängt, dann verliert man schnell die Kontrolle
-
-
+
@@ -53043,8 +53011,7 @@
in iter-adapter.hpp
-
-
+
@@ -53058,8 +53025,7 @@
also exakt die zentrale Stelle, an der entschieden wird, ob eine nachgeschaltete Funktion auf den Resultat-Wert losgeht, oder direkt auf den Iterator-Typ zugreift
-
-
+
@@ -53069,6 +53035,7 @@
+
@@ -53085,10 +53052,15 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -53096,13 +53068,20 @@
...das würde bedeuten: man reicht eine weitere Typ-Def komplett durch die ganze Kette durch, und jeweils nur am Ende der Kette würde diese für den operator* gelten. Da wir aber Ketten im Builder auch noch nachträglich weiter verlängern, indem eine neue Core darüber gesetzt wird, ist das jedoch nicht ohne Weiteres realisierbar
-
-
+
+
+
+
+
+
+
+
+
@@ -53117,7 +53096,9 @@
-
+
+
+
@@ -53129,9 +53110,54 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ das zwingt mich, einen inneren Quell-Layer in den äußeren Wrapper zu schieben; selbst wenn ich das Argument by-value nehme, ist es damit noch nicht in dem Objekt-Feld, wo es hingehört. Das bedeutet dann, entweder eine Kopie (und man ist vom Optimiser abhängig), oder eben ein move(SRC).
+
+
+
+
+
+
+
+
+
+
+
+
+
+