diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index 1cbd0bcf0..a34f30528 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -396,8 +396,8 @@ namespace engine { connectLeadPort (ProcNode& leadNode, uint port) { uint knownEntry{0}; - for (auto& lead : lib::IndexIter{_Par::leads_}) - if (util::isSameObject (leadNode, lead)) + for (auto& lead : lib::IndexIter{_Par::leads_}) // leads_ holds ref-wrappers + if (util::isSameObject (leadNode, lead.get())) break; else ++knownEntry; diff --git a/src/steam/engine/proc-node.cpp b/src/steam/engine/proc-node.cpp index 4d76406d2..d9b90aa14 100644 --- a/src/steam/engine/proc-node.cpp +++ b/src/steam/engine/proc-node.cpp @@ -308,7 +308,8 @@ namespace engine { ProcNode& p{leads.front().get()}; buffer << "◁—" << procID(p).genNodeName() // show immediate predecessor - << procID(p).genSrcSpec(leads); // and behind that recursively the source(s) + << procID(p).genSrcSpec( // ...followed by it's source(s) + watch(p).leads()); } return buffer.str(); } @@ -322,7 +323,7 @@ namespace engine { explore(leads) .expandAll([](ProcNode& n){ return explore(watch(n).leads()); }) // depth-first expand all predecessors .filter ([](ProcNode& n){ return watch(n).isSrc(); }) // but retain only leafs (≙ source nodes) - .transform([](ProcNode& n){ return procID(n).nodeName_;}) // render the node-symbol of each src + .transform([](ProcNode& n){ return procID(n).nodeName_;}) // render the namespace and name of each src .deduplicate()) // sort and deduplicate + "}"; } diff --git a/tests/core/steam/engine/node-link-test.cpp b/tests/core/steam/engine/node-link-test.cpp index fbfc0415f..d8c624493 100644 --- a/tests/core/steam/engine/node-link-test.cpp +++ b/tests/core/steam/engine/node-link-test.cpp @@ -128,7 +128,7 @@ namespace test { auto src_op = [](int param, int* res){ *res = param; }; // A Node with two (source) ports - ProcNode n1{prepareNode("n1") + ProcNode n1s{prepareNode("srcA") .preparePort() .invoke("a(int)", src_op) .setParam(5) @@ -141,19 +141,19 @@ namespace test { // A node to add some "processing" to each data chain auto add1_op = [](int* src, int* res){ *res = 1 + *src; }; - ProcNode n2{prepareNode("n2") + ProcNode n1f{prepareNode("filterA") .preparePort() .invoke("+1(int)(int)", add1_op) - .connectLead(n1) + .connectLead(n1s) .completePort() .preparePort() .invoke("+1(int)(int)", add1_op) - .connectLead(n1) + .connectLead(n1s) .completePort() .build()}; // Need a secondary source, this time with three ports - ProcNode n1b{prepareNode("n1b") + ProcNode n2s{prepareNode("srcB") .preparePort() .invoke("a(int)", src_op) .setParam(7) @@ -174,36 +174,73 @@ namespace test { // Wiring for the Mix, building up three ports // Since the first source-chain has only two ports, // for the third result port we'll re-use the second source - ProcNode n3{prepareNode("n2") + ProcNode mix{prepareNode("mix") .preparePort() - .invoke("A.mix(int/2)(int)", mix_op) - .connectLead(n2) - .connectLead(n1b) + .invoke("a-mix(int/2)(int)", mix_op) + .connectLead(n1f) + .connectLead(n2s) .completePort() .preparePort() - .invoke("B.mix(int/2)(int)", mix_op) - .connectLead(n2) - .connectLead(n1b) + .invoke("b-mix(int/2)(int)", mix_op) + .connectLead(n1f) + .connectLead(n2s) .completePort() .preparePort() - .invoke("C.mix(int/2)(int)", mix_op) - .connectLeadPort(n2,1) - .connectLead(n1b) + .invoke("c-mix(int/2)(int)", mix_op) + .connectLeadPort(n1f,1) + .connectLead(n2s) .completePort() .build()}; -SHOW_EXPR(watch(n1).getNodeSpec()) -SHOW_EXPR(watch(n1).getPortSpec(0)) -SHOW_EXPR(watch(n1).getPortSpec(1)) -SHOW_EXPR(watch(n1.getPort(0)).getProcSpec()) -SHOW_EXPR(watch(n1.getPort(0)).isSrc()) - - CHECK ( is_linked(n2).to(n1)); - CHECK (not is_linked(n1b).to(n1)); + // verify Node-level connectivity + CHECK ( is_linked(n1f).to(n1s)); + CHECK (not is_linked(n2s).to(n1s)); - CHECK (not is_linked(n3).to(n1)); - CHECK ( is_linked(n3).to(n1b)); - CHECK ( is_linked(n3).to(n2)); + CHECK (not is_linked(mix).to(n1s)); + CHECK ( is_linked(mix).to(n2s)); + CHECK ( is_linked(mix).to(n1f)); + + CHECK (watch(n1s).leads().size() == 0 ); + CHECK (watch(n1f).leads().size() == 1 ); + CHECK (watch(n2s).leads().size() == 0 ); + CHECK (watch(mix).leads().size() == 2 ); + + // verify Node and connectivity spec + CHECK (watch(n1s).getNodeSpec() == "srcA-◎"_expect ); + CHECK (watch(n1f).getNodeSpec() == "filterA◁—srcA-◎"_expect ); + CHECK (watch(n2s).getNodeSpec() == "srcB-◎"_expect ); + CHECK (watch(mix).getNodeSpec() == "mix┉┉{srcA, srcB}"_expect); + + // verify setup of th source nodes + CHECK (watch(n1s).ports().size() == 2 ); + CHECK (watch(n1s).watchPort(0).isSrc()); + CHECK (watch(n1s).watchPort(1).isSrc()); + CHECK (watch(n1s).watchPort(0).getProcSpec() == "srcA.a(int)"_expect ); + CHECK (watch(n1s).watchPort(1).getProcSpec() == "srcA.b(int)"_expect ); + CHECK (watch(n1s).getPortSpec(0) == "srcA.a(int)"_expect ); + CHECK (watch(n1s).getPortSpec(1) == "srcA.b(int)"_expect ); + + CHECK (watch(n2s).ports().size() == 3 ); + CHECK (watch(n2s).watchPort(0).isSrc()); + CHECK (watch(n2s).watchPort(1).isSrc()); + CHECK (watch(n2s).watchPort(2).isSrc()); + CHECK (watch(n2s).watchPort(0).getProcSpec() == "srcB.a(int)"_expect ); + CHECK (watch(n2s).watchPort(1).getProcSpec() == "srcB.b(int)"_expect ); + CHECK (watch(n2s).watchPort(2).getProcSpec() == "srcB.c(int)"_expect ); + CHECK (watch(n2s).getPortSpec(0) == "srcB.a(int)"_expect ); + CHECK (watch(n2s).getPortSpec(1) == "srcB.b(int)"_expect ); + CHECK (watch(n2s).getPortSpec(2) == "srcB.c(int)"_expect ); + + // verify 2-chain + CHECK (watch(n1f).leads().size() == 1 ); + CHECK (watch(n1f).ports().size() == 2 ); + CHECK (watch(n1f).watchPort(0).srcPorts().size() == 1 ); + CHECK (watch(n1f).watchLead(0).ports().size() == 2 ); + CHECK (watch(n1f).watchLead(0).getNodeName() == "srcA"_expect); + CHECK (watch(n1f).watchPort(0).watchLead(0).getProcSpec() == "srcA.a(int)"_expect ); + CHECK (watch(n1f).watchLead(0).watchPort(0).getProcSpec() == "srcA.a(int)"_expect ); + CHECK (watch(n1f).watchPort(0).srcPorts()[0] == watch(n1f).watchLead(0).ports()[0]); + CHECK (watch(n1f).watchPort(1).srcPorts()[0] == watch(n1f).watchLead(0).ports()[1]); } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 15b777b2f..8b00990a1 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -92374,9 +92374,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - @@ -92535,8 +92534,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -92787,15 +92787,14 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- + - - + + - @@ -93299,13 +93298,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - - + + - + @@ -102034,8 +102033,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + @@ -102636,7 +102635,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + @@ -103074,8 +103074,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + @@ -103230,8 +103229,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - + + @@ -103279,10 +103278,12 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + - + + @@ -103315,6 +103316,104 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + + + + + + +

+ das ist inhaltlich falsch! +

+ + +
+
+ + + + + + + + + + + + + + +

+ ⟹ jeder Lead erscheint als neu +

+ + +
+ + +
+
+
+ + + + +
+ + + + + + +
    +
  • + also ohne Namespace +
  • +
  • + dafür aber mit Qualifier +
  • +
  • + ohne Argumentlisten +
  • +
+ +
+ + + + + + + + +

+ die Proc-ID ist hier nur der Implementierungs-Ort, weil es auf der Node selber gar keine entsprechende Einrichtung gibt — der Node-Name ist in die Proc-ID aufgedoppelt, um auch für einen Port noch eine sinnvolle Diagnostik zu bieten; diese Redundanz nehme ich in Kauf (ist jeweils ein Pointer); im Gegenzug verzichte ich aber auf eine separate Node-ID, indem die Proc-ID hilfsweise auch die Node-Spec mit implemenitert +

+ + +
+ + +
+
+ + + + + + + + + + +
+ @@ -104947,6 +105046,24 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + +

+ Fazit: Weaving-Patterns +

+ + +
+ + + + + + + + @@ -105091,6 +105208,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)

+
@@ -105122,6 +105240,23 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
+ + + + + + + +

+ wäre nämlich zusätzlicher Coding-Aufwand — und dabei weitgehend redundant +

+ + +
+ +
+ +
@@ -106673,27 +106808,27 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - + + + - + - - + + - - + + - - + + - + @@ -106728,12 +106863,14 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + + + - + @@ -106744,23 +106881,92 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + +

+ Und zwar, weil die Rolle der Ablaufsteuerung grundsätzlich überdacht und reorientiert wurde: Der Engine-Code ist jetzt nicht mehr »Tabellengetrieben«, sondern besteht aus miteinander verwobenen Funktions-Closures. Damit wandert der wichtigste Teil dieser Steuerung in ein zukünftig zu entwickelndes Library Plug-in (erneut für jede Media-Handling Lib, wie z.B. FFmpeg). +

+

+ Daher wird es keine zentrale Node-Factory als Abstraktionskomponente geben; vielmehr erwarte ich, daß der Builder-Level-3 über ein noch zu schaffendes API das Library Plug-in aktiviert, welches dann das API des NodeBuilders verwendet um einzelne Nodes zu konstruieren. Es läuft also auf ein relativ komplexes Wechselspiel zwischen den Builder-Leveln und der Delegation an das Library Plug-in hinaus. Letzteres kann nämlich nicht das Anlegen und Verschalten der Nodes übernehmen, aber muß die Funktion beisteuern und die dazu passende Node-Spec.... +

+ +
+
- + + - - - + + + + + + + +

+ Lösung: Weaving-Pattern wird unmittelbar Teil des Turnout +

+ +
+
+ + + + + + + +

+ verwendet einen Invocation-Adapter mit eingebetteter FeedManifold +

+ +
+
+
+ + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + +

+ Nein! +

+

+ Da wir nun weitgehend auf explizite Typisierung und Templates setzen (Tupel als Argumente der Processing-Function), sind Detail-Implementierungen in den Spezialisierungen der Weaving-Pattern untergebracht, oder werden sogar als Funktoren aus dem Library-Plug-in eingebunden +

+ + +
+ +
+ +
@@ -106793,34 +106999,93 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - - - - + + + + - - + + - + + + + + + +

+ Tatsächlich zeige ich nun alle drei Punkte +

+

+ in einer einzigen Test-Node-Topologie +

+ + +
+ + + +
    +
  • + nahezu identisch verwendet in NodeLink_test und NodeMeta_test +
  • +
  • + in letzterem befindet sich die erschöpfende Abdeckung der Diagnose / Verifikations-Tools +
  • +
  • + als Processing-Funktionen verwende ich in den ersten Schritten einfache Algebra-Funktionen +
  • +
  • + in NodeBase_test habe ich die Korrektheit des Aufrufs solcher einfachen Algebra im Detail verifiziert +
  • +
+ + +
+ + + + - - - + + + + + + + + + + + - + + + + + - - + + - + + + + + - - + + + + + + + @@ -106874,10 +107139,11 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - + - + + @@ -106912,10 +107178,19 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + + + + - + + + @@ -106949,6 +107224,17 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) + + + + +

+ Das ist ein Kompromiß und ein Trick, mit dem man (für Test und Diagnose) doch noch ein bischen hinter die Kulissen schauen kann. Auf dieser Basis habe ich einen Accessor gebaut: PortDiagnostic::getSrcNodes()  ⟼  lib::Several<PortRef> +

+ +
+
+ @@ -107057,7 +107343,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension) - +