// Copyright Sebastian Jeckel 2014. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include "react/Domain.h" #include "react/Signal.h" #include "react/Observer.h" /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 1 - Hello world /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example1 { using namespace std; using namespace react; // Defines a domain. // Each domain represents a separate dependency graph, managed by a dedicated propagation engine. // Reactives of different domains can not be combined. REACTIVE_DOMAIN(D, sequential) // Define type aliases for the given domain in this namespace. // Now we can use VarSignalT instead of D::VarSignalT. USING_REACTIVE_DOMAIN(D) // The concat function string concatFunc(string first, string second) { return first + string(" ") + second; } // A signal that concatenates both words namespace v1 { // The two words VarSignalT firstWord = MakeVar(string("Change")); VarSignalT secondWord = MakeVar(string("me!")); SignalT bothWords = MakeSignal(With(firstWord,secondWord), concatFunc); void Run() { cout << "Example 1 - Hello world (MakeSignal)" << endl; // Imperative imperative value access cout << bothWords.Value() << endl; // Imperative imperative change firstWord <<= string("Hello"); cout << bothWords.Value() << endl; secondWord <<= string("World"); cout << bothWords.Value() << endl; cout << endl; } } // Using overloaded operator + instead of explicit MakeSignal namespace v2 { // The two words VarSignalT firstWord = MakeVar(string("Change")); VarSignalT secondWord = MakeVar(string("me!")); SignalT bothWords = firstWord + string(" ") + secondWord; void Run() { cout << "Example 1 - Hello world (operators)" << endl; cout << bothWords.Value() << endl; firstWord <<= string("Hello"); cout << bothWords.Value() << endl; secondWord <<= string("World"); cout << bothWords.Value() << endl; cout << endl; } } } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 2 - Reacting to value changes /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example2 { using namespace std; using namespace react; REACTIVE_DOMAIN(D, sequential) USING_REACTIVE_DOMAIN(D) VarSignalT x = MakeVar(1); SignalT xAbs = MakeSignal(x, [] (int x) { return abs(x); }); void Run() { cout << "Example 2 - Reacting to value changes" << endl; Observe(xAbs, [] (int newValue) { cout << "xAbs changed to " << newValue << endl; }); // initially x is 1 x <<= 2; // output: xAbs changed to 2 x <<= -3; // output: xAbs changed to 3 x <<= 3; // no output, xAbs is still 3 cout << endl; } } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 3 - Changing multiple inputs /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example3 { using namespace std; using namespace react; REACTIVE_DOMAIN(D, sequential) USING_REACTIVE_DOMAIN(D) VarSignalT a = MakeVar(1); VarSignalT b = MakeVar(1); SignalT x = a + b; SignalT y = a + b; SignalT z = x + y; void Run() { cout << "Example 3 - Changing multiple inputs" << endl; Observe(z, [] (int newValue) { std::cout << "z changed to " << newValue << std::endl; }); a <<= 2; // output: z changed to 6 b <<= 2; // output: z changed to 8 DoTransaction([] { a <<= 4; b <<= 4; }); // output: z changed to 16 cout << endl; } } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 4 - Modifying signal values in place /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example4 { using namespace std; using namespace react; REACTIVE_DOMAIN(D, sequential) USING_REACTIVE_DOMAIN(D) VarSignalT> data = MakeVar(vector{ }); void Run() { cout << "Example 4 - Modifying signal values in place" << endl; data.Modify([] (vector& data) { data.push_back("Hello"); }); data.Modify([] (vector& data) { data.push_back("World"); }); for (const auto& s : data.Value()) cout << s << " "; cout << endl; // output: Hell World cout << endl; } } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Example 5 - Complex signals /////////////////////////////////////////////////////////////////////////////////////////////////// namespace example5 { using namespace std; using namespace react; REACTIVE_DOMAIN(D, sequential) USING_REACTIVE_DOMAIN(D) // Helpers using ExprPairT = pair; using ExprVectT = vector; string makeExprStr(int a, int b, const char* op) { return to_string(a) + string(op) + to_string(b); } ExprPairT makeExprPair(const string& s, int v) { return make_pair(s, v); } void printExpressions(const ExprVectT& expressions) { cout << "Expressions: " << endl; for (const auto& p : expressions) cout << "\t" << p.first << " is " << p.second << endl; } // Version 1 - Intermediate signals namespace v1 { // Input operands VarSignalT a = MakeVar(1); VarSignalT b = MakeVar(2); // Calculations SignalT sum = a + b; SignalT diff = a - b; SignalT prod = a * b; using std::placeholders::_1; using std::placeholders::_2; // Stringified expressions SignalT sumExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "+")); SignalT diffExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "-")); SignalT prodExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "*")); // The expression vector SignalT expressions = MakeSignal( With( MakeSignal(With(sumExpr, sum), &makeExprPair), MakeSignal(With(diffExpr, diff), &makeExprPair), MakeSignal(With(prodExpr, prod), &makeExprPair) ), [] (const ExprPairT& sumP, const ExprPairT& diffP, const ExprPairT& prodP) { return ExprVectT{ sumP, diffP, prodP}; }); void Run() { cout << "Example 5 - Complex signals (v1)" << endl; Observe(expressions, printExpressions); a <<= 10; b <<= 20; cout << endl; } } // Version 2 - Intermediate signals in a function namespace v2 { SignalT createExpressionSignal(const SignalT& a, const SignalT& b) { using std::placeholders::_1; using std::placeholders::_2; // Inside a function, we can use auto auto sumExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "+")); auto diffExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "-")); auto prodExpr = MakeSignal(With(a,b), bind(makeExprStr, _1, _2, "*")); return MakeSignal( With( MakeSignal(With(sumExpr, a + b), &makeExprPair), MakeSignal(With(diffExpr, a - b), &makeExprPair), MakeSignal(With(prodExpr, a * b), &makeExprPair) ), [] (const ExprPairT& sumP, const ExprPairT& diffP, const ExprPairT& prodP) { return ExprVectT{ sumP, diffP, prodP }; }); } // Input operands VarSignalT a = MakeVar(1); VarSignalT b = MakeVar(2); // The expression vector SignalT expressions = createExpressionSignal(a, b); void Run() { cout << "Example 5 - Complex signals (v2)" << endl; Observe(expressions, printExpressions); a <<= 30; b <<= 40; cout << endl; } } // Version 3 - Imperative function namespace v3 { // Input operands VarSignalT a = MakeVar(1); VarSignalT b = MakeVar(2); // The expression vector SignalT expressions = MakeSignal(With(a,b), [] (int a, int b) { ExprVectT result; result.push_back( make_pair( makeExprStr(a, b, "+"), a + b)); result.push_back( make_pair( makeExprStr(a, b, "-"), a - b)); result.push_back( make_pair( makeExprStr(a, b, "*"), a * b)); return result; }); void Run() { cout << "Example 5 - Complex signals (v3)" << endl; Observe(expressions, printExpressions); a <<= 50; b <<= 60; cout << endl; } } } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Run examples /////////////////////////////////////////////////////////////////////////////////////////////////// int main() { example1::v1::Run(); example1::v2::Run(); example2::Run(); example3::Run(); example4::Run(); example5::v1::Run(); example5::v2::Run(); example5::v3::Run(); return 0; }