81 lines
3.1 KiB
C++
81 lines
3.1 KiB
C++
// Example 02 — Named Ports
|
|
//
|
|
// A three-stage text pipeline where port names carry semantic meaning:
|
|
//
|
|
// [tokenise] --"words"--> [count_words] --"count"--> [report]
|
|
// --"words"--> [report]
|
|
//
|
|
// Named ports let the connect() call read like documentation:
|
|
// connect("tok", tok.output<"words">(), "cnt", cnt.input<"words">())
|
|
// A typo in the name is a compile-time error, not a runtime surprise.
|
|
|
|
#include <kpn/kpn.hpp>
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <thread>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
// ── Node functions ────────────────────────────────────────────────────────────
|
|
|
|
static int sentence_index = 0;
|
|
|
|
static std::vector<std::string> tokenise() {
|
|
static const char* sentences[] = {
|
|
"the quick brown fox jumps over the lazy dog",
|
|
"kahn process networks are a model of concurrent computation",
|
|
"each node runs in its own thread communicating via channels",
|
|
"named ports catch wiring mistakes at compile time",
|
|
};
|
|
std::istringstream ss(sentences[sentence_index++ % 4]);
|
|
std::vector<std::string> words;
|
|
std::string w;
|
|
while (ss >> w) words.push_back(w);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
return words;
|
|
}
|
|
|
|
// Returns (word_count, original_words) — two outputs via tuple
|
|
static std::tuple<int, std::vector<std::string>>
|
|
count_words(std::vector<std::string> words) {
|
|
return {static_cast<int>(words.size()), std::move(words)};
|
|
}
|
|
|
|
static void report(int count, std::vector<std::string> words) {
|
|
std::cout << "[" << count << " words] ";
|
|
for (auto& w : words) std::cout << w << ' ';
|
|
std::cout << '\n';
|
|
}
|
|
|
|
// ── main ──────────────────────────────────────────────────────────────────────
|
|
|
|
int main() {
|
|
using namespace kpn;
|
|
|
|
// tokenise: no inputs, one named output "words"
|
|
auto tok = make_node<tokenise>(out<"words">{}, 4);
|
|
|
|
// count_words: named input "words", named outputs "count" and "words"
|
|
auto cnt = make_node<count_words>(in<"words">{}, out<"count", "words">{}, 4);
|
|
|
|
// report: two named inputs — note the function takes (int, vector<string>)
|
|
// so we need two separate input ports wired independently
|
|
// For a two-input sink we wire each output of cnt to a different input of report
|
|
auto snk = make_node<report>(in<"count", "words">{}, 4);
|
|
|
|
Network net;
|
|
net.add("tok", tok)
|
|
.add("cnt", cnt)
|
|
.add("snk", snk)
|
|
.connect("tok", tok.template output<"words">(), "cnt", cnt.template input<"words">())
|
|
.connect("cnt", cnt.template output<"count">(), "snk", snk.template input<"count">())
|
|
.connect("cnt", cnt.template output<"words">(), "snk", snk.template input<"words">())
|
|
.build();
|
|
|
|
net.start();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
net.stop();
|
|
}
|