動かしてみましょう、10個の"Hello, world"を同時に着火します。
int main() {
my_context ctx;
const int steps = 10;
cout << "--- let's start ---\n";
for ( int n = 0; n < steps; ++n ) {
ctx.tags.put(n); // 着火!!
}
cout << "--- all steps activated ---\n";
ctx.wait();
cout << "--- that's it. ---\n";
}
コビトさんが8人いる僕のマシンでの実行結果はこうなりました。
コビトさんたちがCnCの中で同時に働いている様子が伺えますね。
itemの入出力を使った例もお見せしましょう。与えられた値の平方根を求めるだけの簡単なお仕事です。
itemの集合CnC::item_collection<key,value>は辞書になっていて、keyに紐づいたvalueをget/putできます。
#include <iostream>
#include <cmath>
#include <cnc/cnc.h>
using namespace std;
struct my_context;
struct my_step {
int execute(const int& tag, my_context& ctx) const;
};
struct my_context : public CnC::context<my_context> {
CnC::step_collection<my_step> steps;
CnC::tag_collection<int> tags;
CnC::item_collection<int,double> inputs;
CnC::item_collection<int,double> outputs;
my_context() : steps(*this), tags(*this), inputs(*this), outputs(*this) {
tags.prescribes(steps, *this); // tags は steps に指示する
steps.consumes(inputs); // steps は inputs を消費する
steps.produces(outputs); // steps は outputs を生産する
}
};
int my_step::execute(const int& tag, my_context& ctx) const {
double input;
ctx.inputs.get(tag, input);
ctx.outputs.put(tag, sqrt(input));
return CnC::CNC_Success;
}
int main() {
my_context ctx;
const int steps = 10;
// 入力をセットして
for ( int tag = 0; tag < steps; ++tag ) {
ctx.inputs.put(tag, static_cast<double>(tag));
}
// 着火
for ( int tag = 0; tag < steps; ++tag ) {
ctx.tags.put(tag);
}
ctx.wait(); // 完了を待って
// 結果を取り出す
for ( int tag = 0; tag < steps; ++tag ) {
double input;
ctx.inputs.get(tag, input);
double result;
ctx.outputs.get(tag, result);
cout << "sqrt(" << input << ") = " << result << endl;
}
}
では次にちょっとした応用例、複利計算をやってみます。複利計算では"n年後の残高"は"(n-1)年後の残高に(1+利率)を掛ける"ことで得られます。なのでn番itemに"n年後の残高"を求めることにすれば、n番stepで"(n-1)番itemを読み(1+利率)を掛けてn番itemに書く"を行わせれば、こいつを数珠つなぎにすることでn年後の残高がn番itemから得られます。
#include <iostream>
#include <cnc/cnc.h>
using namespace std;
struct my_context; // forward decl.
struct my_step {
int execute(const int& n, my_context& ctx) const;
};
struct my_context : public CnC::context<my_context> {
CnC::step_collection<my_step> steps;
CnC::tag_collection<int> tags;
CnC::item_collection<int,double> items;
double rate; // 利率
my_context() : steps(*this), tags(*this), items(*this) {
tags.prescribes(steps, *this); // tags は steps に 指示する
steps.consumes(items); // steps は items を消費する
steps.produces(items); // steps は items を生産する
}
};
// n-1年の残高と利率からn年後の残高を求める
int my_step::execute(const int& n, my_context& ctx) const {
// n 年後の残高は
double result;
ctx.items.get(n-1, result); // n-1 年後の残高に
result *= (1.0 + ctx.rate); // 利率をかけたもの
ctx.items.put(n, result); // である
return CnC::CNC_Success;
}
int main() {
my_context ctx;
ctx.rate = 0.05; // 年利5%の定期預金に
ctx.items.put(0, 10000.0); // 初年度に1万円預けて
const int duration = 10; // 10年間放置するとき
// 1年後, 2年後, ... 10年後 の残高を求めよ!
for ( int n = 1; n <= duration; ++n ) {
ctx.tags.put(n); // ここでstepをkickする
}
ctx.wait(); // 終わるのを待って
// 出力する
for ( int n = 0; n <= duration; ++n ) {
double balance;
ctx.items.get(n, balance);
cout << balance << endl;
}
}
んー...面白みに欠けますね。前段のstepが完了しないと後段のstepが動けない(ctx.items.get()でブロックする)ので、動いてるstepは1つだけなんですよね。


